aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile45
-rw-r--r--tools/cgroup/.gitignore1
-rw-r--r--tools/cgroup/Makefile11
-rw-r--r--tools/cgroup/cgroup_event_listener.c82
-rw-r--r--tools/firewire/nosy-dump.c4
-rw-r--r--tools/hv/hv_kvp_daemon.c119
-rwxr-xr-xtools/hv/hv_set_ifconfig.sh24
-rw-r--r--tools/lguest/lguest.c84
-rw-r--r--tools/lguest/lguest.txt8
-rw-r--r--tools/lib/traceevent/Makefile2
-rw-r--r--tools/lib/traceevent/event-parse.c71
-rw-r--r--tools/lib/traceevent/event-parse.h3
-rw-r--r--tools/lib/traceevent/event-utils.h3
-rw-r--r--tools/lib/traceevent/parse-filter.c3
-rw-r--r--tools/lib/traceevent/parse-utils.c19
-rw-r--r--tools/lib/traceevent/trace-seq.c3
-rw-r--r--tools/perf/Documentation/Makefile35
-rw-r--r--tools/perf/Documentation/android.txt78
-rw-r--r--tools/perf/Documentation/perf-annotate.txt7
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt7
-rw-r--r--tools/perf/Documentation/perf-diff.txt64
-rw-r--r--tools/perf/Documentation/perf-evlist.txt4
-rw-r--r--tools/perf/Documentation/perf-inject.txt11
-rw-r--r--tools/perf/Documentation/perf-record.txt2
-rw-r--r--tools/perf/Documentation/perf-report.txt41
-rw-r--r--tools/perf/Documentation/perf-script-python.txt2
-rw-r--r--tools/perf/Documentation/perf-stat.txt18
-rw-r--r--tools/perf/Documentation/perf-test.txt4
-rw-r--r--tools/perf/Documentation/perf-top.txt2
-rw-r--r--tools/perf/Documentation/perf-trace.txt6
-rw-r--r--tools/perf/MANIFEST10
-rw-r--r--tools/perf/Makefile303
-rw-r--r--tools/perf/arch/common.c212
-rw-r--r--tools/perf/arch/common.h10
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h2
-rw-r--r--tools/perf/bench/bench.h1
-rw-r--r--tools/perf/bench/numa.c1731
-rw-r--r--tools/perf/builtin-annotate.c47
-rw-r--r--tools/perf/builtin-bench.c19
-rw-r--r--tools/perf/builtin-buildid-cache.c97
-rw-r--r--tools/perf/builtin-buildid-list.c27
-rw-r--r--tools/perf/builtin-diff.c484
-rw-r--r--tools/perf/builtin-evlist.c93
-rw-r--r--tools/perf/builtin-inject.c195
-rw-r--r--tools/perf/builtin-kmem.c21
-rw-r--r--tools/perf/builtin-kvm.c157
-rw-r--r--tools/perf/builtin-lock.c2
-rw-r--r--tools/perf/builtin-record.c212
-rw-r--r--tools/perf/builtin-report.c110
-rw-r--r--tools/perf/builtin-sched.c14
-rw-r--r--tools/perf/builtin-script.c104
-rw-r--r--tools/perf/builtin-stat.c380
-rw-r--r--tools/perf/builtin-test.c1547
-rw-r--r--tools/perf/builtin-timechart.c5
-rw-r--r--tools/perf/builtin-top.c381
-rw-r--r--tools/perf/builtin-trace.c405
-rw-r--r--tools/perf/config/feature-tests.mak36
-rw-r--r--tools/perf/config/utilities.mak16
-rw-r--r--tools/perf/perf.c52
-rw-r--r--tools/perf/perf.h76
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report3
-rw-r--r--tools/perf/scripts/perl/rwtop.pl6
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl129
-rw-r--r--tools/perf/tests/attr.c178
-rw-r--r--tools/perf/tests/attr.py331
-rw-r--r--tools/perf/tests/attr/README64
-rw-r--r--tools/perf/tests/attr/base-record39
-rw-r--r--tools/perf/tests/attr/base-stat39
-rw-r--r--tools/perf/tests/attr/test-record-basic5
-rw-r--r--tools/perf/tests/attr/test-record-branch-any8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any_call8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-any_ret8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-hv8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-ind_call8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-k8
-rw-r--r--tools/perf/tests/attr/test-record-branch-filter-u8
-rw-r--r--tools/perf/tests/attr/test-record-count8
-rw-r--r--tools/perf/tests/attr/test-record-data8
-rw-r--r--tools/perf/tests/attr/test-record-freq6
-rw-r--r--tools/perf/tests/attr/test-record-graph-default6
-rw-r--r--tools/perf/tests/attr/test-record-graph-dwarf10
-rw-r--r--tools/perf/tests/attr/test-record-graph-fp6
-rw-r--r--tools/perf/tests/attr/test-record-group20
-rw-r--r--tools/perf/tests/attr/test-record-group121
-rw-r--r--tools/perf/tests/attr/test-record-no-delay9
-rw-r--r--tools/perf/tests/attr/test-record-no-inherit7
-rw-r--r--tools/perf/tests/attr/test-record-no-samples6
-rw-r--r--tools/perf/tests/attr/test-record-period7
-rw-r--r--tools/perf/tests/attr/test-record-raw7
-rw-r--r--tools/perf/tests/attr/test-stat-basic6
-rw-r--r--tools/perf/tests/attr/test-stat-default64
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-1101
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-2155
-rw-r--r--tools/perf/tests/attr/test-stat-detailed-3173
-rw-r--r--tools/perf/tests/attr/test-stat-group15
-rw-r--r--tools/perf/tests/attr/test-stat-group115
-rw-r--r--tools/perf/tests/attr/test-stat-no-inherit7
-rw-r--r--tools/perf/tests/builtin-test.c203
-rw-r--r--tools/perf/tests/dso-data.c (renamed from tools/perf/util/dso-test-data.c)8
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c114
-rw-r--r--tools/perf/tests/evsel-tp-sched.c84
-rw-r--r--tools/perf/tests/hists_link.c500
-rw-r--r--tools/perf/tests/mmap-basic.c148
-rw-r--r--tools/perf/tests/open-syscall-all-cpus.c109
-rw-r--r--tools/perf/tests/open-syscall-tp-fields.c117
-rw-r--r--tools/perf/tests/open-syscall.c55
-rw-r--r--tools/perf/tests/parse-events.c (renamed from tools/perf/util/parse-events-test.c)395
-rw-r--r--tools/perf/tests/perf-record.c314
-rw-r--r--tools/perf/tests/pmu.c173
-rw-r--r--tools/perf/tests/python-use.c23
-rw-r--r--tools/perf/tests/rdpmc.c175
-rw-r--r--tools/perf/tests/tests.h27
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c233
-rw-r--r--tools/perf/ui/browser.c6
-rw-r--r--tools/perf/ui/browsers/annotate.c78
-rw-r--r--tools/perf/ui/browsers/hists.c432
-rw-r--r--tools/perf/ui/browsers/scripts.c189
-rw-r--r--tools/perf/ui/gtk/annotate.c229
-rw-r--r--tools/perf/ui/gtk/browser.c237
-rw-r--r--tools/perf/ui/gtk/gtk.h11
-rw-r--r--tools/perf/ui/gtk/helpline.c23
-rw-r--r--tools/perf/ui/gtk/hists.c312
-rw-r--r--tools/perf/ui/gtk/progress.c59
-rw-r--r--tools/perf/ui/gtk/setup.c2
-rw-r--r--tools/perf/ui/gtk/util.c11
-rw-r--r--tools/perf/ui/helpline.c12
-rw-r--r--tools/perf/ui/helpline.h22
-rw-r--r--tools/perf/ui/hist.c519
-rw-r--r--tools/perf/ui/keysyms.h1
-rw-r--r--tools/perf/ui/progress.c44
-rw-r--r--tools/perf/ui/progress.h10
-rw-r--r--tools/perf/ui/setup.c3
-rw-r--r--tools/perf/ui/stdio/hist.c27
-rw-r--r--tools/perf/ui/tui/helpline.c29
-rw-r--r--tools/perf/ui/tui/progress.c42
-rw-r--r--tools/perf/ui/tui/setup.c1
-rw-r--r--tools/perf/ui/ui.h28
-rw-r--r--tools/perf/ui/util.c1
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN18
-rw-r--r--tools/perf/util/annotate.c74
-rw-r--r--tools/perf/util/annotate.h34
-rw-r--r--tools/perf/util/build-id.c27
-rw-r--r--tools/perf/util/build-id.h11
-rw-r--r--tools/perf/util/cache.h39
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h5
-rw-r--r--tools/perf/util/cpumap.c54
-rw-r--r--tools/perf/util/cpumap.h9
-rw-r--r--tools/perf/util/debug.c28
-rw-r--r--tools/perf/util/debug.h33
-rw-r--r--tools/perf/util/dso.c595
-rw-r--r--tools/perf/util/dso.h148
-rw-r--r--tools/perf/util/event.c306
-rw-r--r--tools/perf/util/event.h9
-rw-r--r--tools/perf/util/evlist.c43
-rw-r--r--tools/perf/util/evlist.h34
-rw-r--r--tools/perf/util/evsel.c420
-rw-r--r--tools/perf/util/evsel.h57
-rw-r--r--tools/perf/util/header.c279
-rw-r--r--tools/perf/util/header.h5
-rw-r--r--tools/perf/util/hist.c213
-rw-r--r--tools/perf/util/hist.h67
-rw-r--r--tools/perf/util/include/linux/bitops.h1
-rw-r--r--tools/perf/util/intlist.c36
-rw-r--r--tools/perf/util/intlist.h2
-rw-r--r--tools/perf/util/machine.c1226
-rw-r--r--tools/perf/util/machine.h157
-rw-r--r--tools/perf/util/map.c303
-rw-r--r--tools/perf/util/map.h117
-rw-r--r--tools/perf/util/parse-events.c148
-rw-r--r--tools/perf/util/parse-events.h25
-rw-r--r--tools/perf/util/parse-events.l4
-rw-r--r--tools/perf/util/parse-events.y85
-rw-r--r--tools/perf/util/pmu.c238
-rw-r--r--tools/perf/util/pmu.h21
-rw-r--r--tools/perf/util/pmu.y1
-rw-r--r--tools/perf/util/probe-finder.c10
-rw-r--r--tools/perf/util/pstack.c46
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/python.c11
-rw-r--r--tools/perf/util/rblist.c4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/session.c330
-rw-r--r--tools/perf/util/session.h42
-rw-r--r--tools/perf/util/sort.c245
-rw-r--r--tools/perf/util/sort.h52
-rw-r--r--tools/perf/util/strbuf.c8
-rw-r--r--tools/perf/util/string.c36
-rw-r--r--tools/perf/util/strlist.c54
-rw-r--r--tools/perf/util/strlist.h42
-rw-r--r--tools/perf/util/symbol-elf.c14
-rw-r--r--tools/perf/util/symbol-minimal.c1
-rw-r--r--tools/perf/util/symbol.c1194
-rw-r--r--tools/perf/util/symbol.h171
-rw-r--r--tools/perf/util/sysfs.c2
-rw-r--r--tools/perf/util/thread.c61
-rw-r--r--tools/perf/util/thread.h3
-rw-r--r--tools/perf/util/top.c22
-rw-r--r--tools/perf/util/top.h10
-rw-r--r--tools/perf/util/trace-event-read.c2
-rw-r--r--tools/perf/util/util.c59
-rw-r--r--tools/perf/util/util.h12
-rw-r--r--tools/power/acpi/Makefile2
-rw-r--r--tools/power/cpupower/.gitignore7
-rw-r--r--tools/power/cpupower/Makefile3
-rw-r--r--tools/power/cpupower/debug/i386/Makefile5
-rw-r--r--tools/power/cpupower/man/cpupower-monitor.115
-rw-r--r--tools/power/cpupower/utils/helpers/cpuid.c2
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h18
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c19
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c53
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c21
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h17
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c10
-rw-r--r--tools/power/x86/turbostat/Makefile21
-rw-r--r--tools/power/x86/turbostat/turbostat.8139
-rw-r--r--tools/power/x86/turbostat/turbostat.c737
-rw-r--r--tools/power/x86/x86_energy_perf_policy/Makefile6
-rw-r--r--tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c2
-rw-r--r--tools/scripts/Makefile.include23
-rw-r--r--tools/testing/ktest/examples/include/patchcheck.conf37
-rwxr-xr-xtools/testing/ktest/ktest.pl310
-rw-r--r--tools/testing/ktest/sample.conf90
-rw-r--r--tools/testing/selftests/Makefile8
-rw-r--r--tools/testing/selftests/README.txt42
-rw-r--r--tools/testing/selftests/breakpoints/Makefile2
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile2
-rw-r--r--tools/testing/selftests/efivarfs/Makefile12
-rw-r--r--tools/testing/selftests/efivarfs/create-read.c38
-rw-r--r--tools/testing/selftests/efivarfs/efivarfs.sh198
-rw-r--r--tools/testing/selftests/efivarfs/open-unlink.c63
-rw-r--r--tools/testing/selftests/epoll/Makefile11
-rw-r--r--tools/testing/selftests/epoll/test_epoll.c344
-rw-r--r--tools/testing/selftests/ipc/Makefile25
-rw-r--r--tools/testing/selftests/ipc/msgque.c246
-rw-r--r--tools/testing/selftests/kcmp/Makefile6
-rw-r--r--tools/testing/selftests/kcmp/kcmp_test.c6
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile2
-rw-r--r--tools/testing/selftests/mqueue/Makefile4
-rw-r--r--tools/testing/selftests/vm/Makefile6
-rw-r--r--tools/testing/selftests/vm/thuge-gen.c254
-rw-r--r--tools/usb/ffs-test.c2
-rw-r--r--tools/usb/testusb.c31
-rw-r--r--tools/virtio/virtio_test.c6
-rw-r--r--tools/vm/.gitignore2
248 files changed, 16993 insertions, 7198 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 3ae43947a171..fa36565b209d 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -3,6 +3,7 @@ include scripts/Makefile.include
3help: 3help:
4 @echo 'Possible targets:' 4 @echo 'Possible targets:'
5 @echo '' 5 @echo ''
6 @echo ' cgroup - cgroup tools'
6 @echo ' cpupower - a tool for all things x86 CPU power' 7 @echo ' cpupower - a tool for all things x86 CPU power'
7 @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' 8 @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
8 @echo ' lguest - a minimal 32-bit x86 hypervisor' 9 @echo ' lguest - a minimal 32-bit x86 hypervisor'
@@ -15,7 +16,7 @@ help:
15 @echo ' x86_energy_perf_policy - Intel energy policy tool' 16 @echo ' x86_energy_perf_policy - Intel energy policy tool'
16 @echo '' 17 @echo ''
17 @echo 'You can do:' 18 @echo 'You can do:'
18 @echo ' $$ make -C tools/<tool>_install' 19 @echo ' $$ make -C tools/ <tool>_install'
19 @echo '' 20 @echo ''
20 @echo ' from the kernel command line to build and install one of' 21 @echo ' from the kernel command line to build and install one of'
21 @echo ' the tools above' 22 @echo ' the tools above'
@@ -31,47 +32,47 @@ help:
31 @echo ' clean: a summary clean target to clean _all_ folders' 32 @echo ' clean: a summary clean target to clean _all_ folders'
32 33
33cpupower: FORCE 34cpupower: FORCE
34 $(QUIET_SUBDIR0)power/$@/ $(QUIET_SUBDIR1) 35 $(call descend,power/$@)
35 36
36firewire lguest perf usb virtio vm: FORCE 37cgroup firewire lguest perf usb virtio vm: FORCE
37 $(QUIET_SUBDIR0)$@/ $(QUIET_SUBDIR1) 38 $(call descend,$@)
38 39
39selftests: FORCE 40selftests: FORCE
40 $(QUIET_SUBDIR0)testing/$@/ $(QUIET_SUBDIR1) 41 $(call descend,testing/$@)
41 42
42turbostat x86_energy_perf_policy: FORCE 43turbostat x86_energy_perf_policy: FORCE
43 $(QUIET_SUBDIR0)power/x86/$@/ $(QUIET_SUBDIR1) 44 $(call descend,power/x86/$@)
44 45
45cpupower_install: 46cpupower_install:
46 $(QUIET_SUBDIR0)power/$(@:_install=)/ $(QUIET_SUBDIR1) install 47 $(call descend,power/$(@:_install=),install)
47 48
48firewire_install lguest_install perf_install usb_install virtio_install vm_install: 49cgroup_install firewire_install lguest_install perf_install usb_install virtio_install vm_install:
49 $(QUIET_SUBDIR0)$(@:_install=)/ $(QUIET_SUBDIR1) install 50 $(call descend,$(@:_install=),install)
50 51
51selftests_install: 52selftests_install:
52 $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) install 53 $(call descend,testing/$(@:_clean=),install)
53 54
54turbostat_install x86_energy_perf_policy_install: 55turbostat_install x86_energy_perf_policy_install:
55 $(QUIET_SUBDIR0)power/x86/$(@:_install=)/ $(QUIET_SUBDIR1) install 56 $(call descend,power/x86/$(@:_install=),install)
56 57
57install: cpupower_install firewire_install lguest_install perf_install \ 58install: cgroup_install cpupower_install firewire_install lguest_install \
58 selftests_install turbostat_install usb_install virtio_install \ 59 perf_install selftests_install turbostat_install usb_install \
59 vm_install x86_energy_perf_policy_install 60 virtio_install vm_install x86_energy_perf_policy_install
60 61
61cpupower_clean: 62cpupower_clean:
62 $(QUIET_SUBDIR0)power/cpupower/ $(QUIET_SUBDIR1) clean 63 $(call descend,power/cpupower,clean)
63 64
64firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean: 65cgroup_clean firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean:
65 $(QUIET_SUBDIR0)$(@:_clean=)/ $(QUIET_SUBDIR1) clean 66 $(call descend,$(@:_clean=),clean)
66 67
67selftests_clean: 68selftests_clean:
68 $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) clean 69 $(call descend,testing/$(@:_clean=),clean)
69 70
70turbostat_clean x86_energy_perf_policy_clean: 71turbostat_clean x86_energy_perf_policy_clean:
71 $(QUIET_SUBDIR0)power/x86/$(@:_clean=)/ $(QUIET_SUBDIR1) clean 72 $(call descend,power/x86/$(@:_clean=),clean)
72 73
73clean: cpupower_clean firewire_clean lguest_clean perf_clean selftests_clean \ 74clean: cgroup_clean cpupower_clean firewire_clean lguest_clean perf_clean \
74 turbostat_clean usb_clean virtio_clean vm_clean \ 75 selftests_clean turbostat_clean usb_clean virtio_clean \
75 x86_energy_perf_policy_clean 76 vm_clean x86_energy_perf_policy_clean
76 77
77.PHONY: FORCE 78.PHONY: FORCE
diff --git a/tools/cgroup/.gitignore b/tools/cgroup/.gitignore
new file mode 100644
index 000000000000..633cd9b874f9
--- /dev/null
+++ b/tools/cgroup/.gitignore
@@ -0,0 +1 @@
cgroup_event_listener
diff --git a/tools/cgroup/Makefile b/tools/cgroup/Makefile
new file mode 100644
index 000000000000..b4286196b763
--- /dev/null
+++ b/tools/cgroup/Makefile
@@ -0,0 +1,11 @@
1# Makefile for cgroup tools
2
3CC = $(CROSS_COMPILE)gcc
4CFLAGS = -Wall -Wextra
5
6all: cgroup_event_listener
7%: %.c
8 $(CC) $(CFLAGS) -o $@ $^
9
10clean:
11 $(RM) cgroup_event_listener
diff --git a/tools/cgroup/cgroup_event_listener.c b/tools/cgroup/cgroup_event_listener.c
new file mode 100644
index 000000000000..4eb5507205c9
--- /dev/null
+++ b/tools/cgroup/cgroup_event_listener.c
@@ -0,0 +1,82 @@
1/*
2 * cgroup_event_listener.c - Simple listener of cgroup events
3 *
4 * Copyright (C) Kirill A. Shutemov <kirill@shutemov.name>
5 */
6
7#include <assert.h>
8#include <err.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <libgen.h>
12#include <limits.h>
13#include <stdio.h>
14#include <string.h>
15#include <unistd.h>
16
17#include <sys/eventfd.h>
18
19#define USAGE_STR "Usage: cgroup_event_listener <path-to-control-file> <args>"
20
21int main(int argc, char **argv)
22{
23 int efd = -1;
24 int cfd = -1;
25 int event_control = -1;
26 char event_control_path[PATH_MAX];
27 char line[LINE_MAX];
28 int ret;
29
30 if (argc != 3)
31 errx(1, "%s", USAGE_STR);
32
33 cfd = open(argv[1], O_RDONLY);
34 if (cfd == -1)
35 err(1, "Cannot open %s", argv[1]);
36
37 ret = snprintf(event_control_path, PATH_MAX, "%s/cgroup.event_control",
38 dirname(argv[1]));
39 if (ret >= PATH_MAX)
40 errx(1, "Path to cgroup.event_control is too long");
41
42 event_control = open(event_control_path, O_WRONLY);
43 if (event_control == -1)
44 err(1, "Cannot open %s", event_control_path);
45
46 efd = eventfd(0, 0);
47 if (efd == -1)
48 err(1, "eventfd() failed");
49
50 ret = snprintf(line, LINE_MAX, "%d %d %s", efd, cfd, argv[2]);
51 if (ret >= LINE_MAX)
52 errx(1, "Arguments string is too long");
53
54 ret = write(event_control, line, strlen(line) + 1);
55 if (ret == -1)
56 err(1, "Cannot write to cgroup.event_control");
57
58 while (1) {
59 uint64_t result;
60
61 ret = read(efd, &result, sizeof(result));
62 if (ret == -1) {
63 if (errno == EINTR)
64 continue;
65 err(1, "Cannot read from eventfd");
66 }
67 assert(ret == sizeof(result));
68
69 ret = access(event_control_path, W_OK);
70 if ((ret == -1) && (errno == ENOENT)) {
71 puts("The cgroup seems to have removed.");
72 break;
73 }
74
75 if (ret == -1)
76 err(1, "cgroup.event_control is not accessible any more");
77
78 printf("%s %s: crossed\n", argv[1], argv[2]);
79 }
80
81 return 0;
82}
diff --git a/tools/firewire/nosy-dump.c b/tools/firewire/nosy-dump.c
index f93b776370b6..3179c711bd65 100644
--- a/tools/firewire/nosy-dump.c
+++ b/tools/firewire/nosy-dump.c
@@ -150,6 +150,8 @@ subaction_create(uint32_t *data, size_t length)
150 150
151 /* we put the ack in the subaction struct for easy access. */ 151 /* we put the ack in the subaction struct for easy access. */
152 sa = malloc(sizeof *sa - sizeof sa->packet + length); 152 sa = malloc(sizeof *sa - sizeof sa->packet + length);
153 if (!sa)
154 exit(EXIT_FAILURE);
153 sa->ack = data[length / 4 - 1]; 155 sa->ack = data[length / 4 - 1];
154 sa->length = length; 156 sa->length = length;
155 memcpy(&sa->packet, data, length); 157 memcpy(&sa->packet, data, length);
@@ -180,6 +182,8 @@ link_transaction_lookup(int request_node, int response_node, int tlabel)
180 } 182 }
181 183
182 t = malloc(sizeof *t); 184 t = malloc(sizeof *t);
185 if (!t)
186 exit(EXIT_FAILURE);
183 t->request_node = request_node; 187 t->request_node = request_node;
184 t->response_node = response_node; 188 t->response_node = response_node;
185 t->tlabel = tlabel; 189 t->tlabel = tlabel;
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index 5959affd8820..c800ea4c8bf9 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -43,6 +43,7 @@
43#include <sys/stat.h> 43#include <sys/stat.h>
44#include <fcntl.h> 44#include <fcntl.h>
45#include <dirent.h> 45#include <dirent.h>
46#include <net/if.h>
46 47
47/* 48/*
48 * KVP protocol: The user mode component first registers with the 49 * KVP protocol: The user mode component first registers with the
@@ -88,6 +89,7 @@ static char *os_major = "";
88static char *os_minor = ""; 89static char *os_minor = "";
89static char *processor_arch; 90static char *processor_arch;
90static char *os_build; 91static char *os_build;
92static char *os_version;
91static char *lic_version = "Unknown version"; 93static char *lic_version = "Unknown version";
92static struct utsname uts_buf; 94static struct utsname uts_buf;
93 95
@@ -95,7 +97,7 @@ static struct utsname uts_buf;
95 * The location of the interface configuration file. 97 * The location of the interface configuration file.
96 */ 98 */
97 99
98#define KVP_CONFIG_LOC "/var/opt/" 100#define KVP_CONFIG_LOC "/var/lib/hyperv"
99 101
100#define MAX_FILE_NAME 100 102#define MAX_FILE_NAME 100
101#define ENTRIES_PER_BLOCK 50 103#define ENTRIES_PER_BLOCK 50
@@ -149,7 +151,7 @@ static void kvp_update_file(int pool)
149 */ 151 */
150 kvp_acquire_lock(pool); 152 kvp_acquire_lock(pool);
151 153
152 filep = fopen(kvp_file_info[pool].fname, "w"); 154 filep = fopen(kvp_file_info[pool].fname, "we");
153 if (!filep) { 155 if (!filep) {
154 kvp_release_lock(pool); 156 kvp_release_lock(pool);
155 syslog(LOG_ERR, "Failed to open file, pool: %d", pool); 157 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
@@ -180,7 +182,7 @@ static void kvp_update_mem_state(int pool)
180 182
181 kvp_acquire_lock(pool); 183 kvp_acquire_lock(pool);
182 184
183 filep = fopen(kvp_file_info[pool].fname, "r"); 185 filep = fopen(kvp_file_info[pool].fname, "re");
184 if (!filep) { 186 if (!filep) {
185 kvp_release_lock(pool); 187 kvp_release_lock(pool);
186 syslog(LOG_ERR, "Failed to open file, pool: %d", pool); 188 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
@@ -232,9 +234,9 @@ static int kvp_file_init(void)
232 int i; 234 int i;
233 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK; 235 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
234 236
235 if (access("/var/opt/hyperv", F_OK)) { 237 if (access(KVP_CONFIG_LOC, F_OK)) {
236 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) { 238 if (mkdir(KVP_CONFIG_LOC, 0755 /* rwxr-xr-x */)) {
237 syslog(LOG_ERR, " Failed to create /var/opt/hyperv"); 239 syslog(LOG_ERR, " Failed to create %s", KVP_CONFIG_LOC);
238 exit(EXIT_FAILURE); 240 exit(EXIT_FAILURE);
239 } 241 }
240 } 242 }
@@ -243,14 +245,14 @@ static int kvp_file_init(void)
243 fname = kvp_file_info[i].fname; 245 fname = kvp_file_info[i].fname;
244 records_read = 0; 246 records_read = 0;
245 num_blocks = 1; 247 num_blocks = 1;
246 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i); 248 sprintf(fname, "%s/.kvp_pool_%d", KVP_CONFIG_LOC, i);
247 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH); 249 fd = open(fname, O_RDWR | O_CREAT | O_CLOEXEC, 0644 /* rw-r--r-- */);
248 250
249 if (fd == -1) 251 if (fd == -1)
250 return 1; 252 return 1;
251 253
252 254
253 filep = fopen(fname, "r"); 255 filep = fopen(fname, "re");
254 if (!filep) 256 if (!filep)
255 return 1; 257 return 1;
256 258
@@ -297,7 +299,7 @@ static int kvp_file_init(void)
297 return 0; 299 return 0;
298} 300}
299 301
300static int kvp_key_delete(int pool, __u8 *key, int key_size) 302static int kvp_key_delete(int pool, const char *key, int key_size)
301{ 303{
302 int i; 304 int i;
303 int j, k; 305 int j, k;
@@ -340,7 +342,7 @@ static int kvp_key_delete(int pool, __u8 *key, int key_size)
340 return 1; 342 return 1;
341} 343}
342 344
343static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, 345static int kvp_key_add_or_modify(int pool, const char *key, int key_size, const char *value,
344 int value_size) 346 int value_size)
345{ 347{
346 int i; 348 int i;
@@ -394,7 +396,7 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
394 return 0; 396 return 0;
395} 397}
396 398
397static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, 399static int kvp_get_value(int pool, const char *key, int key_size, char *value,
398 int value_size) 400 int value_size)
399{ 401{
400 int i; 402 int i;
@@ -426,8 +428,8 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
426 return 1; 428 return 1;
427} 429}
428 430
429static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, 431static int kvp_pool_enumerate(int pool, int index, char *key, int key_size,
430 __u8 *value, int value_size) 432 char *value, int value_size)
431{ 433{
432 struct kvp_record *record; 434 struct kvp_record *record;
433 435
@@ -453,7 +455,9 @@ void kvp_get_os_info(void)
453 char *p, buf[512]; 455 char *p, buf[512];
454 456
455 uname(&uts_buf); 457 uname(&uts_buf);
456 os_build = uts_buf.release; 458 os_version = uts_buf.release;
459 os_build = strdup(uts_buf.release);
460
457 os_name = uts_buf.sysname; 461 os_name = uts_buf.sysname;
458 processor_arch = uts_buf.machine; 462 processor_arch = uts_buf.machine;
459 463
@@ -462,7 +466,7 @@ void kvp_get_os_info(void)
462 * string to be of the form: x.y.z 466 * string to be of the form: x.y.z
463 * Strip additional information we may have. 467 * Strip additional information we may have.
464 */ 468 */
465 p = strchr(os_build, '-'); 469 p = strchr(os_version, '-');
466 if (p) 470 if (p)
467 *p = '\0'; 471 *p = '\0';
468 472
@@ -879,7 +883,7 @@ static int kvp_process_ip_address(void *addrp,
879 addr_length = INET6_ADDRSTRLEN; 883 addr_length = INET6_ADDRSTRLEN;
880 } 884 }
881 885
882 if ((length - *offset) < addr_length + 1) 886 if ((length - *offset) < addr_length + 2)
883 return HV_E_FAIL; 887 return HV_E_FAIL;
884 if (str == NULL) { 888 if (str == NULL) {
885 strcpy(buffer, "inet_ntop failed\n"); 889 strcpy(buffer, "inet_ntop failed\n");
@@ -887,11 +891,13 @@ static int kvp_process_ip_address(void *addrp,
887 } 891 }
888 if (*offset == 0) 892 if (*offset == 0)
889 strcpy(buffer, tmp); 893 strcpy(buffer, tmp);
890 else 894 else {
895 strcat(buffer, ";");
891 strcat(buffer, tmp); 896 strcat(buffer, tmp);
892 strcat(buffer, ";"); 897 }
893 898
894 *offset += strlen(str) + 1; 899 *offset += strlen(str) + 1;
900
895 return 0; 901 return 0;
896} 902}
897 903
@@ -953,7 +959,9 @@ kvp_get_ip_info(int family, char *if_name, int op,
953 * supported address families; if not we gather info on 959 * supported address families; if not we gather info on
954 * the specified address family. 960 * the specified address family.
955 */ 961 */
956 if ((family != 0) && (curp->ifa_addr->sa_family != family)) { 962 if ((((family != 0) &&
963 (curp->ifa_addr->sa_family != family))) ||
964 (curp->ifa_flags & IFF_LOOPBACK)) {
957 curp = curp->ifa_next; 965 curp = curp->ifa_next;
958 continue; 966 continue;
959 } 967 }
@@ -1154,16 +1162,13 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
1154 snprintf(str, sizeof(str), "%s", "DNS"); 1162 snprintf(str, sizeof(str), "%s", "DNS");
1155 break; 1163 break;
1156 } 1164 }
1157 if (i != 0) { 1165
1158 if (type != DNS) { 1166 if (type == DNS) {
1159 snprintf(sub_str, sizeof(sub_str),
1160 "_%d", i++);
1161 } else {
1162 snprintf(sub_str, sizeof(sub_str),
1163 "%d", ++i);
1164 }
1165 } else if (type == DNS) {
1166 snprintf(sub_str, sizeof(sub_str), "%d", ++i); 1167 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1168 } else if (type == GATEWAY && i == 0) {
1169 ++i;
1170 } else {
1171 snprintf(sub_str, sizeof(sub_str), "%d", i++);
1167 } 1172 }
1168 1173
1169 1174
@@ -1183,17 +1188,13 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
1183 snprintf(str, sizeof(str), "%s", "DNS"); 1188 snprintf(str, sizeof(str), "%s", "DNS");
1184 break; 1189 break;
1185 } 1190 }
1186 if ((j != 0) || (type == DNS)) { 1191
1187 if (type != DNS) { 1192 if (type == DNS) {
1188 snprintf(sub_str, sizeof(sub_str), 1193 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1189 "_%d", j++); 1194 } else if (j == 0) {
1190 } else { 1195 ++j;
1191 snprintf(sub_str, sizeof(sub_str), 1196 } else {
1192 "%d", ++i); 1197 snprintf(sub_str, sizeof(sub_str), "_%d", j++);
1193 }
1194 } else if (type == DNS) {
1195 snprintf(sub_str, sizeof(sub_str),
1196 "%d", ++i);
1197 } 1198 }
1198 } else { 1199 } else {
1199 return HV_INVALIDARG; 1200 return HV_INVALIDARG;
@@ -1236,18 +1237,19 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1236 * Here is the format of the ip configuration file: 1237 * Here is the format of the ip configuration file:
1237 * 1238 *
1238 * HWADDR=macaddr 1239 * HWADDR=macaddr
1239 * IF_NAME=interface name 1240 * DEVICE=interface name
1240 * DHCP=yes (This is optional; if yes, DHCP is configured) 1241 * BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
1242 * or "none" if no boot-time protocol should be used)
1241 * 1243 *
1242 * IPADDR=ipaddr1 1244 * IPADDR0=ipaddr1
1243 * IPADDR_1=ipaddr2 1245 * IPADDR1=ipaddr2
1244 * IPADDR_x=ipaddry (where y = x + 1) 1246 * IPADDRx=ipaddry (where y = x + 1)
1245 * 1247 *
1246 * NETMASK=netmask1 1248 * NETMASK0=netmask1
1247 * NETMASK_x=netmasky (where y = x + 1) 1249 * NETMASKx=netmasky (where y = x + 1)
1248 * 1250 *
1249 * GATEWAY=ipaddr1 1251 * GATEWAY=ipaddr1
1250 * GATEWAY_x=ipaddry (where y = x + 1) 1252 * GATEWAYx=ipaddry (where y = x + 1)
1251 * 1253 *
1252 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) 1254 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1253 * 1255 *
@@ -1263,7 +1265,7 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1263 */ 1265 */
1264 1266
1265 snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC, 1267 snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1266 "hyperv/ifcfg-", if_name); 1268 "/ifcfg-", if_name);
1267 1269
1268 file = fopen(if_file, "w"); 1270 file = fopen(if_file, "w");
1269 1271
@@ -1286,12 +1288,12 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1286 if (error) 1288 if (error)
1287 goto setval_error; 1289 goto setval_error;
1288 1290
1289 error = kvp_write_file(file, "IF_NAME", "", if_name); 1291 error = kvp_write_file(file, "DEVICE", "", if_name);
1290 if (error) 1292 if (error)
1291 goto setval_error; 1293 goto setval_error;
1292 1294
1293 if (new_val->dhcp_enabled) { 1295 if (new_val->dhcp_enabled) {
1294 error = kvp_write_file(file, "DHCP", "", "yes"); 1296 error = kvp_write_file(file, "BOOTPROTO", "", "dhcp");
1295 if (error) 1297 if (error)
1296 goto setval_error; 1298 goto setval_error;
1297 1299
@@ -1299,6 +1301,11 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1299 * We are done!. 1301 * We are done!.
1300 */ 1302 */
1301 goto setval_done; 1303 goto setval_done;
1304
1305 } else {
1306 error = kvp_write_file(file, "BOOTPROTO", "", "none");
1307 if (error)
1308 goto setval_error;
1302 } 1309 }
1303 1310
1304 /* 1311 /*
@@ -1478,13 +1485,19 @@ int main(void)
1478 len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0, 1485 len = recvfrom(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0,
1479 addr_p, &addr_l); 1486 addr_p, &addr_l);
1480 1487
1481 if (len < 0 || addr.nl_pid) { 1488 if (len < 0) {
1482 syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s", 1489 syslog(LOG_ERR, "recvfrom failed; pid:%u error:%d %s",
1483 addr.nl_pid, errno, strerror(errno)); 1490 addr.nl_pid, errno, strerror(errno));
1484 close(fd); 1491 close(fd);
1485 return -1; 1492 return -1;
1486 } 1493 }
1487 1494
1495 if (addr.nl_pid) {
1496 syslog(LOG_WARNING, "Received packet from untrusted pid:%u",
1497 addr.nl_pid);
1498 continue;
1499 }
1500
1488 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer; 1501 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
1489 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); 1502 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
1490 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; 1503 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
@@ -1649,7 +1662,7 @@ int main(void)
1649 strcpy(key_name, "OSMinorVersion"); 1662 strcpy(key_name, "OSMinorVersion");
1650 break; 1663 break;
1651 case OSVersion: 1664 case OSVersion:
1652 strcpy(key_value, os_build); 1665 strcpy(key_value, os_version);
1653 strcpy(key_name, "OSVersion"); 1666 strcpy(key_name, "OSVersion");
1654 break; 1667 break;
1655 case ProcessorArchitecture: 1668 case ProcessorArchitecture:
diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh
index 3e9427e08d80..735aafd64a3f 100755
--- a/tools/hv/hv_set_ifconfig.sh
+++ b/tools/hv/hv_set_ifconfig.sh
@@ -20,18 +20,19 @@
20# Here is the format of the ip configuration file: 20# Here is the format of the ip configuration file:
21# 21#
22# HWADDR=macaddr 22# HWADDR=macaddr
23# IF_NAME=interface name 23# DEVICE=interface name
24# DHCP=yes (This is optional; if yes, DHCP is configured) 24# BOOTPROTO=<protocol> (where <protocol> is "dhcp" if DHCP is configured
25# or "none" if no boot-time protocol should be used)
25# 26#
26# IPADDR=ipaddr1 27# IPADDR0=ipaddr1
27# IPADDR_1=ipaddr2 28# IPADDR1=ipaddr2
28# IPADDR_x=ipaddry (where y = x + 1) 29# IPADDRx=ipaddry (where y = x + 1)
29# 30#
30# NETMASK=netmask1 31# NETMASK0=netmask1
31# NETMASK_x=netmasky (where y = x + 1) 32# NETMASKx=netmasky (where y = x + 1)
32# 33#
33# GATEWAY=ipaddr1 34# GATEWAY=ipaddr1
34# GATEWAY_x=ipaddry (where y = x + 1) 35# GATEWAYx=ipaddry (where y = x + 1)
35# 36#
36# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) 37# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
37# 38#
@@ -53,11 +54,6 @@ echo "NM_CONTROLLED=no" >> $1
53echo "PEERDNS=yes" >> $1 54echo "PEERDNS=yes" >> $1
54echo "ONBOOT=yes" >> $1 55echo "ONBOOT=yes" >> $1
55 56
56dhcp=$(grep "DHCP" $1 2>/dev/null)
57if [ "$dhcp" != "" ];
58then
59echo "BOOTPROTO=dhcp" >> $1;
60fi
61 57
62cp $1 /etc/sysconfig/network-scripts/ 58cp $1 /etc/sysconfig/network-scripts/
63 59
@@ -65,4 +61,4 @@ cp $1 /etc/sysconfig/network-scripts/
65interface=$(echo $1 | awk -F - '{ print $2 }') 61interface=$(echo $1 | awk -F - '{ print $2 }')
66 62
67/sbin/ifdown $interface 2>/dev/null 63/sbin/ifdown $interface 2>/dev/null
68/sbin/ifup $interfac 2>/dev/null 64/sbin/ifup $interface 2>/dev/null
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c
index fd2f9221b241..07a03452c227 100644
--- a/tools/lguest/lguest.c
+++ b/tools/lguest/lguest.c
@@ -179,29 +179,6 @@ static struct termios orig_term;
179#define wmb() __asm__ __volatile__("" : : : "memory") 179#define wmb() __asm__ __volatile__("" : : : "memory")
180#define mb() __asm__ __volatile__("" : : : "memory") 180#define mb() __asm__ __volatile__("" : : : "memory")
181 181
182/*
183 * Convert an iovec element to the given type.
184 *
185 * This is a fairly ugly trick: we need to know the size of the type and
186 * alignment requirement to check the pointer is kosher. It's also nice to
187 * have the name of the type in case we report failure.
188 *
189 * Typing those three things all the time is cumbersome and error prone, so we
190 * have a macro which sets them all up and passes to the real function.
191 */
192#define convert(iov, type) \
193 ((type *)_convert((iov), sizeof(type), __alignof__(type), #type))
194
195static void *_convert(struct iovec *iov, size_t size, size_t align,
196 const char *name)
197{
198 if (iov->iov_len != size)
199 errx(1, "Bad iovec size %zu for %s", iov->iov_len, name);
200 if ((unsigned long)iov->iov_base % align != 0)
201 errx(1, "Bad alignment %p for %s", iov->iov_base, name);
202 return iov->iov_base;
203}
204
205/* Wrapper for the last available index. Makes it easier to change. */ 182/* Wrapper for the last available index. Makes it easier to change. */
206#define lg_last_avail(vq) ((vq)->last_avail_idx) 183#define lg_last_avail(vq) ((vq)->last_avail_idx)
207 184
@@ -228,7 +205,8 @@ static bool iov_empty(const struct iovec iov[], unsigned int num_iov)
228} 205}
229 206
230/* Take len bytes from the front of this iovec. */ 207/* Take len bytes from the front of this iovec. */
231static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len) 208static void iov_consume(struct iovec iov[], unsigned num_iov,
209 void *dest, unsigned len)
232{ 210{
233 unsigned int i; 211 unsigned int i;
234 212
@@ -236,11 +214,16 @@ static void iov_consume(struct iovec iov[], unsigned num_iov, unsigned len)
236 unsigned int used; 214 unsigned int used;
237 215
238 used = iov[i].iov_len < len ? iov[i].iov_len : len; 216 used = iov[i].iov_len < len ? iov[i].iov_len : len;
217 if (dest) {
218 memcpy(dest, iov[i].iov_base, used);
219 dest += used;
220 }
239 iov[i].iov_base += used; 221 iov[i].iov_base += used;
240 iov[i].iov_len -= used; 222 iov[i].iov_len -= used;
241 len -= used; 223 len -= used;
242 } 224 }
243 assert(len == 0); 225 if (len != 0)
226 errx(1, "iovec too short!");
244} 227}
245 228
246/* The device virtqueue descriptors are followed by feature bitmasks. */ 229/* The device virtqueue descriptors are followed by feature bitmasks. */
@@ -864,7 +847,7 @@ static void console_output(struct virtqueue *vq)
864 warn("Write to stdout gave %i (%d)", len, errno); 847 warn("Write to stdout gave %i (%d)", len, errno);
865 break; 848 break;
866 } 849 }
867 iov_consume(iov, out, len); 850 iov_consume(iov, out, NULL, len);
868 } 851 }
869 852
870 /* 853 /*
@@ -1591,9 +1574,9 @@ static void blk_request(struct virtqueue *vq)
1591{ 1574{
1592 struct vblk_info *vblk = vq->dev->priv; 1575 struct vblk_info *vblk = vq->dev->priv;
1593 unsigned int head, out_num, in_num, wlen; 1576 unsigned int head, out_num, in_num, wlen;
1594 int ret; 1577 int ret, i;
1595 u8 *in; 1578 u8 *in;
1596 struct virtio_blk_outhdr *out; 1579 struct virtio_blk_outhdr out;
1597 struct iovec iov[vq->vring.num]; 1580 struct iovec iov[vq->vring.num];
1598 off64_t off; 1581 off64_t off;
1599 1582
@@ -1603,32 +1586,36 @@ static void blk_request(struct virtqueue *vq)
1603 */ 1586 */
1604 head = wait_for_vq_desc(vq, iov, &out_num, &in_num); 1587 head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
1605 1588
1606 /* 1589 /* Copy the output header from the front of the iov (adjusts iov) */
1607 * Every block request should contain at least one output buffer 1590 iov_consume(iov, out_num, &out, sizeof(out));
1608 * (detailing the location on disk and the type of request) and one 1591
1609 * input buffer (to hold the result). 1592 /* Find and trim end of iov input array, for our status byte. */
1610 */ 1593 in = NULL;
1611 if (out_num == 0 || in_num == 0) 1594 for (i = out_num + in_num - 1; i >= out_num; i--) {
1612 errx(1, "Bad virtblk cmd %u out=%u in=%u", 1595 if (iov[i].iov_len > 0) {
1613 head, out_num, in_num); 1596 in = iov[i].iov_base + iov[i].iov_len - 1;
1597 iov[i].iov_len--;
1598 break;
1599 }
1600 }
1601 if (!in)
1602 errx(1, "Bad virtblk cmd with no room for status");
1614 1603
1615 out = convert(&iov[0], struct virtio_blk_outhdr);
1616 in = convert(&iov[out_num+in_num-1], u8);
1617 /* 1604 /*
1618 * For historical reasons, block operations are expressed in 512 byte 1605 * For historical reasons, block operations are expressed in 512 byte
1619 * "sectors". 1606 * "sectors".
1620 */ 1607 */
1621 off = out->sector * 512; 1608 off = out.sector * 512;
1622 1609
1623 /* 1610 /*
1624 * In general the virtio block driver is allowed to try SCSI commands. 1611 * In general the virtio block driver is allowed to try SCSI commands.
1625 * It'd be nice if we supported eject, for example, but we don't. 1612 * It'd be nice if we supported eject, for example, but we don't.
1626 */ 1613 */
1627 if (out->type & VIRTIO_BLK_T_SCSI_CMD) { 1614 if (out.type & VIRTIO_BLK_T_SCSI_CMD) {
1628 fprintf(stderr, "Scsi commands unsupported\n"); 1615 fprintf(stderr, "Scsi commands unsupported\n");
1629 *in = VIRTIO_BLK_S_UNSUPP; 1616 *in = VIRTIO_BLK_S_UNSUPP;
1630 wlen = sizeof(*in); 1617 wlen = sizeof(*in);
1631 } else if (out->type & VIRTIO_BLK_T_OUT) { 1618 } else if (out.type & VIRTIO_BLK_T_OUT) {
1632 /* 1619 /*
1633 * Write 1620 * Write
1634 * 1621 *
@@ -1636,10 +1623,10 @@ static void blk_request(struct virtqueue *vq)
1636 * if they try to write past end. 1623 * if they try to write past end.
1637 */ 1624 */
1638 if (lseek64(vblk->fd, off, SEEK_SET) != off) 1625 if (lseek64(vblk->fd, off, SEEK_SET) != off)
1639 err(1, "Bad seek to sector %llu", out->sector); 1626 err(1, "Bad seek to sector %llu", out.sector);
1640 1627
1641 ret = writev(vblk->fd, iov+1, out_num-1); 1628 ret = writev(vblk->fd, iov, out_num);
1642 verbose("WRITE to sector %llu: %i\n", out->sector, ret); 1629 verbose("WRITE to sector %llu: %i\n", out.sector, ret);
1643 1630
1644 /* 1631 /*
1645 * Grr... Now we know how long the descriptor they sent was, we 1632 * Grr... Now we know how long the descriptor they sent was, we
@@ -1655,7 +1642,7 @@ static void blk_request(struct virtqueue *vq)
1655 1642
1656 wlen = sizeof(*in); 1643 wlen = sizeof(*in);
1657 *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); 1644 *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
1658 } else if (out->type & VIRTIO_BLK_T_FLUSH) { 1645 } else if (out.type & VIRTIO_BLK_T_FLUSH) {
1659 /* Flush */ 1646 /* Flush */
1660 ret = fdatasync(vblk->fd); 1647 ret = fdatasync(vblk->fd);
1661 verbose("FLUSH fdatasync: %i\n", ret); 1648 verbose("FLUSH fdatasync: %i\n", ret);
@@ -1669,10 +1656,9 @@ static void blk_request(struct virtqueue *vq)
1669 * if they try to read past end. 1656 * if they try to read past end.
1670 */ 1657 */
1671 if (lseek64(vblk->fd, off, SEEK_SET) != off) 1658 if (lseek64(vblk->fd, off, SEEK_SET) != off)
1672 err(1, "Bad seek to sector %llu", out->sector); 1659 err(1, "Bad seek to sector %llu", out.sector);
1673 1660
1674 ret = readv(vblk->fd, iov+1, in_num-1); 1661 ret = readv(vblk->fd, iov + out_num, in_num);
1675 verbose("READ from sector %llu: %i\n", out->sector, ret);
1676 if (ret >= 0) { 1662 if (ret >= 0) {
1677 wlen = sizeof(*in) + ret; 1663 wlen = sizeof(*in) + ret;
1678 *in = VIRTIO_BLK_S_OK; 1664 *in = VIRTIO_BLK_S_OK;
@@ -1758,7 +1744,7 @@ static void rng_input(struct virtqueue *vq)
1758 len = readv(rng_info->rfd, iov, in_num); 1744 len = readv(rng_info->rfd, iov, in_num);
1759 if (len <= 0) 1745 if (len <= 0)
1760 err(1, "Read from /dev/random gave %i", len); 1746 err(1, "Read from /dev/random gave %i", len);
1761 iov_consume(iov, in_num, len); 1747 iov_consume(iov, in_num, NULL, len);
1762 totlen += len; 1748 totlen += len;
1763 } 1749 }
1764 1750
diff --git a/tools/lguest/lguest.txt b/tools/lguest/lguest.txt
index bff0c554485d..7203ace65e83 100644
--- a/tools/lguest/lguest.txt
+++ b/tools/lguest/lguest.txt
@@ -29,10 +29,6 @@ Running Lguest:
29 29
30 You will need to configure your kernel with the following options: 30 You will need to configure your kernel with the following options:
31 31
32 "General setup":
33 "Prompt for development and/or incomplete code/drivers" = Y
34 (CONFIG_EXPERIMENTAL=y)
35
36 "Processor type and features": 32 "Processor type and features":
37 "Paravirtualized guest support" = Y 33 "Paravirtualized guest support" = Y
38 "Lguest guest support" = Y 34 "Lguest guest support" = Y
@@ -43,10 +39,10 @@ Running Lguest:
43 39
44 "Device Drivers": 40 "Device Drivers":
45 "Block devices" 41 "Block devices"
46 "Virtio block driver (EXPERIMENTAL)" = M/Y 42 "Virtio block driver" = M/Y
47 "Network device support" 43 "Network device support"
48 "Universal TUN/TAP device driver support" = M/Y 44 "Universal TUN/TAP device driver support" = M/Y
49 "Virtio network driver (EXPERIMENTAL)" = M/Y 45 "Virtio network driver" = M/Y
50 (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m) 46 (CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m)
51 47
52 "Virtualization" 48 "Virtualization"
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
index 04d959fa0226..a20e32033431 100644
--- a/tools/lib/traceevent/Makefile
+++ b/tools/lib/traceevent/Makefile
@@ -253,7 +253,7 @@ all_deps := $(all_objs:%.o=.%.d)
253# let .d file also depends on the source and header files 253# let .d file also depends on the source and header files
254define check_deps 254define check_deps
255 @set -e; $(RM) $@; \ 255 @set -e; $(RM) $@; \
256 $(CC) -M $(CFLAGS) $< > $@.$$$$; \ 256 $(CC) -MM $(CFLAGS) $< > $@.$$$$; \
257 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ 257 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
258 $(RM) $@.$$$$ 258 $(RM) $@.$$$$
259endef 259endef
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index f2989c525e48..82b0606dcb8a 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 * 19 *
@@ -174,7 +173,7 @@ static int cmdline_init(struct pevent *pevent)
174 return 0; 173 return 0;
175} 174}
176 175
177static char *find_cmdline(struct pevent *pevent, int pid) 176static const char *find_cmdline(struct pevent *pevent, int pid)
178{ 177{
179 const struct cmdline *comm; 178 const struct cmdline *comm;
180 struct cmdline key; 179 struct cmdline key;
@@ -1224,6 +1223,34 @@ static int field_is_long(struct format_field *field)
1224 return 0; 1223 return 0;
1225} 1224}
1226 1225
1226static unsigned int type_size(const char *name)
1227{
1228 /* This covers all FIELD_IS_STRING types. */
1229 static struct {
1230 const char *type;
1231 unsigned int size;
1232 } table[] = {
1233 { "u8", 1 },
1234 { "u16", 2 },
1235 { "u32", 4 },
1236 { "u64", 8 },
1237 { "s8", 1 },
1238 { "s16", 2 },
1239 { "s32", 4 },
1240 { "s64", 8 },
1241 { "char", 1 },
1242 { },
1243 };
1244 int i;
1245
1246 for (i = 0; table[i].type; i++) {
1247 if (!strcmp(table[i].type, name))
1248 return table[i].size;
1249 }
1250
1251 return 0;
1252}
1253
1227static int event_read_fields(struct event_format *event, struct format_field **fields) 1254static int event_read_fields(struct event_format *event, struct format_field **fields)
1228{ 1255{
1229 struct format_field *field = NULL; 1256 struct format_field *field = NULL;
@@ -1233,6 +1260,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1233 int count = 0; 1260 int count = 0;
1234 1261
1235 do { 1262 do {
1263 unsigned int size_dynamic = 0;
1264
1236 type = read_token(&token); 1265 type = read_token(&token);
1237 if (type == EVENT_NEWLINE) { 1266 if (type == EVENT_NEWLINE) {
1238 free_token(token); 1267 free_token(token);
@@ -1391,6 +1420,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1391 field->type = new_type; 1420 field->type = new_type;
1392 strcat(field->type, " "); 1421 strcat(field->type, " ");
1393 strcat(field->type, field->name); 1422 strcat(field->type, field->name);
1423 size_dynamic = type_size(field->name);
1394 free_token(field->name); 1424 free_token(field->name);
1395 strcat(field->type, brackets); 1425 strcat(field->type, brackets);
1396 field->name = token; 1426 field->name = token;
@@ -1463,7 +1493,8 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1463 if (read_expect_type(EVENT_ITEM, &token)) 1493 if (read_expect_type(EVENT_ITEM, &token))
1464 goto fail; 1494 goto fail;
1465 1495
1466 /* add signed type */ 1496 if (strtoul(token, NULL, 0))
1497 field->flags |= FIELD_IS_SIGNED;
1467 1498
1468 free_token(token); 1499 free_token(token);
1469 if (read_expected(EVENT_OP, ";") < 0) 1500 if (read_expected(EVENT_OP, ";") < 0)
@@ -1478,10 +1509,14 @@ static int event_read_fields(struct event_format *event, struct format_field **f
1478 if (field->flags & FIELD_IS_ARRAY) { 1509 if (field->flags & FIELD_IS_ARRAY) {
1479 if (field->arraylen) 1510 if (field->arraylen)
1480 field->elementsize = field->size / field->arraylen; 1511 field->elementsize = field->size / field->arraylen;
1512 else if (field->flags & FIELD_IS_DYNAMIC)
1513 field->elementsize = size_dynamic;
1481 else if (field->flags & FIELD_IS_STRING) 1514 else if (field->flags & FIELD_IS_STRING)
1482 field->elementsize = 1; 1515 field->elementsize = 1;
1483 else 1516 else if (field->flags & FIELD_IS_LONG)
1484 field->elementsize = event->pevent->long_size; 1517 field->elementsize = event->pevent ?
1518 event->pevent->long_size :
1519 sizeof(long);
1485 } else 1520 } else
1486 field->elementsize = field->size; 1521 field->elementsize = field->size;
1487 1522
@@ -1785,6 +1820,8 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
1785 strcmp(token, "/") == 0 || 1820 strcmp(token, "/") == 0 ||
1786 strcmp(token, "<") == 0 || 1821 strcmp(token, "<") == 0 ||
1787 strcmp(token, ">") == 0 || 1822 strcmp(token, ">") == 0 ||
1823 strcmp(token, "<=") == 0 ||
1824 strcmp(token, ">=") == 0 ||
1788 strcmp(token, "==") == 0 || 1825 strcmp(token, "==") == 0 ||
1789 strcmp(token, "!=") == 0) { 1826 strcmp(token, "!=") == 0) {
1790 1827
@@ -2481,7 +2518,7 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char **
2481 2518
2482 free_token(token); 2519 free_token(token);
2483 arg = alloc_arg(); 2520 arg = alloc_arg();
2484 if (!field) { 2521 if (!arg) {
2485 do_warning("%s: not enough memory!", __func__); 2522 do_warning("%s: not enough memory!", __func__);
2486 *tok = NULL; 2523 *tok = NULL;
2487 return EVENT_ERROR; 2524 return EVENT_ERROR;
@@ -2637,7 +2674,7 @@ process_func_handler(struct event_format *event, struct pevent_function_handler
2637 struct print_arg *farg; 2674 struct print_arg *farg;
2638 enum event_type type; 2675 enum event_type type;
2639 char *token; 2676 char *token;
2640 char *test; 2677 const char *test;
2641 int i; 2678 int i;
2642 2679
2643 arg->type = PRINT_FUNC; 2680 arg->type = PRINT_FUNC;
@@ -3889,7 +3926,7 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
3889 struct event_format *event, struct print_arg *arg) 3926 struct event_format *event, struct print_arg *arg)
3890{ 3927{
3891 unsigned char *buf; 3928 unsigned char *buf;
3892 char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"; 3929 const char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
3893 3930
3894 if (arg->type == PRINT_FUNC) { 3931 if (arg->type == PRINT_FUNC) {
3895 process_defined_func(s, data, size, event, arg); 3932 process_defined_func(s, data, size, event, arg);
@@ -3931,7 +3968,8 @@ static int is_printable_array(char *p, unsigned int len)
3931 return 1; 3968 return 1;
3932} 3969}
3933 3970
3934static void print_event_fields(struct trace_seq *s, void *data, int size, 3971static void print_event_fields(struct trace_seq *s, void *data,
3972 int size __maybe_unused,
3935 struct event_format *event) 3973 struct event_format *event)
3936{ 3974{
3937 struct format_field *field; 3975 struct format_field *field;
@@ -4408,7 +4446,7 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
4408void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 4446void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
4409 struct pevent_record *record) 4447 struct pevent_record *record)
4410{ 4448{
4411 static char *spaces = " "; /* 20 spaces */ 4449 static const char *spaces = " "; /* 20 spaces */
4412 struct event_format *event; 4450 struct event_format *event;
4413 unsigned long secs; 4451 unsigned long secs;
4414 unsigned long usecs; 4452 unsigned long usecs;
@@ -5070,8 +5108,8 @@ static const char * const pevent_error_str[] = {
5070}; 5108};
5071#undef _PE 5109#undef _PE
5072 5110
5073int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum, 5111int pevent_strerror(struct pevent *pevent __maybe_unused,
5074 char *buf, size_t buflen) 5112 enum pevent_errno errnum, char *buf, size_t buflen)
5075{ 5113{
5076 int idx; 5114 int idx;
5077 const char *msg; 5115 const char *msg;
@@ -5100,6 +5138,7 @@ int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
5100 case PEVENT_ERRNO__READ_FORMAT_FAILED: 5138 case PEVENT_ERRNO__READ_FORMAT_FAILED:
5101 case PEVENT_ERRNO__READ_PRINT_FAILED: 5139 case PEVENT_ERRNO__READ_PRINT_FAILED:
5102 case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED: 5140 case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED:
5141 case PEVENT_ERRNO__INVALID_ARG_TYPE:
5103 snprintf(buf, buflen, "%s", msg); 5142 snprintf(buf, buflen, "%s", msg);
5104 break; 5143 break;
5105 5144
@@ -5362,7 +5401,7 @@ int pevent_register_print_function(struct pevent *pevent,
5362 if (type == PEVENT_FUNC_ARG_VOID) 5401 if (type == PEVENT_FUNC_ARG_VOID)
5363 break; 5402 break;
5364 5403
5365 if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) { 5404 if (type >= PEVENT_FUNC_ARG_MAX_TYPES) {
5366 do_warning("Invalid argument type %d", type); 5405 do_warning("Invalid argument type %d", type);
5367 ret = PEVENT_ERRNO__INVALID_ARG_TYPE; 5406 ret = PEVENT_ERRNO__INVALID_ARG_TYPE;
5368 goto out_free; 5407 goto out_free;
@@ -5560,7 +5599,7 @@ void pevent_free(struct pevent *pevent)
5560 } 5599 }
5561 5600
5562 if (pevent->func_map) { 5601 if (pevent->func_map) {
5563 for (i = 0; i < pevent->func_count; i++) { 5602 for (i = 0; i < (int)pevent->func_count; i++) {
5564 free(pevent->func_map[i].func); 5603 free(pevent->func_map[i].func);
5565 free(pevent->func_map[i].mod); 5604 free(pevent->func_map[i].mod);
5566 } 5605 }
@@ -5582,7 +5621,7 @@ void pevent_free(struct pevent *pevent)
5582 } 5621 }
5583 5622
5584 if (pevent->printk_map) { 5623 if (pevent->printk_map) {
5585 for (i = 0; i < pevent->printk_count; i++) 5624 for (i = 0; i < (int)pevent->printk_count; i++)
5586 free(pevent->printk_map[i].printk); 5625 free(pevent->printk_map[i].printk);
5587 free(pevent->printk_map); 5626 free(pevent->printk_map);
5588 } 5627 }
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 24a4bbabc5d5..7be7e89533e4 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 19 */
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h
index bc075006966e..e76c9acb92cd 100644
--- a/tools/lib/traceevent/event-utils.h
+++ b/tools/lib/traceevent/event-utils.h
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 19 */
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index 5ea4326ad11f..2500e75583fc 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 19 */
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c
index f023a133abb6..bba701cf10e6 100644
--- a/tools/lib/traceevent/parse-utils.c
+++ b/tools/lib/traceevent/parse-utils.c
@@ -1,3 +1,22 @@
1/*
2 * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
1#include <stdio.h> 20#include <stdio.h>
2#include <stdlib.h> 21#include <stdlib.h>
3#include <string.h> 22#include <string.h>
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
index b1ccc923e8a5..a57db805136a 100644
--- a/tools/lib/traceevent/trace-seq.c
+++ b/tools/lib/traceevent/trace-seq.c
@@ -13,8 +13,7 @@
13 * GNU Lesser General Public License for more details. 13 * GNU Lesser General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Lesser General Public 15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, write to the Free Software 16 * License along with this program; if not, see <http://www.gnu.org/licenses>
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 17 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 19 */
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index 9f2e44f2b17a..eb30044a922a 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -1,3 +1,5 @@
1include ../config/utilities.mak
2
1OUTPUT := ./ 3OUTPUT := ./
2ifeq ("$(origin O)", "command line") 4ifeq ("$(origin O)", "command line")
3 ifneq ($(O),) 5 ifneq ($(O),)
@@ -64,6 +66,7 @@ MAKEINFO=makeinfo
64INSTALL_INFO=install-info 66INSTALL_INFO=install-info
65DOCBOOK2X_TEXI=docbook2x-texi 67DOCBOOK2X_TEXI=docbook2x-texi
66DBLATEX=dblatex 68DBLATEX=dblatex
69XMLTO=xmlto
67ifndef PERL_PATH 70ifndef PERL_PATH
68 PERL_PATH = /usr/bin/perl 71 PERL_PATH = /usr/bin/perl
69endif 72endif
@@ -71,6 +74,16 @@ endif
71-include ../config.mak.autogen 74-include ../config.mak.autogen
72-include ../config.mak 75-include ../config.mak
73 76
77_tmp_tool_path := $(call get-executable,$(ASCIIDOC))
78ifeq ($(_tmp_tool_path),)
79 missing_tools = $(ASCIIDOC)
80endif
81
82_tmp_tool_path := $(call get-executable,$(XMLTO))
83ifeq ($(_tmp_tool_path),)
84 missing_tools += $(XMLTO)
85endif
86
74# 87#
75# For asciidoc ... 88# For asciidoc ...
76# -7.1.2, no extra settings are needed. 89# -7.1.2, no extra settings are needed.
@@ -170,7 +183,12 @@ pdf: $(OUTPUT)user-manual.pdf
170 183
171install: install-man 184install: install-man
172 185
173install-man: man 186check-man-tools:
187ifdef missing_tools
188 $(error "You need to install $(missing_tools) for man pages")
189endif
190
191do-install-man: man
174 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir) 192 $(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
175# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir) 193# $(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
176# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir) 194# $(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
@@ -178,6 +196,15 @@ install-man: man
178# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir) 196# $(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
179# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir) 197# $(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
180 198
199install-man: check-man-tools man
200
201try-install-man:
202ifdef missing_tools
203 $(warning Please install $(missing_tools) to have the man pages installed)
204else
205 $(MAKE) do-install-man
206endif
207
181install-info: info 208install-info: info
182 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir) 209 $(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
183 $(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir) 210 $(INSTALL) -m 644 $(OUTPUT)perf.info $(OUTPUT)perfman.info $(DESTDIR)$(infodir)
@@ -195,10 +222,14 @@ install-pdf: pdf
195#install-html: html 222#install-html: html
196# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) 223# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
197 224
225ifneq ($(MAKECMDGOALS),clean)
226ifneq ($(MAKECMDGOALS),tags)
198$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 227$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
199 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE 228 $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) $(OUTPUT)PERF-VERSION-FILE
200 229
201-include $(OUTPUT)PERF-VERSION-FILE 230-include $(OUTPUT)PERF-VERSION-FILE
231endif
232endif
202 233
203# 234#
204# Determine "include::" file references in asciidoc files. 235# Determine "include::" file references in asciidoc files.
@@ -246,7 +277,7 @@ $(MAN_HTML): $(OUTPUT)%.html : %.txt
246 277
247$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml 278$(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
248 $(QUIET_XMLTO)$(RM) $@ && \ 279 $(QUIET_XMLTO)$(RM) $@ && \
249 xmlto -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $< 280 $(XMLTO) -o $(OUTPUT) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
250 281
251$(OUTPUT)%.xml : %.txt 282$(OUTPUT)%.xml : %.txt
252 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \ 283 $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
diff --git a/tools/perf/Documentation/android.txt b/tools/perf/Documentation/android.txt
new file mode 100644
index 000000000000..8484c3a04a6a
--- /dev/null
+++ b/tools/perf/Documentation/android.txt
@@ -0,0 +1,78 @@
1How to compile perf for Android
2=========================================
3
4I. Set the Android NDK environment
5------------------------------------------------
6
7(a). Use the Android NDK
8------------------------------------------------
91. You need to download and install the Android Native Development Kit (NDK).
10Set the NDK variable to point to the path where you installed the NDK:
11 export NDK=/path/to/android-ndk
12
132. Set cross-compiling environment variables for NDK toolchain and sysroot.
14For arm:
15 export NDK_TOOLCHAIN=${NDK}/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-
16 export NDK_SYSROOT=${NDK}/platforms/android-9/arch-arm
17For x86:
18 export NDK_TOOLCHAIN=${NDK}/toolchains/x86-4.6/prebuilt/linux-x86/bin/i686-linux-android-
19 export NDK_SYSROOT=${NDK}/platforms/android-9/arch-x86
20
21This method is not working for Android NDK versions up to Revision 8b.
22perf uses some bionic enhancements that are not included in these NDK versions.
23You can use method (b) described below instead.
24
25(b). Use the Android source tree
26-----------------------------------------------
271. Download the master branch of the Android source tree.
28Set the environment for the target you want using:
29 source build/envsetup.sh
30 lunch
31
322. Build your own NDK sysroot to contain latest bionic changes and set the
33NDK sysroot environment variable.
34 cd ${ANDROID_BUILD_TOP}/ndk
35For arm:
36 ./build/tools/build-ndk-sysroot.sh --abi=arm
37 export NDK_SYSROOT=${ANDROID_BUILD_TOP}/ndk/build/platforms/android-3/arch-arm
38For x86:
39 ./build/tools/build-ndk-sysroot.sh --abi=x86
40 export NDK_SYSROOT=${ANDROID_BUILD_TOP}/ndk/build/platforms/android-3/arch-x86
41
423. Set the NDK toolchain environment variable.
43For arm:
44 export NDK_TOOLCHAIN=${ANDROID_TOOLCHAIN}/arm-linux-androideabi-
45For x86:
46 export NDK_TOOLCHAIN=${ANDROID_TOOLCHAIN}/i686-linux-android-
47
48II. Compile perf for Android
49------------------------------------------------
50You need to run make with the NDK toolchain and sysroot defined above:
51For arm:
52 make ARCH=arm CROSS_COMPILE=${NDK_TOOLCHAIN} CFLAGS="--sysroot=${NDK_SYSROOT}"
53For x86:
54 make ARCH=x86 CROSS_COMPILE=${NDK_TOOLCHAIN} CFLAGS="--sysroot=${NDK_SYSROOT}"
55
56III. Install perf
57-----------------------------------------------
58You need to connect to your Android device/emulator using adb.
59Install perf using:
60 adb push perf /data/perf
61
62If you also want to use perf-archive you need busybox tools for Android.
63For installing perf-archive, you first need to replace #!/bin/bash with #!/system/bin/sh:
64 sed 's/#!\/bin\/bash/#!\/system\/bin\/sh/g' perf-archive >> /tmp/perf-archive
65 chmod +x /tmp/perf-archive
66 adb push /tmp/perf-archive /data/perf-archive
67
68IV. Environment settings for running perf
69------------------------------------------------
70Some perf features need environment variables to run properly.
71You need to set these before running perf on the target:
72 adb shell
73 # PERF_PAGER=cat
74
75IV. Run perf
76------------------------------------------------
77Run perf on your device/emulator to which you previously connected using adb:
78 # ./data/perf
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index c8ffd9fd5c6a..5ad07ef417f0 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -61,11 +61,13 @@ OPTIONS
61 61
62--stdio:: Use the stdio interface. 62--stdio:: Use the stdio interface.
63 63
64--tui:: Use the TUI interface Use of --tui requires a tty, if one is not 64--tui:: Use the TUI interface. Use of --tui requires a tty, if one is not
65 present, as when piping to other commands, the stdio interface is 65 present, as when piping to other commands, the stdio interface is
66 used. This interfaces starts by centering on the line with more 66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples. 67 samples, TAB/UNTAB cycles through the lines with more samples.
68 68
69--gtk:: Use the GTK interface.
70
69-C:: 71-C::
70--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can 72--cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can
71 be provided as a comma-separated list with no space: 0,1. Ranges of 73 be provided as a comma-separated list with no space: 0,1. Ranges of
@@ -88,6 +90,9 @@ OPTIONS
88--objdump=<path>:: 90--objdump=<path>::
89 Path to objdump binary. 91 Path to objdump binary.
90 92
93--skip-missing::
94 Skip symbols that cannot be annotated.
95
91SEE ALSO 96SEE ALSO
92-------- 97--------
93linkperf:perf-record[1], linkperf:perf-report[1] 98linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
index c1057701a7dc..e9a8349a7172 100644
--- a/tools/perf/Documentation/perf-buildid-cache.txt
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -24,6 +24,13 @@ OPTIONS
24-r:: 24-r::
25--remove=:: 25--remove=::
26 Remove specified file from the cache. 26 Remove specified file from the cache.
27-M::
28--missing=::
29 List missing build ids in the cache for the specified file.
30-u::
31--update::
32 Update specified file of the cache. It can be used to update kallsyms
33 kernel dso to vmlinux in order to support annotation.
27-v:: 34-v::
28--verbose:: 35--verbose::
29 Be more verbose. 36 Be more verbose.
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index ab7f667de1b1..5b3123d5721f 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -22,10 +22,6 @@ specified perf.data files.
22 22
23OPTIONS 23OPTIONS
24------- 24-------
25-M::
26--displacement::
27 Show position displacement relative to baseline.
28
29-D:: 25-D::
30--dump-raw-trace:: 26--dump-raw-trace::
31 Dump raw trace in ASCII. 27 Dump raw trace in ASCII.
@@ -72,6 +68,66 @@ OPTIONS
72--symfs=<directory>:: 68--symfs=<directory>::
73 Look for files with symbols relative to this directory. 69 Look for files with symbols relative to this directory.
74 70
71-b::
72--baseline-only::
73 Show only items with match in baseline.
74
75-c::
76--compute::
77 Differential computation selection - delta,ratio,wdiff (default is delta).
78 If '+' is specified as a first character, the output is sorted based
79 on the computation results.
80 See COMPARISON METHODS section for more info.
81
82-p::
83--period::
84 Show period values for both compared hist entries.
85
86-F::
87--formula::
88 Show formula for given computation.
89
90COMPARISON METHODS
91------------------
92delta
93~~~~~
94If specified the 'Delta' column is displayed with value 'd' computed as:
95
96 d = A->period_percent - B->period_percent
97
98with:
99 - A/B being matching hist entry from first/second file specified
100 (or perf.data/perf.data.old) respectively.
101
102 - period_percent being the % of the hist entry period value within
103 single data file
104
105ratio
106~~~~~
107If specified the 'Ratio' column is displayed with value 'r' computed as:
108
109 r = A->period / B->period
110
111with:
112 - A/B being matching hist entry from first/second file specified
113 (or perf.data/perf.data.old) respectively.
114
115 - period being the hist entry period value
116
117wdiff
118~~~~~
119If specified the 'Weighted diff' column is displayed with value 'd' computed as:
120
121 d = B->period * WEIGHT-A - A->period * WEIGHT-B
122
123 - A/B being matching hist entry from first/second file specified
124 (or perf.data/perf.data.old) respectively.
125
126 - period being the hist entry period value
127
128 - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
129 behind ':' separator like '-c wdiff:1,2'.
130
75SEE ALSO 131SEE ALSO
76-------- 132--------
77linkperf:perf-record[1] 133linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 15217345c2fa..1ceb3700ffbb 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -28,6 +28,10 @@ OPTIONS
28--verbose=:: 28--verbose=::
29 Show all fields. 29 Show all fields.
30 30
31-g::
32--group::
33 Show event group information.
34
31SEE ALSO 35SEE ALSO
32-------- 36--------
33linkperf:perf-record[1], linkperf:perf-list[1], 37linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index 025630d43cd2..a00a34276c54 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -29,6 +29,17 @@ OPTIONS
29-v:: 29-v::
30--verbose:: 30--verbose::
31 Be more verbose. 31 Be more verbose.
32-i::
33--input=::
34 Input file name. (default: stdin)
35-o::
36--output=::
37 Output file name. (default: stdout)
38-s::
39--sched-stat::
40 Merge sched_stat and sched_switch for getting events where and how long
41 tasks slept. sched_switch contains a callchain where a task slept and
42 sched_stat contains a timeslice how long a task slept.
32 43
33SEE ALSO 44SEE ALSO
34-------- 45--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index b38a1f9ad460..938e8904f64d 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -175,7 +175,7 @@ following filters are defined:
175 175
176+ 176+
177The option requires at least one branch type among any, any_call, any_ret, ind_call. 177The option requires at least one branch type among any, any_call, any_ret, ind_call.
178The privilege levels may be ommitted, in which case, the privilege levels of the associated 178The privilege levels may be omitted, in which case, the privilege levels of the associated
179event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege 179event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
180levels are subject to permissions. When sampling on multiple events, branch stack sampling 180levels are subject to permissions. When sampling on multiple events, branch stack sampling
181is enabled for all the sampling events. The sampled branch type is the same for all events. 181is enabled for all the sampling events. The sampled branch type is the same for all events.
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index f4d91bebd59d..02284a0067f0 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -57,11 +57,44 @@ OPTIONS
57 57
58-s:: 58-s::
59--sort=:: 59--sort=::
60 Sort by key(s): pid, comm, dso, symbol, parent, srcline. 60 Sort histogram entries by given key(s) - multiple keys can be specified
61 in CSV format. Following sort keys are available:
62 pid, comm, dso, symbol, parent, cpu, srcline.
63
64 Each key has following meaning:
65
66 - comm: command (name) of the task which can be read via /proc/<pid>/comm
67 - pid: command and tid of the task
68 - dso: name of library or module executed at the time of sample
69 - symbol: name of function executed at the time of sample
70 - parent: name of function matched to the parent regex filter. Unmatched
71 entries are displayed as "[other]".
72 - cpu: cpu number the task ran at the time of sample
73 - srcline: filename and line number executed at the time of sample. The
74 DWARF debuggin info must be provided.
75
76 By default, comm, dso and symbol keys are used.
77 (i.e. --sort comm,dso,symbol)
78
79 If --branch-stack option is used, following sort keys are also
80 available:
81 dso_from, dso_to, symbol_from, symbol_to, mispredict.
82
83 - dso_from: name of library or module branched from
84 - dso_to: name of library or module branched to
85 - symbol_from: name of function branched from
86 - symbol_to: name of function branched to
87 - mispredict: "N" for predicted branch, "Y" for mispredicted branch
88
89 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
90 and symbol_to, see '--branch-stack'.
61 91
62-p:: 92-p::
63--parent=<regex>:: 93--parent=<regex>::
64 regex filter to identify parent, see: '--sort parent' 94 A regex filter to identify parent. The parent is a caller of this
95 function and searched through the callchain, thus it requires callchain
96 information recorded. The pattern is in the exteneded regex format and
97 defaults to "\^sys_|^do_page_fault", see '--sort parent'.
65 98
66-x:: 99-x::
67--exclude-other:: 100--exclude-other::
@@ -74,7 +107,6 @@ OPTIONS
74 107
75-t:: 108-t::
76--field-separator=:: 109--field-separator=::
77
78 Use a special separator character and don't pad with spaces, replacing 110 Use a special separator character and don't pad with spaces, replacing
79 all occurrences of this separator in symbol names (and other output) 111 all occurrences of this separator in symbol names (and other output)
80 with a '.' character, that thus it's the only non valid separator. 112 with a '.' character, that thus it's the only non valid separator.
@@ -171,6 +203,9 @@ OPTIONS
171--objdump=<path>:: 203--objdump=<path>::
172 Path to objdump binary. 204 Path to objdump binary.
173 205
206--group::
207 Show event group information together.
208
174SEE ALSO 209SEE ALSO
175-------- 210--------
176linkperf:perf-stat[1], linkperf:perf-annotate[1] 211linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
index a4027f221a53..9f1f054b8432 100644
--- a/tools/perf/Documentation/perf-script-python.txt
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -336,7 +336,6 @@ scripts listed by the 'perf script -l' command e.g.:
336---- 336----
337root@tropicana:~# perf script -l 337root@tropicana:~# perf script -l
338List of available trace scripts: 338List of available trace scripts:
339 workqueue-stats workqueue stats (ins/exe/create/destroy)
340 wakeup-latency system-wide min/max/avg wakeup latency 339 wakeup-latency system-wide min/max/avg wakeup latency
341 rw-by-file <comm> r/w activity for a program, by file 340 rw-by-file <comm> r/w activity for a program, by file
342 rw-by-pid system-wide r/w activity 341 rw-by-pid system-wide r/w activity
@@ -402,7 +401,6 @@ should show a new entry for your script:
402---- 401----
403root@tropicana:~# perf script -l 402root@tropicana:~# perf script -l
404List of available trace scripts: 403List of available trace scripts:
405 workqueue-stats workqueue stats (ins/exe/create/destroy)
406 wakeup-latency system-wide min/max/avg wakeup latency 404 wakeup-latency system-wide min/max/avg wakeup latency
407 rw-by-file <comm> r/w activity for a program, by file 405 rw-by-file <comm> r/w activity for a program, by file
408 rw-by-pid system-wide r/w activity 406 rw-by-pid system-wide r/w activity
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 2fa173b51970..faf4f4feebcc 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -108,7 +108,23 @@ with it. --append may be used here. Examples:
108 3>results perf stat --log-fd 3 -- $cmd 108 3>results perf stat --log-fd 3 -- $cmd
109 3>>results perf stat --log-fd 3 --append -- $cmd 109 3>>results perf stat --log-fd 3 --append -- $cmd
110 110
111 111--pre::
112--post::
113 Pre and post measurement hooks, e.g.:
114
115perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage
116
117-I msecs::
118--interval-print msecs::
119 Print count deltas every N milliseconds (minimum: 100ms)
120 example: perf stat -I 1000 -e cycles -a sleep 5
121
122--aggr-socket::
123Aggregate counts per processor socket for system-wide mode measurements. This
124is a useful mode to detect imbalance between sockets. To enable this mode,
125use --aggr-socket in addition to -a. (system-wide). The output includes the
126socket number and the number of online processors on that socket. This is
127useful to gauge the amount of aggregation.
112 128
113EXAMPLES 129EXAMPLES
114-------- 130--------
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index b24ac40fcd58..d1d3e5121f89 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -23,6 +23,10 @@ from 'perf test list'.
23 23
24OPTIONS 24OPTIONS
25------- 25-------
26-s::
27--skip::
28 Tests to skip (comma separater numeric list).
29
26-v:: 30-v::
27--verbose:: 31--verbose::
28 Be more verbose. 32 Be more verbose.
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 5b80d84d6b4a..a414bc95fd52 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -60,7 +60,7 @@ Default is to monitor all CPUS.
60 60
61-i:: 61-i::
62--inherit:: 62--inherit::
63 Child tasks inherit counters, only makes sens with -p option. 63 Child tasks do not inherit counters.
64 64
65-k <path>:: 65-k <path>::
66--vmlinux=<path>:: 66--vmlinux=<path>::
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 3a2ae37310a9..68718ccdd178 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -48,6 +48,12 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
48In per-thread mode with inheritance mode on (default), Events are captured only when 48In per-thread mode with inheritance mode on (default), Events are captured only when
49the thread executes on the designated CPUs. Default is to monitor all CPUs. 49the thread executes on the designated CPUs. Default is to monitor all CPUs.
50 50
51--duration:
52 Show only events that had a duration greater than N.M ms.
53
54--sched:
55 Accrue thread runtime and provide a summary at the end of the session.
56
51SEE ALSO 57SEE ALSO
52-------- 58--------
53linkperf:perf-record[1], linkperf:perf-script[1] 59linkperf:perf-record[1], linkperf:perf-script[1]
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 80db3f4bcf7a..39d41068484f 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -11,11 +11,21 @@ lib/rbtree.c
11include/linux/swab.h 11include/linux/swab.h
12arch/*/include/asm/unistd*.h 12arch/*/include/asm/unistd*.h
13arch/*/include/asm/perf_regs.h 13arch/*/include/asm/perf_regs.h
14arch/*/include/uapi/asm/unistd*.h
15arch/*/include/uapi/asm/perf_regs.h
14arch/*/lib/memcpy*.S 16arch/*/lib/memcpy*.S
15arch/*/lib/memset*.S 17arch/*/lib/memset*.S
16include/linux/poison.h 18include/linux/poison.h
17include/linux/magic.h 19include/linux/magic.h
18include/linux/hw_breakpoint.h 20include/linux/hw_breakpoint.h
21include/linux/rbtree_augmented.h
22include/uapi/linux/perf_event.h
23include/uapi/linux/const.h
24include/uapi/linux/swab.h
25include/uapi/linux/hw_breakpoint.h
19arch/x86/include/asm/svm.h 26arch/x86/include/asm/svm.h
20arch/x86/include/asm/vmx.h 27arch/x86/include/asm/vmx.h
21arch/x86/include/asm/kvm_host.h 28arch/x86/include/asm/kvm_host.h
29arch/x86/include/uapi/asm/svm.h
30arch/x86/include/uapi/asm/vmx.h
31arch/x86/include/uapi/asm/kvm.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 00deed4d6159..a2108ca1cc17 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -47,10 +47,11 @@ include config/utilities.mak
47# backtrace post unwind. 47# backtrace post unwind.
48# 48#
49# Define NO_BACKTRACE if you do not want stack backtrace debug feature 49# Define NO_BACKTRACE if you do not want stack backtrace debug feature
50#
51# Define NO_LIBNUMA if you do not want numa perf benchmark
50 52
51$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 53$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
52 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) 54 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
53-include $(OUTPUT)PERF-VERSION-FILE
54 55
55uname_M := $(shell uname -m 2>/dev/null || echo not) 56uname_M := $(shell uname -m 2>/dev/null || echo not)
56 57
@@ -58,7 +59,7 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
58 -e s/arm.*/arm/ -e s/sa110/arm/ \ 59 -e s/arm.*/arm/ -e s/sa110/arm/ \
59 -e s/s390x/s390/ -e s/parisc64/parisc/ \ 60 -e s/s390x/s390/ -e s/parisc64/parisc/ \
60 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ 61 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
61 -e s/sh[234].*/sh/ ) 62 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )
62NO_PERF_REGS := 1 63NO_PERF_REGS := 1
63 64
64CC = $(CROSS_COMPILE)gcc 65CC = $(CROSS_COMPILE)gcc
@@ -148,30 +149,79 @@ RM = rm -f
148MKDIR = mkdir 149MKDIR = mkdir
149FIND = find 150FIND = find
150INSTALL = install 151INSTALL = install
152FLEX = flex
153BISON= bison
151 154
152# sparse is architecture-neutral, which means that we need to tell it 155# sparse is architecture-neutral, which means that we need to tell it
153# explicitly what architecture to check for. Fix this up for yours.. 156# explicitly what architecture to check for. Fix this up for yours..
154SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ 157SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__
155 158
159ifneq ($(MAKECMDGOALS),clean)
160ifneq ($(MAKECMDGOALS),tags)
156-include config/feature-tests.mak 161-include config/feature-tests.mak
157 162
158ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) 163ifeq ($(call get-executable,$(FLEX)),)
164 dummy := $(error Error: $(FLEX) is missing on this system, please install it)
165endif
166
167ifeq ($(call get-executable,$(BISON)),)
168 dummy := $(error Error: $(BISON) is missing on this system, please install it)
169endif
170
171ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
159 CFLAGS := $(CFLAGS) -fstack-protector-all 172 CFLAGS := $(CFLAGS) -fstack-protector-all
160endif 173endif
161 174
162ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wstack-protector),y) 175ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wstack-protector,-Wstack-protector),y)
163 CFLAGS := $(CFLAGS) -Wstack-protector 176 CFLAGS := $(CFLAGS) -Wstack-protector
164endif 177endif
165 178
166ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -Wvolatile-register-var),y) 179ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -Wvolatile-register-var,-Wvolatile-register-var),y)
167 CFLAGS := $(CFLAGS) -Wvolatile-register-var 180 CFLAGS := $(CFLAGS) -Wvolatile-register-var
168endif 181endif
169 182
170### --- END CONFIGURATION SECTION --- 183### --- END CONFIGURATION SECTION ---
171 184
172BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 185ifeq ($(srctree),)
186srctree := $(patsubst %/,%,$(dir $(shell pwd)))
187srctree := $(patsubst %/,%,$(dir $(srctree)))
188#$(info Determined 'srctree' to be $(srctree))
189endif
190
191ifneq ($(objtree),)
192#$(info Determined 'objtree' to be $(objtree))
193endif
194
195ifneq ($(OUTPUT),)
196#$(info Determined 'OUTPUT' to be $(OUTPUT))
197endif
198
199BASIC_CFLAGS = \
200 -Iutil/include \
201 -Iarch/$(ARCH)/include \
202 $(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \
203 -I$(srctree)/arch/$(ARCH)/include/uapi \
204 -I$(srctree)/arch/$(ARCH)/include \
205 $(if $(objtree),-I$(objtree)/include/generated/uapi) \
206 -I$(srctree)/include/uapi \
207 -I$(srctree)/include \
208 -I$(OUTPUT)util \
209 -Iutil \
210 -I. \
211 -I$(TRACE_EVENT_DIR) \
212 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
213
173BASIC_LDFLAGS = 214BASIC_LDFLAGS =
174 215
216ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)
217 BIONIC := 1
218 EXTLIBS := $(filter-out -lrt,$(EXTLIBS))
219 EXTLIBS := $(filter-out -lpthread,$(EXTLIBS))
220 BASIC_CFLAGS += -I.
221endif
222endif # MAKECMDGOALS != tags
223endif # MAKECMDGOALS != clean
224
175# Guard against environment variables 225# Guard against environment variables
176BUILTIN_OBJS = 226BUILTIN_OBJS =
177LIB_H = 227LIB_H =
@@ -195,11 +245,19 @@ endif
195LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 245LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
196TE_LIB := -L$(TE_PATH) -ltraceevent 246TE_LIB := -L$(TE_PATH) -ltraceevent
197 247
248export LIBTRACEEVENT
249
250# python extension build directories
251PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
252PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
253PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
254export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
255
256python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
257
198PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) 258PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources)
199PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py 259PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py
200 260
201export LIBTRACEEVENT
202
203$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) 261$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
204 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \ 262 $(QUIET_GEN)CFLAGS='$(BASIC_CFLAGS)' $(PYTHON_WORD) util/setup.py \
205 --quiet build_ext; \ 263 --quiet build_ext; \
@@ -234,20 +292,17 @@ endif
234 292
235export PERL_PATH 293export PERL_PATH
236 294
237FLEX = flex
238BISON= bison
239
240$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c 295$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
241 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c 296 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
242 297
243$(OUTPUT)util/parse-events-bison.c: util/parse-events.y 298$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
244 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c 299 $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c -p parse_events_
245 300
246$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c 301$(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
247 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c 302 $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
248 303
249$(OUTPUT)util/pmu-bison.c: util/pmu.y 304$(OUTPUT)util/pmu-bison.c: util/pmu.y
250 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c 305 $(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -p perf_pmu_
251 306
252$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c 307$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
253$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c 308$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
@@ -303,6 +358,7 @@ LIB_H += util/evlist.h
303LIB_H += util/exec_cmd.h 358LIB_H += util/exec_cmd.h
304LIB_H += util/types.h 359LIB_H += util/types.h
305LIB_H += util/levenshtein.h 360LIB_H += util/levenshtein.h
361LIB_H += util/machine.h
306LIB_H += util/map.h 362LIB_H += util/map.h
307LIB_H += util/parse-options.h 363LIB_H += util/parse-options.h
308LIB_H += util/parse-events.h 364LIB_H += util/parse-events.h
@@ -319,6 +375,7 @@ LIB_H += util/svghelper.h
319LIB_H += util/tool.h 375LIB_H += util/tool.h
320LIB_H += util/run-command.h 376LIB_H += util/run-command.h
321LIB_H += util/sigchain.h 377LIB_H += util/sigchain.h
378LIB_H += util/dso.h
322LIB_H += util/symbol.h 379LIB_H += util/symbol.h
323LIB_H += util/color.h 380LIB_H += util/color.h
324LIB_H += util/values.h 381LIB_H += util/values.h
@@ -341,8 +398,11 @@ LIB_H += util/rblist.h
341LIB_H += util/intlist.h 398LIB_H += util/intlist.h
342LIB_H += util/perf_regs.h 399LIB_H += util/perf_regs.h
343LIB_H += util/unwind.h 400LIB_H += util/unwind.h
344LIB_H += ui/helpline.h
345LIB_H += util/vdso.h 401LIB_H += util/vdso.h
402LIB_H += ui/helpline.h
403LIB_H += ui/progress.h
404LIB_H += ui/util.h
405LIB_H += ui/ui.h
346 406
347LIB_OBJS += $(OUTPUT)util/abspath.o 407LIB_OBJS += $(OUTPUT)util/abspath.o
348LIB_OBJS += $(OUTPUT)util/alias.o 408LIB_OBJS += $(OUTPUT)util/alias.o
@@ -362,7 +422,6 @@ LIB_OBJS += $(OUTPUT)util/help.o
362LIB_OBJS += $(OUTPUT)util/levenshtein.o 422LIB_OBJS += $(OUTPUT)util/levenshtein.o
363LIB_OBJS += $(OUTPUT)util/parse-options.o 423LIB_OBJS += $(OUTPUT)util/parse-options.o
364LIB_OBJS += $(OUTPUT)util/parse-events.o 424LIB_OBJS += $(OUTPUT)util/parse-events.o
365LIB_OBJS += $(OUTPUT)util/parse-events-test.o
366LIB_OBJS += $(OUTPUT)util/path.o 425LIB_OBJS += $(OUTPUT)util/path.o
367LIB_OBJS += $(OUTPUT)util/rbtree.o 426LIB_OBJS += $(OUTPUT)util/rbtree.o
368LIB_OBJS += $(OUTPUT)util/bitmap.o 427LIB_OBJS += $(OUTPUT)util/bitmap.o
@@ -377,15 +436,16 @@ LIB_OBJS += $(OUTPUT)util/top.o
377LIB_OBJS += $(OUTPUT)util/usage.o 436LIB_OBJS += $(OUTPUT)util/usage.o
378LIB_OBJS += $(OUTPUT)util/wrapper.o 437LIB_OBJS += $(OUTPUT)util/wrapper.o
379LIB_OBJS += $(OUTPUT)util/sigchain.o 438LIB_OBJS += $(OUTPUT)util/sigchain.o
439LIB_OBJS += $(OUTPUT)util/dso.o
380LIB_OBJS += $(OUTPUT)util/symbol.o 440LIB_OBJS += $(OUTPUT)util/symbol.o
381LIB_OBJS += $(OUTPUT)util/symbol-elf.o 441LIB_OBJS += $(OUTPUT)util/symbol-elf.o
382LIB_OBJS += $(OUTPUT)util/dso-test-data.o
383LIB_OBJS += $(OUTPUT)util/color.o 442LIB_OBJS += $(OUTPUT)util/color.o
384LIB_OBJS += $(OUTPUT)util/pager.o 443LIB_OBJS += $(OUTPUT)util/pager.o
385LIB_OBJS += $(OUTPUT)util/header.o 444LIB_OBJS += $(OUTPUT)util/header.o
386LIB_OBJS += $(OUTPUT)util/callchain.o 445LIB_OBJS += $(OUTPUT)util/callchain.o
387LIB_OBJS += $(OUTPUT)util/values.o 446LIB_OBJS += $(OUTPUT)util/values.o
388LIB_OBJS += $(OUTPUT)util/debug.o 447LIB_OBJS += $(OUTPUT)util/debug.o
448LIB_OBJS += $(OUTPUT)util/machine.o
389LIB_OBJS += $(OUTPUT)util/map.o 449LIB_OBJS += $(OUTPUT)util/map.o
390LIB_OBJS += $(OUTPUT)util/pstack.o 450LIB_OBJS += $(OUTPUT)util/pstack.o
391LIB_OBJS += $(OUTPUT)util/session.o 451LIB_OBJS += $(OUTPUT)util/session.o
@@ -413,10 +473,31 @@ LIB_OBJS += $(OUTPUT)util/intlist.o
413LIB_OBJS += $(OUTPUT)util/vdso.o 473LIB_OBJS += $(OUTPUT)util/vdso.o
414LIB_OBJS += $(OUTPUT)util/stat.o 474LIB_OBJS += $(OUTPUT)util/stat.o
415 475
476LIB_OBJS += $(OUTPUT)ui/setup.o
416LIB_OBJS += $(OUTPUT)ui/helpline.o 477LIB_OBJS += $(OUTPUT)ui/helpline.o
478LIB_OBJS += $(OUTPUT)ui/progress.o
479LIB_OBJS += $(OUTPUT)ui/util.o
417LIB_OBJS += $(OUTPUT)ui/hist.o 480LIB_OBJS += $(OUTPUT)ui/hist.o
418LIB_OBJS += $(OUTPUT)ui/stdio/hist.o 481LIB_OBJS += $(OUTPUT)ui/stdio/hist.o
419 482
483LIB_OBJS += $(OUTPUT)arch/common.o
484
485LIB_OBJS += $(OUTPUT)tests/parse-events.o
486LIB_OBJS += $(OUTPUT)tests/dso-data.o
487LIB_OBJS += $(OUTPUT)tests/attr.o
488LIB_OBJS += $(OUTPUT)tests/vmlinux-kallsyms.o
489LIB_OBJS += $(OUTPUT)tests/open-syscall.o
490LIB_OBJS += $(OUTPUT)tests/open-syscall-all-cpus.o
491LIB_OBJS += $(OUTPUT)tests/open-syscall-tp-fields.o
492LIB_OBJS += $(OUTPUT)tests/mmap-basic.o
493LIB_OBJS += $(OUTPUT)tests/perf-record.o
494LIB_OBJS += $(OUTPUT)tests/rdpmc.o
495LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o
496LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o
497LIB_OBJS += $(OUTPUT)tests/pmu.o
498LIB_OBJS += $(OUTPUT)tests/hists_link.o
499LIB_OBJS += $(OUTPUT)tests/python-use.o
500
420BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o 501BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
421BUILTIN_OBJS += $(OUTPUT)builtin-bench.o 502BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
422# Benchmark modules 503# Benchmark modules
@@ -446,46 +527,65 @@ BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
446BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o 527BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
447BUILTIN_OBJS += $(OUTPUT)builtin-lock.o 528BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
448BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o 529BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
449BUILTIN_OBJS += $(OUTPUT)builtin-test.o
450BUILTIN_OBJS += $(OUTPUT)builtin-inject.o 530BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
531BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o
451 532
452PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) 533PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
453 534
454# 535#
455# Platform specific tweaks 536# Platform specific tweaks
456# 537#
538ifneq ($(MAKECMDGOALS),clean)
539ifneq ($(MAKECMDGOALS),tags)
457 540
458# We choose to avoid "if .. else if .. else .. endif endif" 541# We choose to avoid "if .. else if .. else .. endif endif"
459# because maintaining the nesting to match is a pain. If 542# because maintaining the nesting to match is a pain. If
460# we had "elif" things would have been much nicer... 543# we had "elif" things would have been much nicer...
461 544
462-include config.mak.autogen
463-include config.mak
464
465ifdef NO_LIBELF 545ifdef NO_LIBELF
466 NO_DWARF := 1 546 NO_DWARF := 1
467 NO_DEMANGLE := 1 547 NO_DEMANGLE := 1
468 NO_LIBUNWIND := 1 548 NO_LIBUNWIND := 1
469else 549else
470FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) 550FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
471ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y) 551ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF),libelf),y)
472 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS) 552 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
473 ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y) 553 ifeq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC),glibc),y)
474 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); 554 LIBC_SUPPORT := 1
475 else 555 endif
556 ifeq ($(BIONIC),1)
557 LIBC_SUPPORT := 1
558 endif
559 ifeq ($(LIBC_SUPPORT),1)
560 msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev);
561
476 NO_LIBELF := 1 562 NO_LIBELF := 1
477 NO_DWARF := 1 563 NO_DWARF := 1
478 NO_DEMANGLE := 1 564 NO_DEMANGLE := 1
565 else
566 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
479 endif 567 endif
480else 568else
481 FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS) 569 # for linking with debug library, run like:
482 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y) 570 # make DEBUG=1 LIBDW_DIR=/opt/libdw/
571 ifdef LIBDW_DIR
572 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
573 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
574 endif
575
576 FLAGS_DWARF=$(ALL_CFLAGS) $(LIBDW_CFLAGS) -ldw -lelf $(LIBDW_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
577 ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF),libdw),y)
483 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); 578 msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev);
484 NO_DWARF := 1 579 NO_DWARF := 1
485 endif # Dwarf support 580 endif # Dwarf support
486endif # SOURCE_LIBELF 581endif # SOURCE_LIBELF
487endif # NO_LIBELF 582endif # NO_LIBELF
488 583
584# There's only x86 (both 32 and 64) support for CFI unwind so far
585ifneq ($(ARCH),x86)
586 NO_LIBUNWIND := 1
587endif
588
489ifndef NO_LIBUNWIND 589ifndef NO_LIBUNWIND
490# for linking with debug library, run like: 590# for linking with debug library, run like:
491# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ 591# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
@@ -495,7 +595,7 @@ ifdef LIBUNWIND_DIR
495endif 595endif
496 596
497FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS) 597FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS)
498ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND)),y) 598ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
499 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99); 599 msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99);
500 NO_LIBUNWIND := 1 600 NO_LIBUNWIND := 1
501endif # Libunwind support 601endif # Libunwind support
@@ -524,7 +624,8 @@ LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
524else # NO_LIBELF 624else # NO_LIBELF
525BASIC_CFLAGS += -DLIBELF_SUPPORT 625BASIC_CFLAGS += -DLIBELF_SUPPORT
526 626
527ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) 627FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
628ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
528 BASIC_CFLAGS += -DLIBELF_MMAP 629 BASIC_CFLAGS += -DLIBELF_MMAP
529endif 630endif
530 631
@@ -532,7 +633,8 @@ ifndef NO_DWARF
532ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) 633ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
533 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); 634 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
534else 635else
535 BASIC_CFLAGS += -DDWARF_SUPPORT 636 BASIC_CFLAGS := -DDWARF_SUPPORT $(LIBDW_CFLAGS) $(BASIC_CFLAGS)
637 BASIC_LDFLAGS := $(LIBDW_LDFLAGS) $(BASIC_LDFLAGS)
536 EXTLIBS += -lelf -ldw 638 EXTLIBS += -lelf -ldw
537 LIB_OBJS += $(OUTPUT)util/probe-finder.o 639 LIB_OBJS += $(OUTPUT)util/probe-finder.o
538 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o 640 LIB_OBJS += $(OUTPUT)util/dwarf-aux.o
@@ -550,7 +652,7 @@ endif
550 652
551ifndef NO_LIBAUDIT 653ifndef NO_LIBAUDIT
552 FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit 654 FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
553 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y) 655 ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
554 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); 656 msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
555 else 657 else
556 BASIC_CFLAGS += -DLIBAUDIT_SUPPORT 658 BASIC_CFLAGS += -DLIBAUDIT_SUPPORT
@@ -561,53 +663,47 @@ endif
561 663
562ifndef NO_NEWT 664ifndef NO_NEWT
563 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt 665 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
564 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y) 666 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT),libnewt),y)
565 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); 667 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
566 else 668 else
567 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h 669 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
568 BASIC_CFLAGS += -I/usr/include/slang 670 BASIC_CFLAGS += -I/usr/include/slang
569 BASIC_CFLAGS += -DNEWT_SUPPORT 671 BASIC_CFLAGS += -DNEWT_SUPPORT
570 EXTLIBS += -lnewt -lslang 672 EXTLIBS += -lnewt -lslang
571 LIB_OBJS += $(OUTPUT)ui/setup.o
572 LIB_OBJS += $(OUTPUT)ui/browser.o 673 LIB_OBJS += $(OUTPUT)ui/browser.o
573 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o 674 LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
574 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o 675 LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
575 LIB_OBJS += $(OUTPUT)ui/browsers/map.o 676 LIB_OBJS += $(OUTPUT)ui/browsers/map.o
576 LIB_OBJS += $(OUTPUT)ui/progress.o 677 LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o
577 LIB_OBJS += $(OUTPUT)ui/util.o
578 LIB_OBJS += $(OUTPUT)ui/tui/setup.o 678 LIB_OBJS += $(OUTPUT)ui/tui/setup.o
579 LIB_OBJS += $(OUTPUT)ui/tui/util.o 679 LIB_OBJS += $(OUTPUT)ui/tui/util.o
580 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o 680 LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
681 LIB_OBJS += $(OUTPUT)ui/tui/progress.o
581 LIB_H += ui/browser.h 682 LIB_H += ui/browser.h
582 LIB_H += ui/browsers/map.h 683 LIB_H += ui/browsers/map.h
583 LIB_H += ui/keysyms.h 684 LIB_H += ui/keysyms.h
584 LIB_H += ui/libslang.h 685 LIB_H += ui/libslang.h
585 LIB_H += ui/progress.h
586 LIB_H += ui/util.h
587 LIB_H += ui/ui.h
588 endif 686 endif
589endif 687endif
590 688
591ifndef NO_GTK2 689ifndef NO_GTK2
592 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) 690 FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null)
593 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) 691 ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2),gtk2),y)
594 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); 692 msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev);
595 else 693 else
596 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2)),y) 694 ifeq ($(call try-cc,$(SOURCE_GTK2_INFOBAR),$(FLAGS_GTK2),-DHAVE_GTK_INFO_BAR),y)
597 BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR 695 BASIC_CFLAGS += -DHAVE_GTK_INFO_BAR
598 endif 696 endif
599 BASIC_CFLAGS += -DGTK2_SUPPORT 697 BASIC_CFLAGS += -DGTK2_SUPPORT
600 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) 698 BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null)
601 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null) 699 EXTLIBS += $(shell pkg-config --libs gtk+-2.0 2>/dev/null)
602 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o 700 LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
701 LIB_OBJS += $(OUTPUT)ui/gtk/hists.o
603 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o 702 LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
604 LIB_OBJS += $(OUTPUT)ui/gtk/util.o 703 LIB_OBJS += $(OUTPUT)ui/gtk/util.o
605 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o 704 LIB_OBJS += $(OUTPUT)ui/gtk/helpline.o
606 # Make sure that it'd be included only once. 705 LIB_OBJS += $(OUTPUT)ui/gtk/progress.o
607 ifeq ($(findstring -DNEWT_SUPPORT,$(BASIC_CFLAGS)),) 706 LIB_OBJS += $(OUTPUT)ui/gtk/annotate.o
608 LIB_OBJS += $(OUTPUT)ui/setup.o
609 LIB_OBJS += $(OUTPUT)ui/util.o
610 endif
611 endif 707 endif
612endif 708endif
613 709
@@ -620,7 +716,7 @@ else
620 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 716 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
621 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) 717 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
622 718
623 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y) 719 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED),perl),y)
624 BASIC_CFLAGS += -DNO_LIBPERL 720 BASIC_CFLAGS += -DNO_LIBPERL
625 else 721 else
626 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS) 722 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
@@ -634,7 +730,7 @@ disable-python = $(eval $(disable-python_code))
634define disable-python_code 730define disable-python_code
635 BASIC_CFLAGS += -DNO_LIBPYTHON 731 BASIC_CFLAGS += -DNO_LIBPYTHON
636 $(if $(1),$(warning No $(1) was found)) 732 $(if $(1),$(warning No $(1) was found))
637 $(warning Python support won't be built) 733 $(warning Python support will not be built)
638endef 734endef
639 735
640override PYTHON := \ 736override PYTHON := \
@@ -642,19 +738,10 @@ override PYTHON := \
642 738
643ifndef PYTHON 739ifndef PYTHON
644 $(call disable-python,python interpreter) 740 $(call disable-python,python interpreter)
645 python-clean :=
646else 741else
647 742
648 PYTHON_WORD := $(call shell-wordify,$(PYTHON)) 743 PYTHON_WORD := $(call shell-wordify,$(PYTHON))
649 744
650 # python extension build directories
651 PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
652 PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
653 PYTHON_EXTBUILD_TMP := $(PYTHON_EXTBUILD)tmp/
654 export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP
655
656 python-clean := rm -rf $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so
657
658 ifdef NO_LIBPYTHON 745 ifdef NO_LIBPYTHON
659 $(call disable-python) 746 $(call disable-python)
660 else 747 else
@@ -674,11 +761,11 @@ else
674 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 761 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
675 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 762 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
676 763
677 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) 764 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED),python),y)
678 $(call disable-python,Python.h (for Python 2.x)) 765 $(call disable-python,Python.h (for Python 2.x))
679 else 766 else
680 767
681 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED)),y) 768 ifneq ($(call try-cc,$(SOURCE_PYTHON_VERSION),$(FLAGS_PYTHON_EMBED),python version),y)
682 $(warning Python 3 is not yet supported; please set) 769 $(warning Python 3 is not yet supported; please set)
683 $(warning PYTHON and/or PYTHON_CONFIG appropriately.) 770 $(warning PYTHON and/or PYTHON_CONFIG appropriately.)
684 $(warning If you also have Python 2 installed, then) 771 $(warning If you also have Python 2 installed, then)
@@ -712,22 +799,22 @@ else
712 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 799 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
713 else 800 else
714 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd 801 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -DPACKAGE='perf' -lbfd
715 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD)) 802 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD),libbfd)
716 ifeq ($(has_bfd),y) 803 ifeq ($(has_bfd),y)
717 EXTLIBS += -lbfd 804 EXTLIBS += -lbfd
718 else 805 else
719 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty 806 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
720 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY)) 807 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY),liberty)
721 ifeq ($(has_bfd_iberty),y) 808 ifeq ($(has_bfd_iberty),y)
722 EXTLIBS += -lbfd -liberty 809 EXTLIBS += -lbfd -liberty
723 else 810 else
724 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz 811 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
725 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z)) 812 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z),libz)
726 ifeq ($(has_bfd_iberty_z),y) 813 ifeq ($(has_bfd_iberty_z),y)
727 EXTLIBS += -lbfd -liberty -lz 814 EXTLIBS += -lbfd -liberty -lz
728 else 815 else
729 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty 816 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
730 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE)) 817 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE),demangle)
731 ifeq ($(has_cplus_demangle),y) 818 ifeq ($(has_cplus_demangle),y)
732 EXTLIBS += -liberty 819 EXTLIBS += -liberty
733 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 820 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
@@ -749,21 +836,41 @@ ifeq ($(NO_PERF_REGS),0)
749endif 836endif
750 837
751ifndef NO_STRLCPY 838ifndef NO_STRLCPY
752 ifeq ($(call try-cc,$(SOURCE_STRLCPY),),y) 839 ifeq ($(call try-cc,$(SOURCE_STRLCPY),,-DHAVE_STRLCPY),y)
753 BASIC_CFLAGS += -DHAVE_STRLCPY 840 BASIC_CFLAGS += -DHAVE_STRLCPY
754 endif 841 endif
755endif 842endif
756 843
844ifndef NO_ON_EXIT
845 ifeq ($(call try-cc,$(SOURCE_ON_EXIT),,-DHAVE_ON_EXIT),y)
846 BASIC_CFLAGS += -DHAVE_ON_EXIT
847 endif
848endif
849
757ifndef NO_BACKTRACE 850ifndef NO_BACKTRACE
758 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),),y) 851 ifeq ($(call try-cc,$(SOURCE_BACKTRACE),,-DBACKTRACE_SUPPORT),y)
759 BASIC_CFLAGS += -DBACKTRACE_SUPPORT 852 BASIC_CFLAGS += -DBACKTRACE_SUPPORT
760 endif 853 endif
761endif 854endif
762 855
856ifndef NO_LIBNUMA
857 FLAGS_LIBNUMA = $(ALL_CFLAGS) $(ALL_LDFLAGS) -lnuma
858 ifneq ($(call try-cc,$(SOURCE_LIBNUMA),$(FLAGS_LIBNUMA),libnuma),y)
859 msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev);
860 else
861 BASIC_CFLAGS += -DLIBNUMA_SUPPORT
862 BUILTIN_OBJS += $(OUTPUT)bench/numa.o
863 EXTLIBS += -lnuma
864 endif
865endif
866
763ifdef ASCIIDOC8 867ifdef ASCIIDOC8
764 export ASCIIDOC8 868 export ASCIIDOC8
765endif 869endif
766 870
871endif # MAKECMDGOALS != tags
872endif # MAKECMDGOALS != clean
873
767# Shell quote (do not use $(call) to accommodate ancient setups); 874# Shell quote (do not use $(call) to accommodate ancient setups);
768 875
769ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) 876ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG))
@@ -805,7 +912,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf
805 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf 912 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf
806 913
807$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS 914$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
808 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 915 $(QUIET_CC)$(CC) -include $(OUTPUT)PERF-VERSION-FILE \
809 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 916 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
810 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ 917 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
811 918
@@ -864,10 +971,20 @@ $(OUTPUT)%.s: %.S
864$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS 971$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
865 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \ 972 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
866 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ 973 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
867 '-DBINDIR="$(bindir_relative_SQ)"' \
868 '-DPREFIX="$(prefix_SQ)"' \ 974 '-DPREFIX="$(prefix_SQ)"' \
869 $< 975 $<
870 976
977$(OUTPUT)tests/attr.o: tests/attr.c $(OUTPUT)PERF-CFLAGS
978 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
979 '-DBINDIR="$(bindir_SQ)"' -DPYTHON='"$(PYTHON_WORD)"' \
980 $<
981
982$(OUTPUT)tests/python-use.o: tests/python-use.c $(OUTPUT)PERF-CFLAGS
983 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
984 -DPYTHONPATH='"$(OUTPUT)python"' \
985 -DPYTHON='"$(PYTHON_WORD)"' \
986 $<
987
871$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS 988$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
872 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 989 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
873 990
@@ -883,6 +1000,9 @@ $(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
883$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS 1000$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
884 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< 1001 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
885 1002
1003$(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS
1004 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
1005
886$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS 1006$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
887 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 1007 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
888 1008
@@ -954,20 +1074,15 @@ help:
954 @echo 'Perf maintainer targets:' 1074 @echo 'Perf maintainer targets:'
955 @echo ' clean - clean all binary objects and build output' 1075 @echo ' clean - clean all binary objects and build output'
956 1076
957doc:
958 $(MAKE) -C Documentation all
959
960man:
961 $(MAKE) -C Documentation man
962 1077
963html: 1078DOC_TARGETS := doc man html info pdf
964 $(MAKE) -C Documentation html
965 1079
966info: 1080INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
967 $(MAKE) -C Documentation info 1081INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
968 1082
969pdf: 1083# 'make doc' should call 'make -C Documentation all'
970 $(MAKE) -C Documentation pdf 1084$(DOC_TARGETS):
1085 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
971 1086
972TAGS: 1087TAGS:
973 $(RM) TAGS 1088 $(RM) TAGS
@@ -1018,7 +1133,7 @@ perfexec_instdir = $(prefix)/$(perfexecdir)
1018endif 1133endif
1019perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 1134perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
1020 1135
1021install: all 1136install-bin: all
1022 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 1137 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1023 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' 1138 $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'
1024 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1139 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
@@ -1034,33 +1149,19 @@ install: all
1034 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' 1149 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1035 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d' 1150 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'
1036 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' 1151 $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
1152 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
1153 $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'
1154 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1155 $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
1156
1157install: install-bin try-install-man
1037 1158
1038install-python_ext: 1159install-python_ext:
1039 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' 1160 $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
1040 1161
1041install-doc: 1162# 'make install-doc' should call 'make -C Documentation install'
1042 $(MAKE) -C Documentation install 1163$(INSTALL_DOC_TARGETS):
1043 1164 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)
1044install-man:
1045 $(MAKE) -C Documentation install-man
1046
1047install-html:
1048 $(MAKE) -C Documentation install-html
1049
1050install-info:
1051 $(MAKE) -C Documentation install-info
1052
1053install-pdf:
1054 $(MAKE) -C Documentation install-pdf
1055
1056quick-install-doc:
1057 $(MAKE) -C Documentation quick-install
1058
1059quick-install-man:
1060 $(MAKE) -C Documentation quick-install-man
1061
1062quick-install-html:
1063 $(MAKE) -C Documentation quick-install-html
1064 1165
1065### Cleaning rules 1166### Cleaning rules
1066 1167
@@ -1068,7 +1169,7 @@ clean: $(LIBTRACEEVENT)-clean
1068 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) 1169 $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
1069 $(RM) $(ALL_PROGRAMS) perf 1170 $(RM) $(ALL_PROGRAMS) perf
1070 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* 1171 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1071 $(MAKE) -C Documentation/ clean 1172 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
1072 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS 1173 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
1073 $(RM) $(OUTPUT)util/*-bison* 1174 $(RM) $(OUTPUT)util/*-bison*
1074 $(RM) $(OUTPUT)util/*-flex* 1175 $(RM) $(OUTPUT)util/*-flex*
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c
new file mode 100644
index 000000000000..aacef07ebf31
--- /dev/null
+++ b/tools/perf/arch/common.c
@@ -0,0 +1,212 @@
1#include <stdio.h>
2#include <sys/utsname.h>
3#include "common.h"
4#include "../util/debug.h"
5
6const char *const arm_triplets[] = {
7 "arm-eabi-",
8 "arm-linux-androideabi-",
9 "arm-unknown-linux-",
10 "arm-unknown-linux-gnu-",
11 "arm-unknown-linux-gnueabi-",
12 NULL
13};
14
15const char *const powerpc_triplets[] = {
16 "powerpc-unknown-linux-gnu-",
17 "powerpc64-unknown-linux-gnu-",
18 NULL
19};
20
21const char *const s390_triplets[] = {
22 "s390-ibm-linux-",
23 NULL
24};
25
26const char *const sh_triplets[] = {
27 "sh-unknown-linux-gnu-",
28 "sh64-unknown-linux-gnu-",
29 NULL
30};
31
32const char *const sparc_triplets[] = {
33 "sparc-unknown-linux-gnu-",
34 "sparc64-unknown-linux-gnu-",
35 NULL
36};
37
38const char *const x86_triplets[] = {
39 "x86_64-pc-linux-gnu-",
40 "x86_64-unknown-linux-gnu-",
41 "i686-pc-linux-gnu-",
42 "i586-pc-linux-gnu-",
43 "i486-pc-linux-gnu-",
44 "i386-pc-linux-gnu-",
45 "i686-linux-android-",
46 "i686-android-linux-",
47 NULL
48};
49
50const char *const mips_triplets[] = {
51 "mips-unknown-linux-gnu-",
52 "mipsel-linux-android-",
53 NULL
54};
55
56static bool lookup_path(char *name)
57{
58 bool found = false;
59 char *path, *tmp;
60 char buf[PATH_MAX];
61 char *env = getenv("PATH");
62
63 if (!env)
64 return false;
65
66 env = strdup(env);
67 if (!env)
68 return false;
69
70 path = strtok_r(env, ":", &tmp);
71 while (path) {
72 scnprintf(buf, sizeof(buf), "%s/%s", path, name);
73 if (access(buf, F_OK) == 0) {
74 found = true;
75 break;
76 }
77 path = strtok_r(NULL, ":", &tmp);
78 }
79 free(env);
80 return found;
81}
82
83static int lookup_triplets(const char *const *triplets, const char *name)
84{
85 int i;
86 char buf[PATH_MAX];
87
88 for (i = 0; triplets[i] != NULL; i++) {
89 scnprintf(buf, sizeof(buf), "%s%s", triplets[i], name);
90 if (lookup_path(buf))
91 return i;
92 }
93 return -1;
94}
95
96/*
97 * Return architecture name in a normalized form.
98 * The conversion logic comes from the Makefile.
99 */
100static const char *normalize_arch(char *arch)
101{
102 if (!strcmp(arch, "x86_64"))
103 return "x86";
104 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6')
105 return "x86";
106 if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5))
107 return "sparc";
108 if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110"))
109 return "arm";
110 if (!strncmp(arch, "s390", 4))
111 return "s390";
112 if (!strncmp(arch, "parisc", 6))
113 return "parisc";
114 if (!strncmp(arch, "powerpc", 7) || !strncmp(arch, "ppc", 3))
115 return "powerpc";
116 if (!strncmp(arch, "mips", 4))
117 return "mips";
118 if (!strncmp(arch, "sh", 2) && isdigit(arch[2]))
119 return "sh";
120
121 return arch;
122}
123
124static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
125 const char *name,
126 const char **path)
127{
128 int idx;
129 const char *arch, *cross_env;
130 struct utsname uts;
131 const char *const *path_list;
132 char *buf = NULL;
133
134 arch = normalize_arch(env->arch);
135
136 if (uname(&uts) < 0)
137 goto out;
138
139 /*
140 * We don't need to try to find objdump path for native system.
141 * Just use default binutils path (e.g.: "objdump").
142 */
143 if (!strcmp(normalize_arch(uts.machine), arch))
144 goto out;
145
146 cross_env = getenv("CROSS_COMPILE");
147 if (cross_env) {
148 if (asprintf(&buf, "%s%s", cross_env, name) < 0)
149 goto out_error;
150 if (buf[0] == '/') {
151 if (access(buf, F_OK) == 0)
152 goto out;
153 goto out_error;
154 }
155 if (lookup_path(buf))
156 goto out;
157 free(buf);
158 buf = NULL;
159 }
160
161 if (!strcmp(arch, "arm"))
162 path_list = arm_triplets;
163 else if (!strcmp(arch, "powerpc"))
164 path_list = powerpc_triplets;
165 else if (!strcmp(arch, "sh"))
166 path_list = sh_triplets;
167 else if (!strcmp(arch, "s390"))
168 path_list = s390_triplets;
169 else if (!strcmp(arch, "sparc"))
170 path_list = sparc_triplets;
171 else if (!strcmp(arch, "x86"))
172 path_list = x86_triplets;
173 else if (!strcmp(arch, "mips"))
174 path_list = mips_triplets;
175 else {
176 ui__error("binutils for %s not supported.\n", arch);
177 goto out_error;
178 }
179
180 idx = lookup_triplets(path_list, name);
181 if (idx < 0) {
182 ui__error("Please install %s for %s.\n"
183 "You can add it to PATH, set CROSS_COMPILE or "
184 "override the default using --%s.\n",
185 name, arch, name);
186 goto out_error;
187 }
188
189 if (asprintf(&buf, "%s%s", path_list[idx], name) < 0)
190 goto out_error;
191
192out:
193 *path = buf;
194 return 0;
195out_error:
196 free(buf);
197 *path = NULL;
198 return -1;
199}
200
201int perf_session_env__lookup_objdump(struct perf_session_env *env)
202{
203 /*
204 * For live mode, env->arch will be NULL and we can use
205 * the native objdump tool.
206 */
207 if (env->arch == NULL)
208 return 0;
209
210 return perf_session_env__lookup_binutils_path(env, "objdump",
211 &objdump_path);
212}
diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h
new file mode 100644
index 000000000000..ede246eda9be
--- /dev/null
+++ b/tools/perf/arch/common.h
@@ -0,0 +1,10 @@
1#ifndef ARCH_PERF_COMMON_H
2#define ARCH_PERF_COMMON_H
3
4#include "../util/session.h"
5
6extern const char *objdump_path;
7
8int perf_session_env__lookup_objdump(struct perf_session_env *env);
9
10#endif /* ARCH_PERF_COMMON_H */
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index 46fc9f15c6b3..7fcdcdbee917 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -3,7 +3,7 @@
3 3
4#include <stdlib.h> 4#include <stdlib.h>
5#include "../../util/types.h" 5#include "../../util/types.h"
6#include "../../../../../arch/x86/include/asm/perf_regs.h" 6#include <asm/perf_regs.h>
7 7
8#ifndef ARCH_X86_64 8#ifndef ARCH_X86_64
9#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1) 9#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index 8f89998eeaf4..a5223e6a7b43 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -1,6 +1,7 @@
1#ifndef BENCH_H 1#ifndef BENCH_H
2#define BENCH_H 2#define BENCH_H
3 3
4extern int bench_numa(int argc, const char **argv, const char *prefix);
4extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); 5extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
5extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); 6extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
6extern int bench_mem_memcpy(int argc, const char **argv, 7extern int bench_mem_memcpy(int argc, const char **argv,
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
new file mode 100644
index 000000000000..30d1c3225b46
--- /dev/null
+++ b/tools/perf/bench/numa.c
@@ -0,0 +1,1731 @@
1/*
2 * numa.c
3 *
4 * numa: Simulate NUMA-sensitive workload and measure their NUMA performance
5 */
6
7#include "../perf.h"
8#include "../builtin.h"
9#include "../util/util.h"
10#include "../util/parse-options.h"
11
12#include "bench.h"
13
14#include <errno.h>
15#include <sched.h>
16#include <stdio.h>
17#include <assert.h>
18#include <malloc.h>
19#include <signal.h>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
23#include <pthread.h>
24#include <sys/mman.h>
25#include <sys/time.h>
26#include <sys/wait.h>
27#include <sys/prctl.h>
28#include <sys/types.h>
29
30#include <numa.h>
31#include <numaif.h>
32
33/*
34 * Regular printout to the terminal, supressed if -q is specified:
35 */
36#define tprintf(x...) do { if (g && g->p.show_details >= 0) printf(x); } while (0)
37
38/*
39 * Debug printf:
40 */
41#define dprintf(x...) do { if (g && g->p.show_details >= 1) printf(x); } while (0)
42
43struct thread_data {
44 int curr_cpu;
45 cpu_set_t bind_cpumask;
46 int bind_node;
47 u8 *process_data;
48 int process_nr;
49 int thread_nr;
50 int task_nr;
51 unsigned int loops_done;
52 u64 val;
53 u64 runtime_ns;
54 pthread_mutex_t *process_lock;
55};
56
57/* Parameters set by options: */
58
59struct params {
60 /* Startup synchronization: */
61 bool serialize_startup;
62
63 /* Task hierarchy: */
64 int nr_proc;
65 int nr_threads;
66
67 /* Working set sizes: */
68 const char *mb_global_str;
69 const char *mb_proc_str;
70 const char *mb_proc_locked_str;
71 const char *mb_thread_str;
72
73 double mb_global;
74 double mb_proc;
75 double mb_proc_locked;
76 double mb_thread;
77
78 /* Access patterns to the working set: */
79 bool data_reads;
80 bool data_writes;
81 bool data_backwards;
82 bool data_zero_memset;
83 bool data_rand_walk;
84 u32 nr_loops;
85 u32 nr_secs;
86 u32 sleep_usecs;
87
88 /* Working set initialization: */
89 bool init_zero;
90 bool init_random;
91 bool init_cpu0;
92
93 /* Misc options: */
94 int show_details;
95 int run_all;
96 int thp;
97
98 long bytes_global;
99 long bytes_process;
100 long bytes_process_locked;
101 long bytes_thread;
102
103 int nr_tasks;
104 bool show_quiet;
105
106 bool show_convergence;
107 bool measure_convergence;
108
109 int perturb_secs;
110 int nr_cpus;
111 int nr_nodes;
112
113 /* Affinity options -C and -N: */
114 char *cpu_list_str;
115 char *node_list_str;
116};
117
118
119/* Global, read-writable area, accessible to all processes and threads: */
120
121struct global_info {
122 u8 *data;
123
124 pthread_mutex_t startup_mutex;
125 int nr_tasks_started;
126
127 pthread_mutex_t startup_done_mutex;
128
129 pthread_mutex_t start_work_mutex;
130 int nr_tasks_working;
131
132 pthread_mutex_t stop_work_mutex;
133 u64 bytes_done;
134
135 struct thread_data *threads;
136
137 /* Convergence latency measurement: */
138 bool all_converged;
139 bool stop_work;
140
141 int print_once;
142
143 struct params p;
144};
145
146static struct global_info *g = NULL;
147
148static int parse_cpus_opt(const struct option *opt, const char *arg, int unset);
149static int parse_nodes_opt(const struct option *opt, const char *arg, int unset);
150
151struct params p0;
152
153static const struct option options[] = {
154 OPT_INTEGER('p', "nr_proc" , &p0.nr_proc, "number of processes"),
155 OPT_INTEGER('t', "nr_threads" , &p0.nr_threads, "number of threads per process"),
156
157 OPT_STRING('G', "mb_global" , &p0.mb_global_str, "MB", "global memory (MBs)"),
158 OPT_STRING('P', "mb_proc" , &p0.mb_proc_str, "MB", "process memory (MBs)"),
159 OPT_STRING('L', "mb_proc_locked", &p0.mb_proc_locked_str,"MB", "process serialized/locked memory access (MBs), <= process_memory"),
160 OPT_STRING('T', "mb_thread" , &p0.mb_thread_str, "MB", "thread memory (MBs)"),
161
162 OPT_UINTEGER('l', "nr_loops" , &p0.nr_loops, "max number of loops to run"),
163 OPT_UINTEGER('s', "nr_secs" , &p0.nr_secs, "max number of seconds to run"),
164 OPT_UINTEGER('u', "usleep" , &p0.sleep_usecs, "usecs to sleep per loop iteration"),
165
166 OPT_BOOLEAN('R', "data_reads" , &p0.data_reads, "access the data via writes (can be mixed with -W)"),
167 OPT_BOOLEAN('W', "data_writes" , &p0.data_writes, "access the data via writes (can be mixed with -R)"),
168 OPT_BOOLEAN('B', "data_backwards", &p0.data_backwards, "access the data backwards as well"),
169 OPT_BOOLEAN('Z', "data_zero_memset", &p0.data_zero_memset,"access the data via glibc bzero only"),
170 OPT_BOOLEAN('r', "data_rand_walk", &p0.data_rand_walk, "access the data with random (32bit LFSR) walk"),
171
172
173 OPT_BOOLEAN('z', "init_zero" , &p0.init_zero, "bzero the initial allocations"),
174 OPT_BOOLEAN('I', "init_random" , &p0.init_random, "randomize the contents of the initial allocations"),
175 OPT_BOOLEAN('0', "init_cpu0" , &p0.init_cpu0, "do the initial allocations on CPU#0"),
176 OPT_INTEGER('x', "perturb_secs", &p0.perturb_secs, "perturb thread 0/0 every X secs, to test convergence stability"),
177
178 OPT_INCR ('d', "show_details" , &p0.show_details, "Show details"),
179 OPT_INCR ('a', "all" , &p0.run_all, "Run all tests in the suite"),
180 OPT_INTEGER('H', "thp" , &p0.thp, "MADV_NOHUGEPAGE < 0 < MADV_HUGEPAGE"),
181 OPT_BOOLEAN('c', "show_convergence", &p0.show_convergence, "show convergence details"),
182 OPT_BOOLEAN('m', "measure_convergence", &p0.measure_convergence, "measure convergence latency"),
183 OPT_BOOLEAN('q', "quiet" , &p0.show_quiet, "bzero the initial allocations"),
184 OPT_BOOLEAN('S', "serialize-startup", &p0.serialize_startup,"serialize thread startup"),
185
186 /* Special option string parsing callbacks: */
187 OPT_CALLBACK('C', "cpus", NULL, "cpu[,cpu2,...cpuN]",
188 "bind the first N tasks to these specific cpus (the rest is unbound)",
189 parse_cpus_opt),
190 OPT_CALLBACK('M', "memnodes", NULL, "node[,node2,...nodeN]",
191 "bind the first N tasks to these specific memory nodes (the rest is unbound)",
192 parse_nodes_opt),
193 OPT_END()
194};
195
196static const char * const bench_numa_usage[] = {
197 "perf bench numa <options>",
198 NULL
199};
200
201static const char * const numa_usage[] = {
202 "perf bench numa mem [<options>]",
203 NULL
204};
205
206static cpu_set_t bind_to_cpu(int target_cpu)
207{
208 cpu_set_t orig_mask, mask;
209 int ret;
210
211 ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
212 BUG_ON(ret);
213
214 CPU_ZERO(&mask);
215
216 if (target_cpu == -1) {
217 int cpu;
218
219 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
220 CPU_SET(cpu, &mask);
221 } else {
222 BUG_ON(target_cpu < 0 || target_cpu >= g->p.nr_cpus);
223 CPU_SET(target_cpu, &mask);
224 }
225
226 ret = sched_setaffinity(0, sizeof(mask), &mask);
227 BUG_ON(ret);
228
229 return orig_mask;
230}
231
232static cpu_set_t bind_to_node(int target_node)
233{
234 int cpus_per_node = g->p.nr_cpus/g->p.nr_nodes;
235 cpu_set_t orig_mask, mask;
236 int cpu;
237 int ret;
238
239 BUG_ON(cpus_per_node*g->p.nr_nodes != g->p.nr_cpus);
240 BUG_ON(!cpus_per_node);
241
242 ret = sched_getaffinity(0, sizeof(orig_mask), &orig_mask);
243 BUG_ON(ret);
244
245 CPU_ZERO(&mask);
246
247 if (target_node == -1) {
248 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
249 CPU_SET(cpu, &mask);
250 } else {
251 int cpu_start = (target_node + 0) * cpus_per_node;
252 int cpu_stop = (target_node + 1) * cpus_per_node;
253
254 BUG_ON(cpu_stop > g->p.nr_cpus);
255
256 for (cpu = cpu_start; cpu < cpu_stop; cpu++)
257 CPU_SET(cpu, &mask);
258 }
259
260 ret = sched_setaffinity(0, sizeof(mask), &mask);
261 BUG_ON(ret);
262
263 return orig_mask;
264}
265
266static void bind_to_cpumask(cpu_set_t mask)
267{
268 int ret;
269
270 ret = sched_setaffinity(0, sizeof(mask), &mask);
271 BUG_ON(ret);
272}
273
274static void mempol_restore(void)
275{
276 int ret;
277
278 ret = set_mempolicy(MPOL_DEFAULT, NULL, g->p.nr_nodes-1);
279
280 BUG_ON(ret);
281}
282
283static void bind_to_memnode(int node)
284{
285 unsigned long nodemask;
286 int ret;
287
288 if (node == -1)
289 return;
290
291 BUG_ON(g->p.nr_nodes > (int)sizeof(nodemask));
292 nodemask = 1L << node;
293
294 ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)*8);
295 dprintf("binding to node %d, mask: %016lx => %d\n", node, nodemask, ret);
296
297 BUG_ON(ret);
298}
299
300#define HPSIZE (2*1024*1024)
301
302#define set_taskname(fmt...) \
303do { \
304 char name[20]; \
305 \
306 snprintf(name, 20, fmt); \
307 prctl(PR_SET_NAME, name); \
308} while (0)
309
310static u8 *alloc_data(ssize_t bytes0, int map_flags,
311 int init_zero, int init_cpu0, int thp, int init_random)
312{
313 cpu_set_t orig_mask;
314 ssize_t bytes;
315 u8 *buf;
316 int ret;
317
318 if (!bytes0)
319 return NULL;
320
321 /* Allocate and initialize all memory on CPU#0: */
322 if (init_cpu0) {
323 orig_mask = bind_to_node(0);
324 bind_to_memnode(0);
325 }
326
327 bytes = bytes0 + HPSIZE;
328
329 buf = (void *)mmap(0, bytes, PROT_READ|PROT_WRITE, MAP_ANON|map_flags, -1, 0);
330 BUG_ON(buf == (void *)-1);
331
332 if (map_flags == MAP_PRIVATE) {
333 if (thp > 0) {
334 ret = madvise(buf, bytes, MADV_HUGEPAGE);
335 if (ret && !g->print_once) {
336 g->print_once = 1;
337 printf("WARNING: Could not enable THP - do: 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled'\n");
338 }
339 }
340 if (thp < 0) {
341 ret = madvise(buf, bytes, MADV_NOHUGEPAGE);
342 if (ret && !g->print_once) {
343 g->print_once = 1;
344 printf("WARNING: Could not disable THP: run a CONFIG_TRANSPARENT_HUGEPAGE kernel?\n");
345 }
346 }
347 }
348
349 if (init_zero) {
350 bzero(buf, bytes);
351 } else {
352 /* Initialize random contents, different in each word: */
353 if (init_random) {
354 u64 *wbuf = (void *)buf;
355 long off = rand();
356 long i;
357
358 for (i = 0; i < bytes/8; i++)
359 wbuf[i] = i + off;
360 }
361 }
362
363 /* Align to 2MB boundary: */
364 buf = (void *)(((unsigned long)buf + HPSIZE-1) & ~(HPSIZE-1));
365
366 /* Restore affinity: */
367 if (init_cpu0) {
368 bind_to_cpumask(orig_mask);
369 mempol_restore();
370 }
371
372 return buf;
373}
374
375static void free_data(void *data, ssize_t bytes)
376{
377 int ret;
378
379 if (!data)
380 return;
381
382 ret = munmap(data, bytes);
383 BUG_ON(ret);
384}
385
386/*
387 * Create a shared memory buffer that can be shared between processes, zeroed:
388 */
389static void * zalloc_shared_data(ssize_t bytes)
390{
391 return alloc_data(bytes, MAP_SHARED, 1, g->p.init_cpu0, g->p.thp, g->p.init_random);
392}
393
394/*
395 * Create a shared memory buffer that can be shared between processes:
396 */
397static void * setup_shared_data(ssize_t bytes)
398{
399 return alloc_data(bytes, MAP_SHARED, 0, g->p.init_cpu0, g->p.thp, g->p.init_random);
400}
401
402/*
403 * Allocate process-local memory - this will either be shared between
404 * threads of this process, or only be accessed by this thread:
405 */
406static void * setup_private_data(ssize_t bytes)
407{
408 return alloc_data(bytes, MAP_PRIVATE, 0, g->p.init_cpu0, g->p.thp, g->p.init_random);
409}
410
411/*
412 * Return a process-shared (global) mutex:
413 */
414static void init_global_mutex(pthread_mutex_t *mutex)
415{
416 pthread_mutexattr_t attr;
417
418 pthread_mutexattr_init(&attr);
419 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
420 pthread_mutex_init(mutex, &attr);
421}
422
423static int parse_cpu_list(const char *arg)
424{
425 p0.cpu_list_str = strdup(arg);
426
427 dprintf("got CPU list: {%s}\n", p0.cpu_list_str);
428
429 return 0;
430}
431
432static void parse_setup_cpu_list(void)
433{
434 struct thread_data *td;
435 char *str0, *str;
436 int t;
437
438 if (!g->p.cpu_list_str)
439 return;
440
441 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
442
443 str0 = str = strdup(g->p.cpu_list_str);
444 t = 0;
445
446 BUG_ON(!str);
447
448 tprintf("# binding tasks to CPUs:\n");
449 tprintf("# ");
450
451 while (true) {
452 int bind_cpu, bind_cpu_0, bind_cpu_1;
453 char *tok, *tok_end, *tok_step, *tok_len, *tok_mul;
454 int bind_len;
455 int step;
456 int mul;
457
458 tok = strsep(&str, ",");
459 if (!tok)
460 break;
461
462 tok_end = strstr(tok, "-");
463
464 dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end);
465 if (!tok_end) {
466 /* Single CPU specified: */
467 bind_cpu_0 = bind_cpu_1 = atol(tok);
468 } else {
469 /* CPU range specified (for example: "5-11"): */
470 bind_cpu_0 = atol(tok);
471 bind_cpu_1 = atol(tok_end + 1);
472 }
473
474 step = 1;
475 tok_step = strstr(tok, "#");
476 if (tok_step) {
477 step = atol(tok_step + 1);
478 BUG_ON(step <= 0 || step >= g->p.nr_cpus);
479 }
480
481 /*
482 * Mask length.
483 * Eg: "--cpus 8_4-16#4" means: '--cpus 8_4,12_4,16_4',
484 * where the _4 means the next 4 CPUs are allowed.
485 */
486 bind_len = 1;
487 tok_len = strstr(tok, "_");
488 if (tok_len) {
489 bind_len = atol(tok_len + 1);
490 BUG_ON(bind_len <= 0 || bind_len > g->p.nr_cpus);
491 }
492
493 /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */
494 mul = 1;
495 tok_mul = strstr(tok, "x");
496 if (tok_mul) {
497 mul = atol(tok_mul + 1);
498 BUG_ON(mul <= 0);
499 }
500
501 dprintf("CPUs: %d_%d-%d#%dx%d\n", bind_cpu_0, bind_len, bind_cpu_1, step, mul);
502
503 BUG_ON(bind_cpu_0 < 0 || bind_cpu_0 >= g->p.nr_cpus);
504 BUG_ON(bind_cpu_1 < 0 || bind_cpu_1 >= g->p.nr_cpus);
505 BUG_ON(bind_cpu_0 > bind_cpu_1);
506
507 for (bind_cpu = bind_cpu_0; bind_cpu <= bind_cpu_1; bind_cpu += step) {
508 int i;
509
510 for (i = 0; i < mul; i++) {
511 int cpu;
512
513 if (t >= g->p.nr_tasks) {
514 printf("\n# NOTE: ignoring bind CPUs starting at CPU#%d\n #", bind_cpu);
515 goto out;
516 }
517 td = g->threads + t;
518
519 if (t)
520 tprintf(",");
521 if (bind_len > 1) {
522 tprintf("%2d/%d", bind_cpu, bind_len);
523 } else {
524 tprintf("%2d", bind_cpu);
525 }
526
527 CPU_ZERO(&td->bind_cpumask);
528 for (cpu = bind_cpu; cpu < bind_cpu+bind_len; cpu++) {
529 BUG_ON(cpu < 0 || cpu >= g->p.nr_cpus);
530 CPU_SET(cpu, &td->bind_cpumask);
531 }
532 t++;
533 }
534 }
535 }
536out:
537
538 tprintf("\n");
539
540 if (t < g->p.nr_tasks)
541 printf("# NOTE: %d tasks bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
542
543 free(str0);
544}
545
546static int parse_cpus_opt(const struct option *opt __maybe_unused,
547 const char *arg, int unset __maybe_unused)
548{
549 if (!arg)
550 return -1;
551
552 return parse_cpu_list(arg);
553}
554
555static int parse_node_list(const char *arg)
556{
557 p0.node_list_str = strdup(arg);
558
559 dprintf("got NODE list: {%s}\n", p0.node_list_str);
560
561 return 0;
562}
563
564static void parse_setup_node_list(void)
565{
566 struct thread_data *td;
567 char *str0, *str;
568 int t;
569
570 if (!g->p.node_list_str)
571 return;
572
573 dprintf("g->p.nr_tasks: %d\n", g->p.nr_tasks);
574
575 str0 = str = strdup(g->p.node_list_str);
576 t = 0;
577
578 BUG_ON(!str);
579
580 tprintf("# binding tasks to NODEs:\n");
581 tprintf("# ");
582
583 while (true) {
584 int bind_node, bind_node_0, bind_node_1;
585 char *tok, *tok_end, *tok_step, *tok_mul;
586 int step;
587 int mul;
588
589 tok = strsep(&str, ",");
590 if (!tok)
591 break;
592
593 tok_end = strstr(tok, "-");
594
595 dprintf("\ntoken: {%s}, end: {%s}\n", tok, tok_end);
596 if (!tok_end) {
597 /* Single NODE specified: */
598 bind_node_0 = bind_node_1 = atol(tok);
599 } else {
600 /* NODE range specified (for example: "5-11"): */
601 bind_node_0 = atol(tok);
602 bind_node_1 = atol(tok_end + 1);
603 }
604
605 step = 1;
606 tok_step = strstr(tok, "#");
607 if (tok_step) {
608 step = atol(tok_step + 1);
609 BUG_ON(step <= 0 || step >= g->p.nr_nodes);
610 }
611
612 /* Multiplicator shortcut, "0x8" is a shortcut for: "0,0,0,0,0,0,0,0" */
613 mul = 1;
614 tok_mul = strstr(tok, "x");
615 if (tok_mul) {
616 mul = atol(tok_mul + 1);
617 BUG_ON(mul <= 0);
618 }
619
620 dprintf("NODEs: %d-%d #%d\n", bind_node_0, bind_node_1, step);
621
622 BUG_ON(bind_node_0 < 0 || bind_node_0 >= g->p.nr_nodes);
623 BUG_ON(bind_node_1 < 0 || bind_node_1 >= g->p.nr_nodes);
624 BUG_ON(bind_node_0 > bind_node_1);
625
626 for (bind_node = bind_node_0; bind_node <= bind_node_1; bind_node += step) {
627 int i;
628
629 for (i = 0; i < mul; i++) {
630 if (t >= g->p.nr_tasks) {
631 printf("\n# NOTE: ignoring bind NODEs starting at NODE#%d\n", bind_node);
632 goto out;
633 }
634 td = g->threads + t;
635
636 if (!t)
637 tprintf(" %2d", bind_node);
638 else
639 tprintf(",%2d", bind_node);
640
641 td->bind_node = bind_node;
642 t++;
643 }
644 }
645 }
646out:
647
648 tprintf("\n");
649
650 if (t < g->p.nr_tasks)
651 printf("# NOTE: %d tasks mem-bound, %d tasks unbound\n", t, g->p.nr_tasks - t);
652
653 free(str0);
654}
655
656static int parse_nodes_opt(const struct option *opt __maybe_unused,
657 const char *arg, int unset __maybe_unused)
658{
659 if (!arg)
660 return -1;
661
662 return parse_node_list(arg);
663
664 return 0;
665}
666
667#define BIT(x) (1ul << x)
668
669static inline uint32_t lfsr_32(uint32_t lfsr)
670{
671 const uint32_t taps = BIT(1) | BIT(5) | BIT(6) | BIT(31);
672 return (lfsr>>1) ^ ((0x0u - (lfsr & 0x1u)) & taps);
673}
674
675/*
676 * Make sure there's real data dependency to RAM (when read
677 * accesses are enabled), so the compiler, the CPU and the
678 * kernel (KSM, zero page, etc.) cannot optimize away RAM
679 * accesses:
680 */
681static inline u64 access_data(u64 *data __attribute__((unused)), u64 val)
682{
683 if (g->p.data_reads)
684 val += *data;
685 if (g->p.data_writes)
686 *data = val + 1;
687 return val;
688}
689
690/*
691 * The worker process does two types of work, a forwards going
692 * loop and a backwards going loop.
693 *
694 * We do this so that on multiprocessor systems we do not create
695 * a 'train' of processing, with highly synchronized processes,
696 * skewing the whole benchmark.
697 */
698static u64 do_work(u8 *__data, long bytes, int nr, int nr_max, int loop, u64 val)
699{
700 long words = bytes/sizeof(u64);
701 u64 *data = (void *)__data;
702 long chunk_0, chunk_1;
703 u64 *d0, *d, *d1;
704 long off;
705 long i;
706
707 BUG_ON(!data && words);
708 BUG_ON(data && !words);
709
710 if (!data)
711 return val;
712
713 /* Very simple memset() work variant: */
714 if (g->p.data_zero_memset && !g->p.data_rand_walk) {
715 bzero(data, bytes);
716 return val;
717 }
718
719 /* Spread out by PID/TID nr and by loop nr: */
720 chunk_0 = words/nr_max;
721 chunk_1 = words/g->p.nr_loops;
722 off = nr*chunk_0 + loop*chunk_1;
723
724 while (off >= words)
725 off -= words;
726
727 if (g->p.data_rand_walk) {
728 u32 lfsr = nr + loop + val;
729 int j;
730
731 for (i = 0; i < words/1024; i++) {
732 long start, end;
733
734 lfsr = lfsr_32(lfsr);
735
736 start = lfsr % words;
737 end = min(start + 1024, words-1);
738
739 if (g->p.data_zero_memset) {
740 bzero(data + start, (end-start) * sizeof(u64));
741 } else {
742 for (j = start; j < end; j++)
743 val = access_data(data + j, val);
744 }
745 }
746 } else if (!g->p.data_backwards || (nr + loop) & 1) {
747
748 d0 = data + off;
749 d = data + off + 1;
750 d1 = data + words;
751
752 /* Process data forwards: */
753 for (;;) {
754 if (unlikely(d >= d1))
755 d = data;
756 if (unlikely(d == d0))
757 break;
758
759 val = access_data(d, val);
760
761 d++;
762 }
763 } else {
764 /* Process data backwards: */
765
766 d0 = data + off;
767 d = data + off - 1;
768 d1 = data + words;
769
770 /* Process data forwards: */
771 for (;;) {
772 if (unlikely(d < data))
773 d = data + words-1;
774 if (unlikely(d == d0))
775 break;
776
777 val = access_data(d, val);
778
779 d--;
780 }
781 }
782
783 return val;
784}
785
786static void update_curr_cpu(int task_nr, unsigned long bytes_worked)
787{
788 unsigned int cpu;
789
790 cpu = sched_getcpu();
791
792 g->threads[task_nr].curr_cpu = cpu;
793 prctl(0, bytes_worked);
794}
795
796#define MAX_NR_NODES 64
797
798/*
799 * Count the number of nodes a process's threads
800 * are spread out on.
801 *
802 * A count of 1 means that the process is compressed
803 * to a single node. A count of g->p.nr_nodes means it's
804 * spread out on the whole system.
805 */
806static int count_process_nodes(int process_nr)
807{
808 char node_present[MAX_NR_NODES] = { 0, };
809 int nodes;
810 int n, t;
811
812 for (t = 0; t < g->p.nr_threads; t++) {
813 struct thread_data *td;
814 int task_nr;
815 int node;
816
817 task_nr = process_nr*g->p.nr_threads + t;
818 td = g->threads + task_nr;
819
820 node = numa_node_of_cpu(td->curr_cpu);
821 node_present[node] = 1;
822 }
823
824 nodes = 0;
825
826 for (n = 0; n < MAX_NR_NODES; n++)
827 nodes += node_present[n];
828
829 return nodes;
830}
831
832/*
833 * Count the number of distinct process-threads a node contains.
834 *
835 * A count of 1 means that the node contains only a single
836 * process. If all nodes on the system contain at most one
837 * process then we are well-converged.
838 */
839static int count_node_processes(int node)
840{
841 int processes = 0;
842 int t, p;
843
844 for (p = 0; p < g->p.nr_proc; p++) {
845 for (t = 0; t < g->p.nr_threads; t++) {
846 struct thread_data *td;
847 int task_nr;
848 int n;
849
850 task_nr = p*g->p.nr_threads + t;
851 td = g->threads + task_nr;
852
853 n = numa_node_of_cpu(td->curr_cpu);
854 if (n == node) {
855 processes++;
856 break;
857 }
858 }
859 }
860
861 return processes;
862}
863
864static void calc_convergence_compression(int *strong)
865{
866 unsigned int nodes_min, nodes_max;
867 int p;
868
869 nodes_min = -1;
870 nodes_max = 0;
871
872 for (p = 0; p < g->p.nr_proc; p++) {
873 unsigned int nodes = count_process_nodes(p);
874
875 nodes_min = min(nodes, nodes_min);
876 nodes_max = max(nodes, nodes_max);
877 }
878
879 /* Strong convergence: all threads compress on a single node: */
880 if (nodes_min == 1 && nodes_max == 1) {
881 *strong = 1;
882 } else {
883 *strong = 0;
884 tprintf(" {%d-%d}", nodes_min, nodes_max);
885 }
886}
887
888static void calc_convergence(double runtime_ns_max, double *convergence)
889{
890 unsigned int loops_done_min, loops_done_max;
891 int process_groups;
892 int nodes[MAX_NR_NODES];
893 int distance;
894 int nr_min;
895 int nr_max;
896 int strong;
897 int sum;
898 int nr;
899 int node;
900 int cpu;
901 int t;
902
903 if (!g->p.show_convergence && !g->p.measure_convergence)
904 return;
905
906 for (node = 0; node < g->p.nr_nodes; node++)
907 nodes[node] = 0;
908
909 loops_done_min = -1;
910 loops_done_max = 0;
911
912 for (t = 0; t < g->p.nr_tasks; t++) {
913 struct thread_data *td = g->threads + t;
914 unsigned int loops_done;
915
916 cpu = td->curr_cpu;
917
918 /* Not all threads have written it yet: */
919 if (cpu < 0)
920 continue;
921
922 node = numa_node_of_cpu(cpu);
923
924 nodes[node]++;
925
926 loops_done = td->loops_done;
927 loops_done_min = min(loops_done, loops_done_min);
928 loops_done_max = max(loops_done, loops_done_max);
929 }
930
931 nr_max = 0;
932 nr_min = g->p.nr_tasks;
933 sum = 0;
934
935 for (node = 0; node < g->p.nr_nodes; node++) {
936 nr = nodes[node];
937 nr_min = min(nr, nr_min);
938 nr_max = max(nr, nr_max);
939 sum += nr;
940 }
941 BUG_ON(nr_min > nr_max);
942
943 BUG_ON(sum > g->p.nr_tasks);
944
945 if (0 && (sum < g->p.nr_tasks))
946 return;
947
948 /*
949 * Count the number of distinct process groups present
950 * on nodes - when we are converged this will decrease
951 * to g->p.nr_proc:
952 */
953 process_groups = 0;
954
955 for (node = 0; node < g->p.nr_nodes; node++) {
956 int processes = count_node_processes(node);
957
958 nr = nodes[node];
959 tprintf(" %2d/%-2d", nr, processes);
960
961 process_groups += processes;
962 }
963
964 distance = nr_max - nr_min;
965
966 tprintf(" [%2d/%-2d]", distance, process_groups);
967
968 tprintf(" l:%3d-%-3d (%3d)",
969 loops_done_min, loops_done_max, loops_done_max-loops_done_min);
970
971 if (loops_done_min && loops_done_max) {
972 double skew = 1.0 - (double)loops_done_min/loops_done_max;
973
974 tprintf(" [%4.1f%%]", skew * 100.0);
975 }
976
977 calc_convergence_compression(&strong);
978
979 if (strong && process_groups == g->p.nr_proc) {
980 if (!*convergence) {
981 *convergence = runtime_ns_max;
982 tprintf(" (%6.1fs converged)\n", *convergence/1e9);
983 if (g->p.measure_convergence) {
984 g->all_converged = true;
985 g->stop_work = true;
986 }
987 }
988 } else {
989 if (*convergence) {
990 tprintf(" (%6.1fs de-converged)", runtime_ns_max/1e9);
991 *convergence = 0;
992 }
993 tprintf("\n");
994 }
995}
996
997static void show_summary(double runtime_ns_max, int l, double *convergence)
998{
999 tprintf("\r # %5.1f%% [%.1f mins]",
1000 (double)(l+1)/g->p.nr_loops*100.0, runtime_ns_max/1e9 / 60.0);
1001
1002 calc_convergence(runtime_ns_max, convergence);
1003
1004 if (g->p.show_details >= 0)
1005 fflush(stdout);
1006}
1007
1008static void *worker_thread(void *__tdata)
1009{
1010 struct thread_data *td = __tdata;
1011 struct timeval start0, start, stop, diff;
1012 int process_nr = td->process_nr;
1013 int thread_nr = td->thread_nr;
1014 unsigned long last_perturbance;
1015 int task_nr = td->task_nr;
1016 int details = g->p.show_details;
1017 int first_task, last_task;
1018 double convergence = 0;
1019 u64 val = td->val;
1020 double runtime_ns_max;
1021 u8 *global_data;
1022 u8 *process_data;
1023 u8 *thread_data;
1024 u64 bytes_done;
1025 long work_done;
1026 u32 l;
1027
1028 bind_to_cpumask(td->bind_cpumask);
1029 bind_to_memnode(td->bind_node);
1030
1031 set_taskname("thread %d/%d", process_nr, thread_nr);
1032
1033 global_data = g->data;
1034 process_data = td->process_data;
1035 thread_data = setup_private_data(g->p.bytes_thread);
1036
1037 bytes_done = 0;
1038
1039 last_task = 0;
1040 if (process_nr == g->p.nr_proc-1 && thread_nr == g->p.nr_threads-1)
1041 last_task = 1;
1042
1043 first_task = 0;
1044 if (process_nr == 0 && thread_nr == 0)
1045 first_task = 1;
1046
1047 if (details >= 2) {
1048 printf("# thread %2d / %2d global mem: %p, process mem: %p, thread mem: %p\n",
1049 process_nr, thread_nr, global_data, process_data, thread_data);
1050 }
1051
1052 if (g->p.serialize_startup) {
1053 pthread_mutex_lock(&g->startup_mutex);
1054 g->nr_tasks_started++;
1055 pthread_mutex_unlock(&g->startup_mutex);
1056
1057 /* Here we will wait for the main process to start us all at once: */
1058 pthread_mutex_lock(&g->start_work_mutex);
1059 g->nr_tasks_working++;
1060
1061 /* Last one wake the main process: */
1062 if (g->nr_tasks_working == g->p.nr_tasks)
1063 pthread_mutex_unlock(&g->startup_done_mutex);
1064
1065 pthread_mutex_unlock(&g->start_work_mutex);
1066 }
1067
1068 gettimeofday(&start0, NULL);
1069
1070 start = stop = start0;
1071 last_perturbance = start.tv_sec;
1072
1073 for (l = 0; l < g->p.nr_loops; l++) {
1074 start = stop;
1075
1076 if (g->stop_work)
1077 break;
1078
1079 val += do_work(global_data, g->p.bytes_global, process_nr, g->p.nr_proc, l, val);
1080 val += do_work(process_data, g->p.bytes_process, thread_nr, g->p.nr_threads, l, val);
1081 val += do_work(thread_data, g->p.bytes_thread, 0, 1, l, val);
1082
1083 if (g->p.sleep_usecs) {
1084 pthread_mutex_lock(td->process_lock);
1085 usleep(g->p.sleep_usecs);
1086 pthread_mutex_unlock(td->process_lock);
1087 }
1088 /*
1089 * Amount of work to be done under a process-global lock:
1090 */
1091 if (g->p.bytes_process_locked) {
1092 pthread_mutex_lock(td->process_lock);
1093 val += do_work(process_data, g->p.bytes_process_locked, thread_nr, g->p.nr_threads, l, val);
1094 pthread_mutex_unlock(td->process_lock);
1095 }
1096
1097 work_done = g->p.bytes_global + g->p.bytes_process +
1098 g->p.bytes_process_locked + g->p.bytes_thread;
1099
1100 update_curr_cpu(task_nr, work_done);
1101 bytes_done += work_done;
1102
1103 if (details < 0 && !g->p.perturb_secs && !g->p.measure_convergence && !g->p.nr_secs)
1104 continue;
1105
1106 td->loops_done = l;
1107
1108 gettimeofday(&stop, NULL);
1109
1110 /* Check whether our max runtime timed out: */
1111 if (g->p.nr_secs) {
1112 timersub(&stop, &start0, &diff);
1113 if (diff.tv_sec >= g->p.nr_secs) {
1114 g->stop_work = true;
1115 break;
1116 }
1117 }
1118
1119 /* Update the summary at most once per second: */
1120 if (start.tv_sec == stop.tv_sec)
1121 continue;
1122
1123 /*
1124 * Perturb the first task's equilibrium every g->p.perturb_secs seconds,
1125 * by migrating to CPU#0:
1126 */
1127 if (first_task && g->p.perturb_secs && (int)(stop.tv_sec - last_perturbance) >= g->p.perturb_secs) {
1128 cpu_set_t orig_mask;
1129 int target_cpu;
1130 int this_cpu;
1131
1132 last_perturbance = stop.tv_sec;
1133
1134 /*
1135 * Depending on where we are running, move into
1136 * the other half of the system, to create some
1137 * real disturbance:
1138 */
1139 this_cpu = g->threads[task_nr].curr_cpu;
1140 if (this_cpu < g->p.nr_cpus/2)
1141 target_cpu = g->p.nr_cpus-1;
1142 else
1143 target_cpu = 0;
1144
1145 orig_mask = bind_to_cpu(target_cpu);
1146
1147 /* Here we are running on the target CPU already */
1148 if (details >= 1)
1149 printf(" (injecting perturbalance, moved to CPU#%d)\n", target_cpu);
1150
1151 bind_to_cpumask(orig_mask);
1152 }
1153
1154 if (details >= 3) {
1155 timersub(&stop, &start, &diff);
1156 runtime_ns_max = diff.tv_sec * 1000000000;
1157 runtime_ns_max += diff.tv_usec * 1000;
1158
1159 if (details >= 0) {
1160 printf(" #%2d / %2d: %14.2lf nsecs/op [val: %016lx]\n",
1161 process_nr, thread_nr, runtime_ns_max / bytes_done, val);
1162 }
1163 fflush(stdout);
1164 }
1165 if (!last_task)
1166 continue;
1167
1168 timersub(&stop, &start0, &diff);
1169 runtime_ns_max = diff.tv_sec * 1000000000ULL;
1170 runtime_ns_max += diff.tv_usec * 1000ULL;
1171
1172 show_summary(runtime_ns_max, l, &convergence);
1173 }
1174
1175 gettimeofday(&stop, NULL);
1176 timersub(&stop, &start0, &diff);
1177 td->runtime_ns = diff.tv_sec * 1000000000ULL;
1178 td->runtime_ns += diff.tv_usec * 1000ULL;
1179
1180 free_data(thread_data, g->p.bytes_thread);
1181
1182 pthread_mutex_lock(&g->stop_work_mutex);
1183 g->bytes_done += bytes_done;
1184 pthread_mutex_unlock(&g->stop_work_mutex);
1185
1186 return NULL;
1187}
1188
1189/*
1190 * A worker process starts a couple of threads:
1191 */
1192static void worker_process(int process_nr)
1193{
1194 pthread_mutex_t process_lock;
1195 struct thread_data *td;
1196 pthread_t *pthreads;
1197 u8 *process_data;
1198 int task_nr;
1199 int ret;
1200 int t;
1201
1202 pthread_mutex_init(&process_lock, NULL);
1203 set_taskname("process %d", process_nr);
1204
1205 /*
1206 * Pick up the memory policy and the CPU binding of our first thread,
1207 * so that we initialize memory accordingly:
1208 */
1209 task_nr = process_nr*g->p.nr_threads;
1210 td = g->threads + task_nr;
1211
1212 bind_to_memnode(td->bind_node);
1213 bind_to_cpumask(td->bind_cpumask);
1214
1215 pthreads = zalloc(g->p.nr_threads * sizeof(pthread_t));
1216 process_data = setup_private_data(g->p.bytes_process);
1217
1218 if (g->p.show_details >= 3) {
1219 printf(" # process %2d global mem: %p, process mem: %p\n",
1220 process_nr, g->data, process_data);
1221 }
1222
1223 for (t = 0; t < g->p.nr_threads; t++) {
1224 task_nr = process_nr*g->p.nr_threads + t;
1225 td = g->threads + task_nr;
1226
1227 td->process_data = process_data;
1228 td->process_nr = process_nr;
1229 td->thread_nr = t;
1230 td->task_nr = task_nr;
1231 td->val = rand();
1232 td->curr_cpu = -1;
1233 td->process_lock = &process_lock;
1234
1235 ret = pthread_create(pthreads + t, NULL, worker_thread, td);
1236 BUG_ON(ret);
1237 }
1238
1239 for (t = 0; t < g->p.nr_threads; t++) {
1240 ret = pthread_join(pthreads[t], NULL);
1241 BUG_ON(ret);
1242 }
1243
1244 free_data(process_data, g->p.bytes_process);
1245 free(pthreads);
1246}
1247
1248static void print_summary(void)
1249{
1250 if (g->p.show_details < 0)
1251 return;
1252
1253 printf("\n ###\n");
1254 printf(" # %d %s will execute (on %d nodes, %d CPUs):\n",
1255 g->p.nr_tasks, g->p.nr_tasks == 1 ? "task" : "tasks", g->p.nr_nodes, g->p.nr_cpus);
1256 printf(" # %5dx %5ldMB global shared mem operations\n",
1257 g->p.nr_loops, g->p.bytes_global/1024/1024);
1258 printf(" # %5dx %5ldMB process shared mem operations\n",
1259 g->p.nr_loops, g->p.bytes_process/1024/1024);
1260 printf(" # %5dx %5ldMB thread local mem operations\n",
1261 g->p.nr_loops, g->p.bytes_thread/1024/1024);
1262
1263 printf(" ###\n");
1264
1265 printf("\n ###\n"); fflush(stdout);
1266}
1267
1268static void init_thread_data(void)
1269{
1270 ssize_t size = sizeof(*g->threads)*g->p.nr_tasks;
1271 int t;
1272
1273 g->threads = zalloc_shared_data(size);
1274
1275 for (t = 0; t < g->p.nr_tasks; t++) {
1276 struct thread_data *td = g->threads + t;
1277 int cpu;
1278
1279 /* Allow all nodes by default: */
1280 td->bind_node = -1;
1281
1282 /* Allow all CPUs by default: */
1283 CPU_ZERO(&td->bind_cpumask);
1284 for (cpu = 0; cpu < g->p.nr_cpus; cpu++)
1285 CPU_SET(cpu, &td->bind_cpumask);
1286 }
1287}
1288
1289static void deinit_thread_data(void)
1290{
1291 ssize_t size = sizeof(*g->threads)*g->p.nr_tasks;
1292
1293 free_data(g->threads, size);
1294}
1295
1296static int init(void)
1297{
1298 g = (void *)alloc_data(sizeof(*g), MAP_SHARED, 1, 0, 0 /* THP */, 0);
1299
1300 /* Copy over options: */
1301 g->p = p0;
1302
1303 g->p.nr_cpus = numa_num_configured_cpus();
1304
1305 g->p.nr_nodes = numa_max_node() + 1;
1306
1307 /* char array in count_process_nodes(): */
1308 BUG_ON(g->p.nr_nodes > MAX_NR_NODES || g->p.nr_nodes < 0);
1309
1310 if (g->p.show_quiet && !g->p.show_details)
1311 g->p.show_details = -1;
1312
1313 /* Some memory should be specified: */
1314 if (!g->p.mb_global_str && !g->p.mb_proc_str && !g->p.mb_thread_str)
1315 return -1;
1316
1317 if (g->p.mb_global_str) {
1318 g->p.mb_global = atof(g->p.mb_global_str);
1319 BUG_ON(g->p.mb_global < 0);
1320 }
1321
1322 if (g->p.mb_proc_str) {
1323 g->p.mb_proc = atof(g->p.mb_proc_str);
1324 BUG_ON(g->p.mb_proc < 0);
1325 }
1326
1327 if (g->p.mb_proc_locked_str) {
1328 g->p.mb_proc_locked = atof(g->p.mb_proc_locked_str);
1329 BUG_ON(g->p.mb_proc_locked < 0);
1330 BUG_ON(g->p.mb_proc_locked > g->p.mb_proc);
1331 }
1332
1333 if (g->p.mb_thread_str) {
1334 g->p.mb_thread = atof(g->p.mb_thread_str);
1335 BUG_ON(g->p.mb_thread < 0);
1336 }
1337
1338 BUG_ON(g->p.nr_threads <= 0);
1339 BUG_ON(g->p.nr_proc <= 0);
1340
1341 g->p.nr_tasks = g->p.nr_proc*g->p.nr_threads;
1342
1343 g->p.bytes_global = g->p.mb_global *1024L*1024L;
1344 g->p.bytes_process = g->p.mb_proc *1024L*1024L;
1345 g->p.bytes_process_locked = g->p.mb_proc_locked *1024L*1024L;
1346 g->p.bytes_thread = g->p.mb_thread *1024L*1024L;
1347
1348 g->data = setup_shared_data(g->p.bytes_global);
1349
1350 /* Startup serialization: */
1351 init_global_mutex(&g->start_work_mutex);
1352 init_global_mutex(&g->startup_mutex);
1353 init_global_mutex(&g->startup_done_mutex);
1354 init_global_mutex(&g->stop_work_mutex);
1355
1356 init_thread_data();
1357
1358 tprintf("#\n");
1359 parse_setup_cpu_list();
1360 parse_setup_node_list();
1361 tprintf("#\n");
1362
1363 print_summary();
1364
1365 return 0;
1366}
1367
1368static void deinit(void)
1369{
1370 free_data(g->data, g->p.bytes_global);
1371 g->data = NULL;
1372
1373 deinit_thread_data();
1374
1375 free_data(g, sizeof(*g));
1376 g = NULL;
1377}
1378
1379/*
1380 * Print a short or long result, depending on the verbosity setting:
1381 */
1382static void print_res(const char *name, double val,
1383 const char *txt_unit, const char *txt_short, const char *txt_long)
1384{
1385 if (!name)
1386 name = "main,";
1387
1388 if (g->p.show_quiet)
1389 printf(" %-30s %15.3f, %-15s %s\n", name, val, txt_unit, txt_short);
1390 else
1391 printf(" %14.3f %s\n", val, txt_long);
1392}
1393
1394static int __bench_numa(const char *name)
1395{
1396 struct timeval start, stop, diff;
1397 u64 runtime_ns_min, runtime_ns_sum;
1398 pid_t *pids, pid, wpid;
1399 double delta_runtime;
1400 double runtime_avg;
1401 double runtime_sec_max;
1402 double runtime_sec_min;
1403 int wait_stat;
1404 double bytes;
1405 int i, t;
1406
1407 if (init())
1408 return -1;
1409
1410 pids = zalloc(g->p.nr_proc * sizeof(*pids));
1411 pid = -1;
1412
1413 /* All threads try to acquire it, this way we can wait for them to start up: */
1414 pthread_mutex_lock(&g->start_work_mutex);
1415
1416 if (g->p.serialize_startup) {
1417 tprintf(" #\n");
1418 tprintf(" # Startup synchronization: ..."); fflush(stdout);
1419 }
1420
1421 gettimeofday(&start, NULL);
1422
1423 for (i = 0; i < g->p.nr_proc; i++) {
1424 pid = fork();
1425 dprintf(" # process %2d: PID %d\n", i, pid);
1426
1427 BUG_ON(pid < 0);
1428 if (!pid) {
1429 /* Child process: */
1430 worker_process(i);
1431
1432 exit(0);
1433 }
1434 pids[i] = pid;
1435
1436 }
1437 /* Wait for all the threads to start up: */
1438 while (g->nr_tasks_started != g->p.nr_tasks)
1439 usleep(1000);
1440
1441 BUG_ON(g->nr_tasks_started != g->p.nr_tasks);
1442
1443 if (g->p.serialize_startup) {
1444 double startup_sec;
1445
1446 pthread_mutex_lock(&g->startup_done_mutex);
1447
1448 /* This will start all threads: */
1449 pthread_mutex_unlock(&g->start_work_mutex);
1450
1451 /* This mutex is locked - the last started thread will wake us: */
1452 pthread_mutex_lock(&g->startup_done_mutex);
1453
1454 gettimeofday(&stop, NULL);
1455
1456 timersub(&stop, &start, &diff);
1457
1458 startup_sec = diff.tv_sec * 1000000000.0;
1459 startup_sec += diff.tv_usec * 1000.0;
1460 startup_sec /= 1e9;
1461
1462 tprintf(" threads initialized in %.6f seconds.\n", startup_sec);
1463 tprintf(" #\n");
1464
1465 start = stop;
1466 pthread_mutex_unlock(&g->startup_done_mutex);
1467 } else {
1468 gettimeofday(&start, NULL);
1469 }
1470
1471 /* Parent process: */
1472
1473
1474 for (i = 0; i < g->p.nr_proc; i++) {
1475 wpid = waitpid(pids[i], &wait_stat, 0);
1476 BUG_ON(wpid < 0);
1477 BUG_ON(!WIFEXITED(wait_stat));
1478
1479 }
1480
1481 runtime_ns_sum = 0;
1482 runtime_ns_min = -1LL;
1483
1484 for (t = 0; t < g->p.nr_tasks; t++) {
1485 u64 thread_runtime_ns = g->threads[t].runtime_ns;
1486
1487 runtime_ns_sum += thread_runtime_ns;
1488 runtime_ns_min = min(thread_runtime_ns, runtime_ns_min);
1489 }
1490
1491 gettimeofday(&stop, NULL);
1492 timersub(&stop, &start, &diff);
1493
1494 BUG_ON(bench_format != BENCH_FORMAT_DEFAULT);
1495
1496 tprintf("\n ###\n");
1497 tprintf("\n");
1498
1499 runtime_sec_max = diff.tv_sec * 1000000000.0;
1500 runtime_sec_max += diff.tv_usec * 1000.0;
1501 runtime_sec_max /= 1e9;
1502
1503 runtime_sec_min = runtime_ns_min/1e9;
1504
1505 bytes = g->bytes_done;
1506 runtime_avg = (double)runtime_ns_sum / g->p.nr_tasks / 1e9;
1507
1508 if (g->p.measure_convergence) {
1509 print_res(name, runtime_sec_max,
1510 "secs,", "NUMA-convergence-latency", "secs latency to NUMA-converge");
1511 }
1512
1513 print_res(name, runtime_sec_max,
1514 "secs,", "runtime-max/thread", "secs slowest (max) thread-runtime");
1515
1516 print_res(name, runtime_sec_min,
1517 "secs,", "runtime-min/thread", "secs fastest (min) thread-runtime");
1518
1519 print_res(name, runtime_avg,
1520 "secs,", "runtime-avg/thread", "secs average thread-runtime");
1521
1522 delta_runtime = (runtime_sec_max - runtime_sec_min)/2.0;
1523 print_res(name, delta_runtime / runtime_sec_max * 100.0,
1524 "%,", "spread-runtime/thread", "% difference between max/avg runtime");
1525
1526 print_res(name, bytes / g->p.nr_tasks / 1e9,
1527 "GB,", "data/thread", "GB data processed, per thread");
1528
1529 print_res(name, bytes / 1e9,
1530 "GB,", "data-total", "GB data processed, total");
1531
1532 print_res(name, runtime_sec_max * 1e9 / (bytes / g->p.nr_tasks),
1533 "nsecs,", "runtime/byte/thread","nsecs/byte/thread runtime");
1534
1535 print_res(name, bytes / g->p.nr_tasks / 1e9 / runtime_sec_max,
1536 "GB/sec,", "thread-speed", "GB/sec/thread speed");
1537
1538 print_res(name, bytes / runtime_sec_max / 1e9,
1539 "GB/sec,", "total-speed", "GB/sec total speed");
1540
1541 free(pids);
1542
1543 deinit();
1544
1545 return 0;
1546}
1547
1548#define MAX_ARGS 50
1549
1550static int command_size(const char **argv)
1551{
1552 int size = 0;
1553
1554 while (*argv) {
1555 size++;
1556 argv++;
1557 }
1558
1559 BUG_ON(size >= MAX_ARGS);
1560
1561 return size;
1562}
1563
1564static void init_params(struct params *p, const char *name, int argc, const char **argv)
1565{
1566 int i;
1567
1568 printf("\n # Running %s \"perf bench numa", name);
1569
1570 for (i = 0; i < argc; i++)
1571 printf(" %s", argv[i]);
1572
1573 printf("\"\n");
1574
1575 memset(p, 0, sizeof(*p));
1576
1577 /* Initialize nonzero defaults: */
1578
1579 p->serialize_startup = 1;
1580 p->data_reads = true;
1581 p->data_writes = true;
1582 p->data_backwards = true;
1583 p->data_rand_walk = true;
1584 p->nr_loops = -1;
1585 p->init_random = true;
1586}
1587
1588static int run_bench_numa(const char *name, const char **argv)
1589{
1590 int argc = command_size(argv);
1591
1592 init_params(&p0, name, argc, argv);
1593 argc = parse_options(argc, argv, options, bench_numa_usage, 0);
1594 if (argc)
1595 goto err;
1596
1597 if (__bench_numa(name))
1598 goto err;
1599
1600 return 0;
1601
1602err:
1603 usage_with_options(numa_usage, options);
1604 return -1;
1605}
1606
1607#define OPT_BW_RAM "-s", "20", "-zZq", "--thp", " 1", "--no-data_rand_walk"
1608#define OPT_BW_RAM_NOTHP OPT_BW_RAM, "--thp", "-1"
1609
1610#define OPT_CONV "-s", "100", "-zZ0qcm", "--thp", " 1"
1611#define OPT_CONV_NOTHP OPT_CONV, "--thp", "-1"
1612
1613#define OPT_BW "-s", "20", "-zZ0q", "--thp", " 1"
1614#define OPT_BW_NOTHP OPT_BW, "--thp", "-1"
1615
1616/*
1617 * The built-in test-suite executed by "perf bench numa -a".
1618 *
1619 * (A minimum of 4 nodes and 16 GB of RAM is recommended.)
1620 */
1621static const char *tests[][MAX_ARGS] = {
1622 /* Basic single-stream NUMA bandwidth measurements: */
1623 { "RAM-bw-local,", "mem", "-p", "1", "-t", "1", "-P", "1024",
1624 "-C" , "0", "-M", "0", OPT_BW_RAM },
1625 { "RAM-bw-local-NOTHP,",
1626 "mem", "-p", "1", "-t", "1", "-P", "1024",
1627 "-C" , "0", "-M", "0", OPT_BW_RAM_NOTHP },
1628 { "RAM-bw-remote,", "mem", "-p", "1", "-t", "1", "-P", "1024",
1629 "-C" , "0", "-M", "1", OPT_BW_RAM },
1630
1631 /* 2-stream NUMA bandwidth measurements: */
1632 { "RAM-bw-local-2x,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1633 "-C", "0,2", "-M", "0x2", OPT_BW_RAM },
1634 { "RAM-bw-remote-2x,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1635 "-C", "0,2", "-M", "1x2", OPT_BW_RAM },
1636
1637 /* Cross-stream NUMA bandwidth measurement: */
1638 { "RAM-bw-cross,", "mem", "-p", "2", "-t", "1", "-P", "1024",
1639 "-C", "0,8", "-M", "1,0", OPT_BW_RAM },
1640
1641 /* Convergence latency measurements: */
1642 { " 1x3-convergence,", "mem", "-p", "1", "-t", "3", "-P", "512", OPT_CONV },
1643 { " 1x4-convergence,", "mem", "-p", "1", "-t", "4", "-P", "512", OPT_CONV },
1644 { " 1x6-convergence,", "mem", "-p", "1", "-t", "6", "-P", "1020", OPT_CONV },
1645 { " 2x3-convergence,", "mem", "-p", "3", "-t", "3", "-P", "1020", OPT_CONV },
1646 { " 3x3-convergence,", "mem", "-p", "3", "-t", "3", "-P", "1020", OPT_CONV },
1647 { " 4x4-convergence,", "mem", "-p", "4", "-t", "4", "-P", "512", OPT_CONV },
1648 { " 4x4-convergence-NOTHP,",
1649 "mem", "-p", "4", "-t", "4", "-P", "512", OPT_CONV_NOTHP },
1650 { " 4x6-convergence,", "mem", "-p", "4", "-t", "6", "-P", "1020", OPT_CONV },
1651 { " 4x8-convergence,", "mem", "-p", "4", "-t", "8", "-P", "512", OPT_CONV },
1652 { " 8x4-convergence,", "mem", "-p", "8", "-t", "4", "-P", "512", OPT_CONV },
1653 { " 8x4-convergence-NOTHP,",
1654 "mem", "-p", "8", "-t", "4", "-P", "512", OPT_CONV_NOTHP },
1655 { " 3x1-convergence,", "mem", "-p", "3", "-t", "1", "-P", "512", OPT_CONV },
1656 { " 4x1-convergence,", "mem", "-p", "4", "-t", "1", "-P", "512", OPT_CONV },
1657 { " 8x1-convergence,", "mem", "-p", "8", "-t", "1", "-P", "512", OPT_CONV },
1658 { "16x1-convergence,", "mem", "-p", "16", "-t", "1", "-P", "256", OPT_CONV },
1659 { "32x1-convergence,", "mem", "-p", "32", "-t", "1", "-P", "128", OPT_CONV },
1660
1661 /* Various NUMA process/thread layout bandwidth measurements: */
1662 { " 2x1-bw-process,", "mem", "-p", "2", "-t", "1", "-P", "1024", OPT_BW },
1663 { " 3x1-bw-process,", "mem", "-p", "3", "-t", "1", "-P", "1024", OPT_BW },
1664 { " 4x1-bw-process,", "mem", "-p", "4", "-t", "1", "-P", "1024", OPT_BW },
1665 { " 8x1-bw-process,", "mem", "-p", "8", "-t", "1", "-P", " 512", OPT_BW },
1666 { " 8x1-bw-process-NOTHP,",
1667 "mem", "-p", "8", "-t", "1", "-P", " 512", OPT_BW_NOTHP },
1668 { "16x1-bw-process,", "mem", "-p", "16", "-t", "1", "-P", "256", OPT_BW },
1669
1670 { " 4x1-bw-thread,", "mem", "-p", "1", "-t", "4", "-T", "256", OPT_BW },
1671 { " 8x1-bw-thread,", "mem", "-p", "1", "-t", "8", "-T", "256", OPT_BW },
1672 { "16x1-bw-thread,", "mem", "-p", "1", "-t", "16", "-T", "128", OPT_BW },
1673 { "32x1-bw-thread,", "mem", "-p", "1", "-t", "32", "-T", "64", OPT_BW },
1674
1675 { " 2x3-bw-thread,", "mem", "-p", "2", "-t", "3", "-P", "512", OPT_BW },
1676 { " 4x4-bw-thread,", "mem", "-p", "4", "-t", "4", "-P", "512", OPT_BW },
1677 { " 4x6-bw-thread,", "mem", "-p", "4", "-t", "6", "-P", "512", OPT_BW },
1678 { " 4x8-bw-thread,", "mem", "-p", "4", "-t", "8", "-P", "512", OPT_BW },
1679 { " 4x8-bw-thread-NOTHP,",
1680 "mem", "-p", "4", "-t", "8", "-P", "512", OPT_BW_NOTHP },
1681 { " 3x3-bw-thread,", "mem", "-p", "3", "-t", "3", "-P", "512", OPT_BW },
1682 { " 5x5-bw-thread,", "mem", "-p", "5", "-t", "5", "-P", "512", OPT_BW },
1683
1684 { "2x16-bw-thread,", "mem", "-p", "2", "-t", "16", "-P", "512", OPT_BW },
1685 { "1x32-bw-thread,", "mem", "-p", "1", "-t", "32", "-P", "2048", OPT_BW },
1686
1687 { "numa02-bw,", "mem", "-p", "1", "-t", "32", "-T", "32", OPT_BW },
1688 { "numa02-bw-NOTHP,", "mem", "-p", "1", "-t", "32", "-T", "32", OPT_BW_NOTHP },
1689 { "numa01-bw-thread,", "mem", "-p", "2", "-t", "16", "-T", "192", OPT_BW },
1690 { "numa01-bw-thread-NOTHP,",
1691 "mem", "-p", "2", "-t", "16", "-T", "192", OPT_BW_NOTHP },
1692};
1693
1694static int bench_all(void)
1695{
1696 int nr = ARRAY_SIZE(tests);
1697 int ret;
1698 int i;
1699
1700 ret = system("echo ' #'; echo ' # Running test on: '$(uname -a); echo ' #'");
1701 BUG_ON(ret < 0);
1702
1703 for (i = 0; i < nr; i++) {
1704 if (run_bench_numa(tests[i][0], tests[i] + 1))
1705 return -1;
1706 }
1707
1708 printf("\n");
1709
1710 return 0;
1711}
1712
1713int bench_numa(int argc, const char **argv, const char *prefix __maybe_unused)
1714{
1715 init_params(&p0, "main,", argc, argv);
1716 argc = parse_options(argc, argv, options, bench_numa_usage, 0);
1717 if (argc)
1718 goto err;
1719
1720 if (p0.run_all)
1721 return bench_all();
1722
1723 if (__bench_numa(NULL))
1724 goto err;
1725
1726 return 0;
1727
1728err:
1729 usage_with_options(numa_usage, options);
1730 return -1;
1731}
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 9ea38540b873..2e6961ea3184 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -28,15 +28,16 @@
28#include "util/hist.h" 28#include "util/hist.h"
29#include "util/session.h" 29#include "util/session.h"
30#include "util/tool.h" 30#include "util/tool.h"
31#include "arch/common.h"
31 32
32#include <linux/bitmap.h> 33#include <linux/bitmap.h>
33 34
34struct perf_annotate { 35struct perf_annotate {
35 struct perf_tool tool; 36 struct perf_tool tool;
36 char const *input_name; 37 bool force, use_tui, use_stdio, use_gtk;
37 bool force, use_tui, use_stdio;
38 bool full_paths; 38 bool full_paths;
39 bool print_line; 39 bool print_line;
40 bool skip_missing;
40 const char *sym_hist_filter; 41 const char *sym_hist_filter;
41 const char *cpu_list; 42 const char *cpu_list;
42 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 43 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -138,9 +139,22 @@ find_next:
138 continue; 139 continue;
139 } 140 }
140 141
141 if (use_browser > 0) { 142 if (use_browser == 2) {
142 key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0); 143 int ret;
144
145 ret = hist_entry__gtk_annotate(he, evidx, NULL);
146 if (!ret || !ann->skip_missing)
147 return;
148
149 /* skip missing symbols */
150 nd = rb_next(nd);
151 } else if (use_browser == 1) {
152 key = hist_entry__tui_annotate(he, evidx, NULL);
143 switch (key) { 153 switch (key) {
154 case -1:
155 if (!ann->skip_missing)
156 return;
157 /* fall through */
144 case K_RIGHT: 158 case K_RIGHT:
145 next = rb_next(nd); 159 next = rb_next(nd);
146 break; 160 break;
@@ -174,7 +188,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
174 struct perf_evsel *pos; 188 struct perf_evsel *pos;
175 u64 total_nr_samples; 189 u64 total_nr_samples;
176 190
177 session = perf_session__new(ann->input_name, O_RDONLY, 191 session = perf_session__new(input_name, O_RDONLY,
178 ann->force, false, &ann->tool); 192 ann->force, false, &ann->tool);
179 if (session == NULL) 193 if (session == NULL)
180 return -ENOMEM; 194 return -ENOMEM;
@@ -186,6 +200,12 @@ static int __cmd_annotate(struct perf_annotate *ann)
186 goto out_delete; 200 goto out_delete;
187 } 201 }
188 202
203 if (!objdump_path) {
204 ret = perf_session_env__lookup_objdump(&session->header.env);
205 if (ret)
206 goto out_delete;
207 }
208
189 ret = perf_session__process_events(session, &ann->tool); 209 ret = perf_session__process_events(session, &ann->tool);
190 if (ret) 210 if (ret)
191 goto out_delete; 211 goto out_delete;
@@ -218,6 +238,10 @@ static int __cmd_annotate(struct perf_annotate *ann)
218 ui__error("The %s file has no samples!\n", session->filename); 238 ui__error("The %s file has no samples!\n", session->filename);
219 goto out_delete; 239 goto out_delete;
220 } 240 }
241
242 if (use_browser == 2)
243 perf_gtk__show_annotations();
244
221out_delete: 245out_delete:
222 /* 246 /*
223 * Speed up the exit process, for large files this can 247 * Speed up the exit process, for large files this can
@@ -246,13 +270,14 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
246 .sample = process_sample_event, 270 .sample = process_sample_event,
247 .mmap = perf_event__process_mmap, 271 .mmap = perf_event__process_mmap,
248 .comm = perf_event__process_comm, 272 .comm = perf_event__process_comm,
249 .fork = perf_event__process_task, 273 .exit = perf_event__process_exit,
274 .fork = perf_event__process_fork,
250 .ordered_samples = true, 275 .ordered_samples = true,
251 .ordering_requires_timestamps = true, 276 .ordering_requires_timestamps = true,
252 }, 277 },
253 }; 278 };
254 const struct option options[] = { 279 const struct option options[] = {
255 OPT_STRING('i', "input", &annotate.input_name, "file", 280 OPT_STRING('i', "input", &input_name, "file",
256 "input file name"), 281 "input file name"),
257 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 282 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
258 "only consider symbols in these dsos"), 283 "only consider symbols in these dsos"),
@@ -263,6 +288,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
263 "be more verbose (show symbol address, etc)"), 288 "be more verbose (show symbol address, etc)"),
264 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 289 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
265 "dump raw trace in ASCII"), 290 "dump raw trace in ASCII"),
291 OPT_BOOLEAN(0, "gtk", &annotate.use_gtk, "Use the GTK interface"),
266 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), 292 OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"),
267 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), 293 OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"),
268 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 294 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
@@ -273,6 +299,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
273 "print matching source lines (may be slow)"), 299 "print matching source lines (may be slow)"),
274 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, 300 OPT_BOOLEAN('P', "full-paths", &annotate.full_paths,
275 "Don't shorten the displayed pathnames"), 301 "Don't shorten the displayed pathnames"),
302 OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
303 "Skip symbols that cannot be annotated"),
276 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), 304 OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
277 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 305 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
278 "Look for files with symbols relative to this directory"), 306 "Look for files with symbols relative to this directory"),
@@ -293,6 +321,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
293 use_browser = 0; 321 use_browser = 0;
294 else if (annotate.use_tui) 322 else if (annotate.use_tui)
295 use_browser = 1; 323 use_browser = 1;
324 else if (annotate.use_gtk)
325 use_browser = 2;
296 326
297 setup_browser(true); 327 setup_browser(true);
298 328
@@ -302,7 +332,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
302 if (symbol__init() < 0) 332 if (symbol__init() < 0)
303 return -1; 333 return -1;
304 334
305 setup_sorting(annotate_usage, options); 335 if (setup_sorting() < 0)
336 usage_with_options(annotate_usage, options);
306 337
307 if (argc) { 338 if (argc) {
308 /* 339 /*
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index cae9a5fd2ecf..77298bf892b8 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -35,6 +35,18 @@ struct bench_suite {
35/* sentinel: easy for help */ 35/* sentinel: easy for help */
36#define suite_all { "all", "Test all benchmark suites", NULL } 36#define suite_all { "all", "Test all benchmark suites", NULL }
37 37
38#ifdef LIBNUMA_SUPPORT
39static struct bench_suite numa_suites[] = {
40 { "mem",
41 "Benchmark for NUMA workloads",
42 bench_numa },
43 suite_all,
44 { NULL,
45 NULL,
46 NULL }
47};
48#endif
49
38static struct bench_suite sched_suites[] = { 50static struct bench_suite sched_suites[] = {
39 { "messaging", 51 { "messaging",
40 "Benchmark for scheduler and IPC mechanisms", 52 "Benchmark for scheduler and IPC mechanisms",
@@ -68,6 +80,11 @@ struct bench_subsys {
68}; 80};
69 81
70static struct bench_subsys subsystems[] = { 82static struct bench_subsys subsystems[] = {
83#ifdef LIBNUMA_SUPPORT
84 { "numa",
85 "NUMA scheduling and MM behavior",
86 numa_suites },
87#endif
71 { "sched", 88 { "sched",
72 "scheduler and IPC mechanism", 89 "scheduler and IPC mechanism",
73 sched_suites }, 90 sched_suites },
@@ -159,6 +176,7 @@ static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
159 printf("# Running %s/%s benchmark...\n", 176 printf("# Running %s/%s benchmark...\n",
160 subsys->name, 177 subsys->name,
161 suites[i].name); 178 suites[i].name);
179 fflush(stdout);
162 180
163 argv[1] = suites[i].name; 181 argv[1] = suites[i].name;
164 suites[i].fn(1, argv, NULL); 182 suites[i].fn(1, argv, NULL);
@@ -225,6 +243,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
225 printf("# Running %s/%s benchmark...\n", 243 printf("# Running %s/%s benchmark...\n",
226 subsystems[i].name, 244 subsystems[i].name,
227 subsystems[i].suites[j].name); 245 subsystems[i].suites[j].name);
246 fflush(stdout);
228 status = subsystems[i].suites[j].fn(argc - 1, 247 status = subsystems[i].suites[j].fn(argc - 1,
229 argv + 1, prefix); 248 argv + 1, prefix);
230 goto end; 249 goto end;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index d37e077f4b14..c96c8fa38243 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -13,6 +13,8 @@
13#include "util/header.h" 13#include "util/header.h"
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/strlist.h" 15#include "util/strlist.h"
16#include "util/build-id.h"
17#include "util/session.h"
16#include "util/symbol.h" 18#include "util/symbol.h"
17 19
18static int build_id_cache__add_file(const char *filename, const char *debugdir) 20static int build_id_cache__add_file(const char *filename, const char *debugdir)
@@ -57,19 +59,89 @@ static int build_id_cache__remove_file(const char *filename,
57 return err; 59 return err;
58} 60}
59 61
62static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)
63{
64 char filename[PATH_MAX];
65 u8 build_id[BUILD_ID_SIZE];
66
67 if (dso__build_id_filename(dso, filename, sizeof(filename)) &&
68 filename__read_build_id(filename, build_id,
69 sizeof(build_id)) != sizeof(build_id)) {
70 if (errno == ENOENT)
71 return false;
72
73 pr_warning("Problems with %s file, consider removing it from the cache\n",
74 filename);
75 } else if (memcmp(dso->build_id, build_id, sizeof(dso->build_id))) {
76 pr_warning("Problems with %s file, consider removing it from the cache\n",
77 filename);
78 }
79
80 return true;
81}
82
83static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp)
84{
85 struct perf_session *session = perf_session__new(filename, O_RDONLY,
86 force, false, NULL);
87 if (session == NULL)
88 return -1;
89
90 perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0);
91 perf_session__delete(session);
92
93 return 0;
94}
95
96static int build_id_cache__update_file(const char *filename,
97 const char *debugdir)
98{
99 u8 build_id[BUILD_ID_SIZE];
100 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
101
102 int err;
103
104 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
105 pr_debug("Couldn't read a build-id in %s\n", filename);
106 return -1;
107 }
108
109 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
110 err = build_id_cache__remove_s(sbuild_id, debugdir);
111 if (!err) {
112 err = build_id_cache__add_s(sbuild_id, debugdir, filename,
113 false, false);
114 }
115 if (verbose)
116 pr_info("Updating %s %s: %s\n", sbuild_id, filename,
117 err ? "FAIL" : "Ok");
118
119 return err;
120}
121
60int cmd_buildid_cache(int argc, const char **argv, 122int cmd_buildid_cache(int argc, const char **argv,
61 const char *prefix __maybe_unused) 123 const char *prefix __maybe_unused)
62{ 124{
63 struct strlist *list; 125 struct strlist *list;
64 struct str_node *pos; 126 struct str_node *pos;
127 int ret = 0;
128 bool force = false;
65 char debugdir[PATH_MAX]; 129 char debugdir[PATH_MAX];
66 char const *add_name_list_str = NULL, 130 char const *add_name_list_str = NULL,
67 *remove_name_list_str = NULL; 131 *remove_name_list_str = NULL,
132 *missing_filename = NULL,
133 *update_name_list_str = NULL;
134
68 const struct option buildid_cache_options[] = { 135 const struct option buildid_cache_options[] = {
69 OPT_STRING('a', "add", &add_name_list_str, 136 OPT_STRING('a', "add", &add_name_list_str,
70 "file list", "file(s) to add"), 137 "file list", "file(s) to add"),
71 OPT_STRING('r', "remove", &remove_name_list_str, "file list", 138 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
72 "file(s) to remove"), 139 "file(s) to remove"),
140 OPT_STRING('M', "missing", &missing_filename, "file",
141 "to find missing build ids in the cache"),
142 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
143 OPT_STRING('u', "update", &update_name_list_str, "file list",
144 "file(s) to update"),
73 OPT_INCR('v', "verbose", &verbose, "be more verbose"), 145 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
74 OPT_END() 146 OPT_END()
75 }; 147 };
@@ -124,5 +196,26 @@ int cmd_buildid_cache(int argc, const char **argv,
124 } 196 }
125 } 197 }
126 198
127 return 0; 199 if (missing_filename)
200 ret = build_id_cache__fprintf_missing(missing_filename, force, stdout);
201
202 if (update_name_list_str) {
203 list = strlist__new(true, update_name_list_str);
204 if (list) {
205 strlist__for_each(pos, list)
206 if (build_id_cache__update_file(pos->s, debugdir)) {
207 if (errno == ENOENT) {
208 pr_debug("%s wasn't in the cache\n",
209 pos->s);
210 continue;
211 }
212 pr_warning("Couldn't update %s: %s\n",
213 pos->s, strerror(errno));
214 }
215
216 strlist__delete(list);
217 }
218 }
219
220 return ret;
128} 221}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index a0e94fffa03e..e74366a13218 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -44,24 +44,26 @@ static int filename__fprintf_build_id(const char *name, FILE *fp)
44 return fprintf(fp, "%s\n", sbuild_id); 44 return fprintf(fp, "%s\n", sbuild_id);
45} 45}
46 46
47static int perf_session__list_build_ids(const char *input_name, 47static bool dso__skip_buildid(struct dso *dso, int with_hits)
48 bool force, bool with_hits) 48{
49 return with_hits && !dso->hit;
50}
51
52static int perf_session__list_build_ids(bool force, bool with_hits)
49{ 53{
50 struct perf_session *session; 54 struct perf_session *session;
51 55
52 symbol__elf_init(); 56 symbol__elf_init();
53
54 session = perf_session__new(input_name, O_RDONLY, force, false,
55 &build_id__mark_dso_hit_ops);
56 if (session == NULL)
57 return -1;
58
59 /* 57 /*
60 * See if this is an ELF file first: 58 * See if this is an ELF file first:
61 */ 59 */
62 if (filename__fprintf_build_id(session->filename, stdout)) 60 if (filename__fprintf_build_id(input_name, stdout))
63 goto out; 61 goto out;
64 62
63 session = perf_session__new(input_name, O_RDONLY, force, false,
64 &build_id__mark_dso_hit_ops);
65 if (session == NULL)
66 return -1;
65 /* 67 /*
66 * in pipe-mode, the only way to get the buildids is to parse 68 * in pipe-mode, the only way to get the buildids is to parse
67 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID 69 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
@@ -69,9 +71,9 @@ static int perf_session__list_build_ids(const char *input_name,
69 if (with_hits || session->fd_pipe) 71 if (with_hits || session->fd_pipe)
70 perf_session__process_events(session, &build_id__mark_dso_hit_ops); 72 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
71 73
72 perf_session__fprintf_dsos_buildid(session, stdout, with_hits); 74 perf_session__fprintf_dsos_buildid(session, stdout, dso__skip_buildid, with_hits);
73out:
74 perf_session__delete(session); 75 perf_session__delete(session);
76out:
75 return 0; 77 return 0;
76} 78}
77 79
@@ -81,7 +83,6 @@ int cmd_buildid_list(int argc, const char **argv,
81 bool show_kernel = false; 83 bool show_kernel = false;
82 bool with_hits = false; 84 bool with_hits = false;
83 bool force = false; 85 bool force = false;
84 const char *input_name = NULL;
85 const struct option options[] = { 86 const struct option options[] = {
86 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"), 87 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
87 OPT_STRING('i', "input", &input_name, "file", "input file name"), 88 OPT_STRING('i', "input", &input_name, "file", "input file name"),
@@ -101,5 +102,5 @@ int cmd_buildid_list(int argc, const char **argv,
101 if (show_kernel) 102 if (show_kernel)
102 return sysfs__fprintf_build_id(stdout); 103 return sysfs__fprintf_build_id(stdout);
103 104
104 return perf_session__list_build_ids(input_name, force, with_hits); 105 return perf_session__list_build_ids(force, with_hits);
105} 106}
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index a0b531c14b97..d207a97a2db1 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -23,7 +23,212 @@ static char const *input_old = "perf.data.old",
23 *input_new = "perf.data"; 23 *input_new = "perf.data";
24static char diff__default_sort_order[] = "dso,symbol"; 24static char diff__default_sort_order[] = "dso,symbol";
25static bool force; 25static bool force;
26static bool show_displacement; 26static bool show_period;
27static bool show_formula;
28static bool show_baseline_only;
29static bool sort_compute;
30
31static s64 compute_wdiff_w1;
32static s64 compute_wdiff_w2;
33
34enum {
35 COMPUTE_DELTA,
36 COMPUTE_RATIO,
37 COMPUTE_WEIGHTED_DIFF,
38 COMPUTE_MAX,
39};
40
41const char *compute_names[COMPUTE_MAX] = {
42 [COMPUTE_DELTA] = "delta",
43 [COMPUTE_RATIO] = "ratio",
44 [COMPUTE_WEIGHTED_DIFF] = "wdiff",
45};
46
47static int compute;
48
49static int setup_compute_opt_wdiff(char *opt)
50{
51 char *w1_str = opt;
52 char *w2_str;
53
54 int ret = -EINVAL;
55
56 if (!opt)
57 goto out;
58
59 w2_str = strchr(opt, ',');
60 if (!w2_str)
61 goto out;
62
63 *w2_str++ = 0x0;
64 if (!*w2_str)
65 goto out;
66
67 compute_wdiff_w1 = strtol(w1_str, NULL, 10);
68 compute_wdiff_w2 = strtol(w2_str, NULL, 10);
69
70 if (!compute_wdiff_w1 || !compute_wdiff_w2)
71 goto out;
72
73 pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
74 compute_wdiff_w1, compute_wdiff_w2);
75
76 ret = 0;
77
78 out:
79 if (ret)
80 pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
81
82 return ret;
83}
84
85static int setup_compute_opt(char *opt)
86{
87 if (compute == COMPUTE_WEIGHTED_DIFF)
88 return setup_compute_opt_wdiff(opt);
89
90 if (opt) {
91 pr_err("Failed: extra option specified '%s'", opt);
92 return -EINVAL;
93 }
94
95 return 0;
96}
97
98static int setup_compute(const struct option *opt, const char *str,
99 int unset __maybe_unused)
100{
101 int *cp = (int *) opt->value;
102 char *cstr = (char *) str;
103 char buf[50];
104 unsigned i;
105 char *option;
106
107 if (!str) {
108 *cp = COMPUTE_DELTA;
109 return 0;
110 }
111
112 if (*str == '+') {
113 sort_compute = true;
114 cstr = (char *) ++str;
115 if (!*str)
116 return 0;
117 }
118
119 option = strchr(str, ':');
120 if (option) {
121 unsigned len = option++ - str;
122
123 /*
124 * The str data are not writeable, so we need
125 * to use another buffer.
126 */
127
128 /* No option value is longer. */
129 if (len >= sizeof(buf))
130 return -EINVAL;
131
132 strncpy(buf, str, len);
133 buf[len] = 0x0;
134 cstr = buf;
135 }
136
137 for (i = 0; i < COMPUTE_MAX; i++)
138 if (!strcmp(cstr, compute_names[i])) {
139 *cp = i;
140 return setup_compute_opt(option);
141 }
142
143 pr_err("Failed: '%s' is not computation method "
144 "(use 'delta','ratio' or 'wdiff')\n", str);
145 return -EINVAL;
146}
147
148double perf_diff__period_percent(struct hist_entry *he, u64 period)
149{
150 u64 total = he->hists->stats.total_period;
151 return (period * 100.0) / total;
152}
153
154double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair)
155{
156 double new_percent = perf_diff__period_percent(he, he->stat.period);
157 double old_percent = perf_diff__period_percent(pair, pair->stat.period);
158
159 he->diff.period_ratio_delta = new_percent - old_percent;
160 he->diff.computed = true;
161 return he->diff.period_ratio_delta;
162}
163
164double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair)
165{
166 double new_period = he->stat.period;
167 double old_period = pair->stat.period;
168
169 he->diff.computed = true;
170 he->diff.period_ratio = new_period / old_period;
171 return he->diff.period_ratio;
172}
173
174s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
175{
176 u64 new_period = he->stat.period;
177 u64 old_period = pair->stat.period;
178
179 he->diff.computed = true;
180 he->diff.wdiff = new_period * compute_wdiff_w2 -
181 old_period * compute_wdiff_w1;
182
183 return he->diff.wdiff;
184}
185
186static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
187 char *buf, size_t size)
188{
189 return scnprintf(buf, size,
190 "(%" PRIu64 " * 100 / %" PRIu64 ") - "
191 "(%" PRIu64 " * 100 / %" PRIu64 ")",
192 he->stat.period, he->hists->stats.total_period,
193 pair->stat.period, pair->hists->stats.total_period);
194}
195
196static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
197 char *buf, size_t size)
198{
199 double new_period = he->stat.period;
200 double old_period = pair->stat.period;
201
202 return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
203}
204
205static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
206 char *buf, size_t size)
207{
208 u64 new_period = he->stat.period;
209 u64 old_period = pair->stat.period;
210
211 return scnprintf(buf, size,
212 "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
213 new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
214}
215
216int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
217 char *buf, size_t size)
218{
219 switch (compute) {
220 case COMPUTE_DELTA:
221 return formula_delta(he, pair, buf, size);
222 case COMPUTE_RATIO:
223 return formula_ratio(he, pair, buf, size);
224 case COMPUTE_WEIGHTED_DIFF:
225 return formula_wdiff(he, pair, buf, size);
226 default:
227 BUG_ON(1);
228 }
229
230 return -1;
231}
27 232
28static int hists__add_entry(struct hists *self, 233static int hists__add_entry(struct hists *self,
29 struct addr_location *al, u64 period) 234 struct addr_location *al, u64 period)
@@ -47,7 +252,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
47 return -1; 252 return -1;
48 } 253 }
49 254
50 if (al.filtered || al.sym == NULL) 255 if (al.filtered)
51 return 0; 256 return 0;
52 257
53 if (hists__add_entry(&evsel->hists, &al, sample->period)) { 258 if (hists__add_entry(&evsel->hists, &al, sample->period)) {
@@ -63,115 +268,197 @@ static struct perf_tool tool = {
63 .sample = diff__process_sample_event, 268 .sample = diff__process_sample_event,
64 .mmap = perf_event__process_mmap, 269 .mmap = perf_event__process_mmap,
65 .comm = perf_event__process_comm, 270 .comm = perf_event__process_comm,
66 .exit = perf_event__process_task, 271 .exit = perf_event__process_exit,
67 .fork = perf_event__process_task, 272 .fork = perf_event__process_fork,
68 .lost = perf_event__process_lost, 273 .lost = perf_event__process_lost,
69 .ordered_samples = true, 274 .ordered_samples = true,
70 .ordering_requires_timestamps = true, 275 .ordering_requires_timestamps = true,
71}; 276};
72 277
73static void insert_hist_entry_by_name(struct rb_root *root, 278static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
74 struct hist_entry *he) 279 struct perf_evlist *evlist)
75{ 280{
76 struct rb_node **p = &root->rb_node; 281 struct perf_evsel *e;
77 struct rb_node *parent = NULL;
78 struct hist_entry *iter;
79 282
80 while (*p != NULL) { 283 list_for_each_entry(e, &evlist->entries, node)
81 parent = *p; 284 if (perf_evsel__match2(evsel, e))
82 iter = rb_entry(parent, struct hist_entry, rb_node); 285 return e;
83 if (hist_entry__cmp(he, iter) < 0) 286
84 p = &(*p)->rb_left; 287 return NULL;
85 else 288}
86 p = &(*p)->rb_right; 289
290static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
291{
292 struct perf_evsel *evsel;
293
294 list_for_each_entry(evsel, &evlist->entries, node) {
295 struct hists *hists = &evsel->hists;
296
297 hists__collapse_resort(hists);
87 } 298 }
299}
88 300
89 rb_link_node(&he->rb_node, parent, p); 301static void hists__baseline_only(struct hists *hists)
90 rb_insert_color(&he->rb_node, root); 302{
303 struct rb_root *root;
304 struct rb_node *next;
305
306 if (sort__need_collapse)
307 root = &hists->entries_collapsed;
308 else
309 root = hists->entries_in;
310
311 next = rb_first(root);
312 while (next != NULL) {
313 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
314
315 next = rb_next(&he->rb_node_in);
316 if (!hist_entry__next_pair(he)) {
317 rb_erase(&he->rb_node_in, root);
318 hist_entry__free(he);
319 }
320 }
91} 321}
92 322
93static void hists__name_resort(struct hists *self, bool sort) 323static void hists__precompute(struct hists *hists)
94{ 324{
95 unsigned long position = 1; 325 struct rb_node *next = rb_first(&hists->entries);
96 struct rb_root tmp = RB_ROOT;
97 struct rb_node *next = rb_first(&self->entries);
98 326
99 while (next != NULL) { 327 while (next != NULL) {
100 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); 328 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node);
329 struct hist_entry *pair = hist_entry__next_pair(he);
101 330
102 next = rb_next(&n->rb_node); 331 next = rb_next(&he->rb_node);
103 n->position = position++; 332 if (!pair)
333 continue;
104 334
105 if (sort) { 335 switch (compute) {
106 rb_erase(&n->rb_node, &self->entries); 336 case COMPUTE_DELTA:
107 insert_hist_entry_by_name(&tmp, n); 337 perf_diff__compute_delta(he, pair);
338 break;
339 case COMPUTE_RATIO:
340 perf_diff__compute_ratio(he, pair);
341 break;
342 case COMPUTE_WEIGHTED_DIFF:
343 perf_diff__compute_wdiff(he, pair);
344 break;
345 default:
346 BUG_ON(1);
108 } 347 }
109 } 348 }
349}
110 350
111 if (sort) 351static int64_t cmp_doubles(double l, double r)
112 self->entries = tmp; 352{
353 if (l > r)
354 return -1;
355 else if (l < r)
356 return 1;
357 else
358 return 0;
113} 359}
114 360
115static struct hist_entry *hists__find_entry(struct hists *self, 361static int64_t
116 struct hist_entry *he) 362hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
363 int c)
117{ 364{
118 struct rb_node *n = self->entries.rb_node; 365 switch (c) {
366 case COMPUTE_DELTA:
367 {
368 double l = left->diff.period_ratio_delta;
369 double r = right->diff.period_ratio_delta;
119 370
120 while (n) { 371 return cmp_doubles(l, r);
121 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 372 }
122 int64_t cmp = hist_entry__cmp(he, iter); 373 case COMPUTE_RATIO:
374 {
375 double l = left->diff.period_ratio;
376 double r = right->diff.period_ratio;
123 377
124 if (cmp < 0) 378 return cmp_doubles(l, r);
125 n = n->rb_left;
126 else if (cmp > 0)
127 n = n->rb_right;
128 else
129 return iter;
130 } 379 }
380 case COMPUTE_WEIGHTED_DIFF:
381 {
382 s64 l = left->diff.wdiff;
383 s64 r = right->diff.wdiff;
131 384
132 return NULL; 385 return r - l;
386 }
387 default:
388 BUG_ON(1);
389 }
390
391 return 0;
133} 392}
134 393
135static void hists__match(struct hists *older, struct hists *newer) 394static void insert_hist_entry_by_compute(struct rb_root *root,
395 struct hist_entry *he,
396 int c)
136{ 397{
137 struct rb_node *nd; 398 struct rb_node **p = &root->rb_node;
399 struct rb_node *parent = NULL;
400 struct hist_entry *iter;
138 401
139 for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) { 402 while (*p != NULL) {
140 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node); 403 parent = *p;
141 pos->pair = hists__find_entry(older, pos); 404 iter = rb_entry(parent, struct hist_entry, rb_node);
405 if (hist_entry__cmp_compute(he, iter, c) < 0)
406 p = &(*p)->rb_left;
407 else
408 p = &(*p)->rb_right;
142 } 409 }
410
411 rb_link_node(&he->rb_node, parent, p);
412 rb_insert_color(&he->rb_node, root);
143} 413}
144 414
145static struct perf_evsel *evsel_match(struct perf_evsel *evsel, 415static void hists__compute_resort(struct hists *hists)
146 struct perf_evlist *evlist)
147{ 416{
148 struct perf_evsel *e; 417 struct rb_root *root;
418 struct rb_node *next;
149 419
150 list_for_each_entry(e, &evlist->entries, node) 420 if (sort__need_collapse)
151 if (perf_evsel__match2(evsel, e)) 421 root = &hists->entries_collapsed;
152 return e; 422 else
423 root = hists->entries_in;
153 424
154 return NULL; 425 hists->entries = RB_ROOT;
155} 426 next = rb_first(root);
156 427
157static void perf_evlist__resort_hists(struct perf_evlist *evlist, bool name) 428 hists->nr_entries = 0;
158{ 429 hists->stats.total_period = 0;
159 struct perf_evsel *evsel; 430 hists__reset_col_len(hists);
160 431
161 list_for_each_entry(evsel, &evlist->entries, node) { 432 while (next != NULL) {
162 struct hists *hists = &evsel->hists; 433 struct hist_entry *he;
163 434
164 hists__output_resort(hists); 435 he = rb_entry(next, struct hist_entry, rb_node_in);
436 next = rb_next(&he->rb_node_in);
165 437
166 /* 438 insert_hist_entry_by_compute(&hists->entries, he, compute);
167 * The hists__name_resort only sets possition 439 hists__inc_nr_entries(hists, he);
168 * if name is false.
169 */
170 if (name || ((!name) && show_displacement))
171 hists__name_resort(hists, name);
172 } 440 }
173} 441}
174 442
443static void hists__process(struct hists *old, struct hists *new)
444{
445 hists__match(new, old);
446
447 if (show_baseline_only)
448 hists__baseline_only(new);
449 else
450 hists__link(new, old);
451
452 if (sort_compute) {
453 hists__precompute(new);
454 hists__compute_resort(new);
455 } else {
456 hists__output_resort(new);
457 }
458
459 hists__fprintf(new, true, 0, 0, stdout);
460}
461
175static int __cmd_diff(void) 462static int __cmd_diff(void)
176{ 463{
177 int ret, i; 464 int ret, i;
@@ -198,8 +485,8 @@ static int __cmd_diff(void)
198 evlist_old = older->evlist; 485 evlist_old = older->evlist;
199 evlist_new = newer->evlist; 486 evlist_new = newer->evlist;
200 487
201 perf_evlist__resort_hists(evlist_old, true); 488 perf_evlist__collapse_resort(evlist_old);
202 perf_evlist__resort_hists(evlist_new, false); 489 perf_evlist__collapse_resort(evlist_new);
203 490
204 list_for_each_entry(evsel, &evlist_new->entries, node) { 491 list_for_each_entry(evsel, &evlist_new->entries, node) {
205 struct perf_evsel *evsel_old; 492 struct perf_evsel *evsel_old;
@@ -213,8 +500,7 @@ static int __cmd_diff(void)
213 500
214 first = false; 501 first = false;
215 502
216 hists__match(&evsel_old->hists, &evsel->hists); 503 hists__process(&evsel_old->hists, &evsel->hists);
217 hists__fprintf(&evsel->hists, true, 0, 0, stdout);
218 } 504 }
219 505
220out_delete: 506out_delete:
@@ -233,8 +519,16 @@ static const char * const diff_usage[] = {
233static const struct option options[] = { 519static const struct option options[] = {
234 OPT_INCR('v', "verbose", &verbose, 520 OPT_INCR('v', "verbose", &verbose,
235 "be more verbose (show symbol address, etc)"), 521 "be more verbose (show symbol address, etc)"),
236 OPT_BOOLEAN('M', "displacement", &show_displacement, 522 OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
237 "Show position displacement relative to baseline"), 523 "Show only items with match in baseline"),
524 OPT_CALLBACK('c', "compute", &compute,
525 "delta,ratio,wdiff:w1,w2 (default delta)",
526 "Entries differential computation selection",
527 setup_compute),
528 OPT_BOOLEAN('p', "period", &show_period,
529 "Show period values."),
530 OPT_BOOLEAN('F', "formula", &show_formula,
531 "Show formula."),
238 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 532 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
239 "dump raw trace in ASCII"), 533 "dump raw trace in ASCII"),
240 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 534 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -258,17 +552,33 @@ static const struct option options[] = {
258 552
259static void ui_init(void) 553static void ui_init(void)
260{ 554{
261 perf_hpp__init(); 555 /*
262 556 * Display baseline/delta/ratio
263 /* No overhead column. */ 557 * formula/periods columns.
264 perf_hpp__column_enable(PERF_HPP__OVERHEAD, false); 558 */
265 559 perf_hpp__column_enable(PERF_HPP__BASELINE);
266 /* Display baseline/delta/displacement columns. */ 560
267 perf_hpp__column_enable(PERF_HPP__BASELINE, true); 561 switch (compute) {
268 perf_hpp__column_enable(PERF_HPP__DELTA, true); 562 case COMPUTE_DELTA:
269 563 perf_hpp__column_enable(PERF_HPP__DELTA);
270 if (show_displacement) 564 break;
271 perf_hpp__column_enable(PERF_HPP__DISPL, true); 565 case COMPUTE_RATIO:
566 perf_hpp__column_enable(PERF_HPP__RATIO);
567 break;
568 case COMPUTE_WEIGHTED_DIFF:
569 perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
570 break;
571 default:
572 BUG_ON(1);
573 };
574
575 if (show_formula)
576 perf_hpp__column_enable(PERF_HPP__FORMULA);
577
578 if (show_period) {
579 perf_hpp__column_enable(PERF_HPP__PERIOD);
580 perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
581 }
272} 582}
273 583
274int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) 584int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
@@ -295,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
295 605
296 ui_init(); 606 ui_init();
297 607
298 setup_sorting(diff_usage, options); 608 if (setup_sorting() < 0)
609 usage_with_options(diff_usage, options);
610
299 setup_pager(); 611 setup_pager();
300 612
301 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); 613 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 997afb82691b..05bd9dfe875c 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,94 +15,17 @@
15#include "util/parse-options.h" 15#include "util/parse-options.h"
16#include "util/session.h" 16#include "util/session.h"
17 17
18struct perf_attr_details { 18static int __cmd_evlist(const char *file_name, struct perf_attr_details *details)
19 bool freq;
20 bool verbose;
21};
22
23static int comma_printf(bool *first, const char *fmt, ...)
24{
25 va_list args;
26 int ret = 0;
27
28 if (!*first) {
29 ret += printf(",");
30 } else {
31 ret += printf(":");
32 *first = false;
33 }
34
35 va_start(args, fmt);
36 ret += vprintf(fmt, args);
37 va_end(args);
38 return ret;
39}
40
41static int __if_print(bool *first, const char *field, u64 value)
42{
43 if (value == 0)
44 return 0;
45
46 return comma_printf(first, " %s: %" PRIu64, field, value);
47}
48
49#define if_print(field) __if_print(&first, #field, pos->attr.field)
50
51static int __cmd_evlist(const char *input_name, struct perf_attr_details *details)
52{ 19{
53 struct perf_session *session; 20 struct perf_session *session;
54 struct perf_evsel *pos; 21 struct perf_evsel *pos;
55 22
56 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL); 23 session = perf_session__new(file_name, O_RDONLY, 0, false, NULL);
57 if (session == NULL) 24 if (session == NULL)
58 return -ENOMEM; 25 return -ENOMEM;
59 26
60 list_for_each_entry(pos, &session->evlist->entries, node) { 27 list_for_each_entry(pos, &session->evlist->entries, node)
61 bool first = true; 28 perf_evsel__fprintf(pos, details, stdout);
62
63 printf("%s", perf_evsel__name(pos));
64
65 if (details->verbose || details->freq) {
66 comma_printf(&first, " sample_freq=%" PRIu64,
67 (u64)pos->attr.sample_freq);
68 }
69
70 if (details->verbose) {
71 if_print(type);
72 if_print(config);
73 if_print(config1);
74 if_print(config2);
75 if_print(size);
76 if_print(sample_type);
77 if_print(read_format);
78 if_print(disabled);
79 if_print(inherit);
80 if_print(pinned);
81 if_print(exclusive);
82 if_print(exclude_user);
83 if_print(exclude_kernel);
84 if_print(exclude_hv);
85 if_print(exclude_idle);
86 if_print(mmap);
87 if_print(comm);
88 if_print(freq);
89 if_print(inherit_stat);
90 if_print(enable_on_exec);
91 if_print(task);
92 if_print(watermark);
93 if_print(precise_ip);
94 if_print(mmap_data);
95 if_print(sample_id_all);
96 if_print(exclude_host);
97 if_print(exclude_guest);
98 if_print(__reserved_1);
99 if_print(wakeup_events);
100 if_print(bp_type);
101 if_print(branch_sample_type);
102 }
103
104 putchar('\n');
105 }
106 29
107 perf_session__delete(session); 30 perf_session__delete(session);
108 return 0; 31 return 0;
@@ -111,12 +34,13 @@ static int __cmd_evlist(const char *input_name, struct perf_attr_details *detail
111int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) 34int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
112{ 35{
113 struct perf_attr_details details = { .verbose = false, }; 36 struct perf_attr_details details = { .verbose = false, };
114 const char *input_name = NULL;
115 const struct option options[] = { 37 const struct option options[] = {
116 OPT_STRING('i', "input", &input_name, "file", "Input file name"), 38 OPT_STRING('i', "input", &input_name, "file", "Input file name"),
117 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), 39 OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"),
118 OPT_BOOLEAN('v', "verbose", &details.verbose, 40 OPT_BOOLEAN('v', "verbose", &details.verbose,
119 "Show all event attr details"), 41 "Show all event attr details"),
42 OPT_BOOLEAN('g', "group", &details.event_group,
43 "Show event group information"),
120 OPT_END() 44 OPT_END()
121 }; 45 };
122 const char * const evlist_usage[] = { 46 const char * const evlist_usage[] = {
@@ -128,5 +52,10 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
128 if (argc) 52 if (argc)
129 usage_with_options(evlist_usage, options); 53 usage_with_options(evlist_usage, options);
130 54
55 if (details.event_group && (details.verbose || details.freq)) {
56 pr_err("--group option is not compatible with other options\n");
57 usage_with_options(evlist_usage, options);
58 }
59
131 return __cmd_evlist(input_name, &details); 60 return __cmd_evlist(input_name, &details);
132} 61}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 4688bea95c12..84ad6abe4258 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -8,33 +8,53 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "perf.h" 10#include "perf.h"
11#include "util/color.h"
12#include "util/evlist.h"
13#include "util/evsel.h"
11#include "util/session.h" 14#include "util/session.h"
12#include "util/tool.h" 15#include "util/tool.h"
13#include "util/debug.h" 16#include "util/debug.h"
17#include "util/build-id.h"
14 18
15#include "util/parse-options.h" 19#include "util/parse-options.h"
16 20
21#include <linux/list.h>
22
17struct perf_inject { 23struct perf_inject {
18 struct perf_tool tool; 24 struct perf_tool tool;
19 bool build_ids; 25 bool build_ids;
26 bool sched_stat;
27 const char *input_name;
28 int pipe_output,
29 output;
30 u64 bytes_written;
31 struct list_head samples;
32};
33
34struct event_entry {
35 struct list_head node;
36 u32 tid;
37 union perf_event event[0];
20}; 38};
21 39
22static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused, 40static int perf_event__repipe_synth(struct perf_tool *tool,
23 union perf_event *event, 41 union perf_event *event,
24 struct machine *machine __maybe_unused) 42 struct machine *machine __maybe_unused)
25{ 43{
44 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
26 uint32_t size; 45 uint32_t size;
27 void *buf = event; 46 void *buf = event;
28 47
29 size = event->header.size; 48 size = event->header.size;
30 49
31 while (size) { 50 while (size) {
32 int ret = write(STDOUT_FILENO, buf, size); 51 int ret = write(inject->output, buf, size);
33 if (ret < 0) 52 if (ret < 0)
34 return -errno; 53 return -errno;
35 54
36 size -= ret; 55 size -= ret;
37 buf += ret; 56 buf += ret;
57 inject->bytes_written += ret;
38 } 58 }
39 59
40 return 0; 60 return 0;
@@ -80,12 +100,25 @@ static int perf_event__repipe(struct perf_tool *tool,
80 return perf_event__repipe_synth(tool, event, machine); 100 return perf_event__repipe_synth(tool, event, machine);
81} 101}
82 102
103typedef int (*inject_handler)(struct perf_tool *tool,
104 union perf_event *event,
105 struct perf_sample *sample,
106 struct perf_evsel *evsel,
107 struct machine *machine);
108
83static int perf_event__repipe_sample(struct perf_tool *tool, 109static int perf_event__repipe_sample(struct perf_tool *tool,
84 union perf_event *event, 110 union perf_event *event,
85 struct perf_sample *sample __maybe_unused, 111 struct perf_sample *sample,
86 struct perf_evsel *evsel __maybe_unused, 112 struct perf_evsel *evsel,
87 struct machine *machine) 113 struct machine *machine)
88{ 114{
115 if (evsel->handler.func) {
116 inject_handler f = evsel->handler.func;
117 return f(tool, event, sample, evsel, machine);
118 }
119
120 build_id__mark_dso_hit(tool, event, sample, evsel, machine);
121
89 return perf_event__repipe_synth(tool, event, machine); 122 return perf_event__repipe_synth(tool, event, machine);
90} 123}
91 124
@@ -102,14 +135,14 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
102 return err; 135 return err;
103} 136}
104 137
105static int perf_event__repipe_task(struct perf_tool *tool, 138static int perf_event__repipe_fork(struct perf_tool *tool,
106 union perf_event *event, 139 union perf_event *event,
107 struct perf_sample *sample, 140 struct perf_sample *sample,
108 struct machine *machine) 141 struct machine *machine)
109{ 142{
110 int err; 143 int err;
111 144
112 err = perf_event__process_task(tool, event, sample, machine); 145 err = perf_event__process_fork(tool, event, sample, machine);
113 perf_event__repipe(tool, event, sample, machine); 146 perf_event__repipe(tool, event, sample, machine);
114 147
115 return err; 148 return err;
@@ -210,6 +243,80 @@ repipe:
210 return 0; 243 return 0;
211} 244}
212 245
246static int perf_inject__sched_process_exit(struct perf_tool *tool,
247 union perf_event *event __maybe_unused,
248 struct perf_sample *sample,
249 struct perf_evsel *evsel __maybe_unused,
250 struct machine *machine __maybe_unused)
251{
252 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
253 struct event_entry *ent;
254
255 list_for_each_entry(ent, &inject->samples, node) {
256 if (sample->tid == ent->tid) {
257 list_del_init(&ent->node);
258 free(ent);
259 break;
260 }
261 }
262
263 return 0;
264}
265
266static int perf_inject__sched_switch(struct perf_tool *tool,
267 union perf_event *event,
268 struct perf_sample *sample,
269 struct perf_evsel *evsel,
270 struct machine *machine)
271{
272 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
273 struct event_entry *ent;
274
275 perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
276
277 ent = malloc(event->header.size + sizeof(struct event_entry));
278 if (ent == NULL) {
279 color_fprintf(stderr, PERF_COLOR_RED,
280 "Not enough memory to process sched switch event!");
281 return -1;
282 }
283
284 ent->tid = sample->tid;
285 memcpy(&ent->event, event, event->header.size);
286 list_add(&ent->node, &inject->samples);
287 return 0;
288}
289
290static int perf_inject__sched_stat(struct perf_tool *tool,
291 union perf_event *event __maybe_unused,
292 struct perf_sample *sample,
293 struct perf_evsel *evsel,
294 struct machine *machine)
295{
296 struct event_entry *ent;
297 union perf_event *event_sw;
298 struct perf_sample sample_sw;
299 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
300 u32 pid = perf_evsel__intval(evsel, sample, "pid");
301
302 list_for_each_entry(ent, &inject->samples, node) {
303 if (pid == ent->tid)
304 goto found;
305 }
306
307 return 0;
308found:
309 event_sw = &ent->event[0];
310 perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
311
312 sample_sw.period = sample->period;
313 sample_sw.time = sample->time;
314 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
315 &sample_sw, false);
316 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
317 return perf_event__repipe(tool, event_sw, &sample_sw, machine);
318}
319
213extern volatile int session_done; 320extern volatile int session_done;
214 321
215static void sig_handler(int sig __maybe_unused) 322static void sig_handler(int sig __maybe_unused)
@@ -217,6 +324,21 @@ static void sig_handler(int sig __maybe_unused)
217 session_done = 1; 324 session_done = 1;
218} 325}
219 326
327static int perf_evsel__check_stype(struct perf_evsel *evsel,
328 u64 sample_type, const char *sample_msg)
329{
330 struct perf_event_attr *attr = &evsel->attr;
331 const char *name = perf_evsel__name(evsel);
332
333 if (!(attr->sample_type & sample_type)) {
334 pr_err("Samples for %s event do not have %s attribute set.",
335 name, sample_msg);
336 return -EINVAL;
337 }
338
339 return 0;
340}
341
220static int __cmd_inject(struct perf_inject *inject) 342static int __cmd_inject(struct perf_inject *inject)
221{ 343{
222 struct perf_session *session; 344 struct perf_session *session;
@@ -224,19 +346,48 @@ static int __cmd_inject(struct perf_inject *inject)
224 346
225 signal(SIGINT, sig_handler); 347 signal(SIGINT, sig_handler);
226 348
227 if (inject->build_ids) { 349 if (inject->build_ids || inject->sched_stat) {
228 inject->tool.sample = perf_event__inject_buildid;
229 inject->tool.mmap = perf_event__repipe_mmap; 350 inject->tool.mmap = perf_event__repipe_mmap;
230 inject->tool.fork = perf_event__repipe_task; 351 inject->tool.fork = perf_event__repipe_fork;
231 inject->tool.tracing_data = perf_event__repipe_tracing_data; 352 inject->tool.tracing_data = perf_event__repipe_tracing_data;
232 } 353 }
233 354
234 session = perf_session__new("-", O_RDONLY, false, true, &inject->tool); 355 session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool);
235 if (session == NULL) 356 if (session == NULL)
236 return -ENOMEM; 357 return -ENOMEM;
237 358
359 if (inject->build_ids) {
360 inject->tool.sample = perf_event__inject_buildid;
361 } else if (inject->sched_stat) {
362 struct perf_evsel *evsel;
363
364 inject->tool.ordered_samples = true;
365
366 list_for_each_entry(evsel, &session->evlist->entries, node) {
367 const char *name = perf_evsel__name(evsel);
368
369 if (!strcmp(name, "sched:sched_switch")) {
370 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
371 return -EINVAL;
372
373 evsel->handler.func = perf_inject__sched_switch;
374 } else if (!strcmp(name, "sched:sched_process_exit"))
375 evsel->handler.func = perf_inject__sched_process_exit;
376 else if (!strncmp(name, "sched:sched_stat_", 17))
377 evsel->handler.func = perf_inject__sched_stat;
378 }
379 }
380
381 if (!inject->pipe_output)
382 lseek(inject->output, session->header.data_offset, SEEK_SET);
383
238 ret = perf_session__process_events(session, &inject->tool); 384 ret = perf_session__process_events(session, &inject->tool);
239 385
386 if (!inject->pipe_output) {
387 session->header.data_size = inject->bytes_written;
388 perf_session__write_header(session, session->evlist, inject->output, true);
389 }
390
240 perf_session__delete(session); 391 perf_session__delete(session);
241 392
242 return ret; 393 return ret;
@@ -260,10 +411,20 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
260 .tracing_data = perf_event__repipe_tracing_data_synth, 411 .tracing_data = perf_event__repipe_tracing_data_synth,
261 .build_id = perf_event__repipe_op2_synth, 412 .build_id = perf_event__repipe_op2_synth,
262 }, 413 },
414 .input_name = "-",
415 .samples = LIST_HEAD_INIT(inject.samples),
263 }; 416 };
417 const char *output_name = "-";
264 const struct option options[] = { 418 const struct option options[] = {
265 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 419 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
266 "Inject build-ids into the output stream"), 420 "Inject build-ids into the output stream"),
421 OPT_STRING('i', "input", &inject.input_name, "file",
422 "input file name"),
423 OPT_STRING('o', "output", &output_name, "file",
424 "output file name"),
425 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
426 "Merge sched-stat and sched-switch for getting events "
427 "where and how long tasks slept"),
267 OPT_INCR('v', "verbose", &verbose, 428 OPT_INCR('v', "verbose", &verbose,
268 "be more verbose (show build ids, etc)"), 429 "be more verbose (show build ids, etc)"),
269 OPT_END() 430 OPT_END()
@@ -281,6 +442,18 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
281 if (argc) 442 if (argc)
282 usage_with_options(inject_usage, options); 443 usage_with_options(inject_usage, options);
283 444
445 if (!strcmp(output_name, "-")) {
446 inject.pipe_output = 1;
447 inject.output = STDOUT_FILENO;
448 } else {
449 inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC,
450 S_IRUSR | S_IWUSR);
451 if (inject.output < 0) {
452 perror("failed to create output file");
453 return -1;
454 }
455 }
456
284 if (symbol__init() < 0) 457 if (symbol__init() < 0)
285 return -1; 458 return -1;
286 459
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 14bf82f63659..46878daca5cc 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -17,6 +17,7 @@
17#include "util/debug.h" 17#include "util/debug.h"
18 18
19#include <linux/rbtree.h> 19#include <linux/rbtree.h>
20#include <linux/string.h>
20 21
21struct alloc_stat; 22struct alloc_stat;
22typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); 23typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
@@ -340,7 +341,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
340 int n_lines, int is_caller) 341 int n_lines, int is_caller)
341{ 342{
342 struct rb_node *next; 343 struct rb_node *next;
343 struct machine *machine; 344 struct machine *machine = &session->machines.host;
344 345
345 printf("%.102s\n", graph_dotted_line); 346 printf("%.102s\n", graph_dotted_line);
346 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 347 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
@@ -349,11 +350,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
349 350
350 next = rb_first(root); 351 next = rb_first(root);
351 352
352 machine = perf_session__find_host_machine(session);
353 if (!machine) {
354 pr_err("__print_result: couldn't find kernel information\n");
355 return;
356 }
357 while (next && n_lines--) { 353 while (next && n_lines--) {
358 struct alloc_stat *data = rb_entry(next, struct alloc_stat, 354 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
359 node); 355 node);
@@ -477,7 +473,7 @@ static void sort_result(void)
477 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); 473 __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort);
478} 474}
479 475
480static int __cmd_kmem(const char *input_name) 476static int __cmd_kmem(void)
481{ 477{
482 int err = -EINVAL; 478 int err = -EINVAL;
483 struct perf_session *session; 479 struct perf_session *session;
@@ -614,8 +610,7 @@ static struct sort_dimension *avail_sorts[] = {
614 &pingpong_sort_dimension, 610 &pingpong_sort_dimension,
615}; 611};
616 612
617#define NUM_AVAIL_SORTS \ 613#define NUM_AVAIL_SORTS ((int)ARRAY_SIZE(avail_sorts))
618 (int)(sizeof(avail_sorts) / sizeof(struct sort_dimension *))
619 614
620static int sort_dimension__add(const char *tok, struct list_head *list) 615static int sort_dimension__add(const char *tok, struct list_head *list)
621{ 616{
@@ -624,12 +619,11 @@ static int sort_dimension__add(const char *tok, struct list_head *list)
624 619
625 for (i = 0; i < NUM_AVAIL_SORTS; i++) { 620 for (i = 0; i < NUM_AVAIL_SORTS; i++) {
626 if (!strcmp(avail_sorts[i]->name, tok)) { 621 if (!strcmp(avail_sorts[i]->name, tok)) {
627 sort = malloc(sizeof(*sort)); 622 sort = memdup(avail_sorts[i], sizeof(*avail_sorts[i]));
628 if (!sort) { 623 if (!sort) {
629 pr_err("%s: malloc failed\n", __func__); 624 pr_err("%s: memdup failed\n", __func__);
630 return -1; 625 return -1;
631 } 626 }
632 memcpy(sort, avail_sorts[i], sizeof(*sort));
633 list_add_tail(&sort->list, list); 627 list_add_tail(&sort->list, list);
634 return 0; 628 return 0;
635 } 629 }
@@ -743,7 +737,6 @@ static int __cmd_record(int argc, const char **argv)
743int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) 737int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
744{ 738{
745 const char * const default_sort_order = "frag,hit,bytes"; 739 const char * const default_sort_order = "frag,hit,bytes";
746 const char *input_name = NULL;
747 const struct option kmem_options[] = { 740 const struct option kmem_options[] = {
748 OPT_STRING('i', "input", &input_name, "file", "input file name"), 741 OPT_STRING('i', "input", &input_name, "file", "input file name"),
749 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL, 742 OPT_CALLBACK_NOOPT(0, "caller", NULL, NULL,
@@ -779,7 +772,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
779 if (list_empty(&alloc_sort)) 772 if (list_empty(&alloc_sort))
780 setup_sorting(&alloc_sort, default_sort_order); 773 setup_sorting(&alloc_sort, default_sort_order);
781 774
782 return __cmd_kmem(input_name); 775 return __cmd_kmem();
783 } else 776 } else
784 usage_with_options(kmem_usage, kmem_options); 777 usage_with_options(kmem_usage, kmem_options);
785 778
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 260abc535b5b..37a769d7f9fe 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -22,9 +22,10 @@
22#include <pthread.h> 22#include <pthread.h>
23#include <math.h> 23#include <math.h>
24 24
25#include "../../arch/x86/include/asm/svm.h" 25#if defined(__i386__) || defined(__x86_64__)
26#include "../../arch/x86/include/asm/vmx.h" 26#include <asm/svm.h>
27#include "../../arch/x86/include/asm/kvm.h" 27#include <asm/vmx.h>
28#include <asm/kvm.h>
28 29
29struct event_key { 30struct event_key {
30 #define INVALID_KEY (~0ULL) 31 #define INVALID_KEY (~0ULL)
@@ -58,7 +59,7 @@ struct kvm_event_key {
58}; 59};
59 60
60 61
61struct perf_kvm; 62struct perf_kvm_stat;
62 63
63struct kvm_events_ops { 64struct kvm_events_ops {
64 bool (*is_begin_event)(struct perf_evsel *evsel, 65 bool (*is_begin_event)(struct perf_evsel *evsel,
@@ -66,7 +67,7 @@ struct kvm_events_ops {
66 struct event_key *key); 67 struct event_key *key);
67 bool (*is_end_event)(struct perf_evsel *evsel, 68 bool (*is_end_event)(struct perf_evsel *evsel,
68 struct perf_sample *sample, struct event_key *key); 69 struct perf_sample *sample, struct event_key *key);
69 void (*decode_key)(struct perf_kvm *kvm, struct event_key *key, 70 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
70 char decode[20]); 71 char decode[20]);
71 const char *name; 72 const char *name;
72}; 73};
@@ -79,7 +80,7 @@ struct exit_reasons_table {
79#define EVENTS_BITS 12 80#define EVENTS_BITS 12
80#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) 81#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
81 82
82struct perf_kvm { 83struct perf_kvm_stat {
83 struct perf_tool tool; 84 struct perf_tool tool;
84 struct perf_session *session; 85 struct perf_session *session;
85 86
@@ -146,7 +147,7 @@ static struct exit_reasons_table svm_exit_reasons[] = {
146 SVM_EXIT_REASONS 147 SVM_EXIT_REASONS
147}; 148};
148 149
149static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code) 150static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
150{ 151{
151 int i = kvm->exit_reasons_size; 152 int i = kvm->exit_reasons_size;
152 struct exit_reasons_table *tbl = kvm->exit_reasons; 153 struct exit_reasons_table *tbl = kvm->exit_reasons;
@@ -162,7 +163,7 @@ static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code)
162 return "UNKNOWN"; 163 return "UNKNOWN";
163} 164}
164 165
165static void exit_event_decode_key(struct perf_kvm *kvm, 166static void exit_event_decode_key(struct perf_kvm_stat *kvm,
166 struct event_key *key, 167 struct event_key *key,
167 char decode[20]) 168 char decode[20])
168{ 169{
@@ -228,7 +229,7 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
228 return false; 229 return false;
229} 230}
230 231
231static void mmio_event_decode_key(struct perf_kvm *kvm __maybe_unused, 232static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
232 struct event_key *key, 233 struct event_key *key,
233 char decode[20]) 234 char decode[20])
234{ 235{
@@ -271,7 +272,7 @@ static bool ioport_event_end(struct perf_evsel *evsel,
271 return kvm_entry_event(evsel); 272 return kvm_entry_event(evsel);
272} 273}
273 274
274static void ioport_event_decode_key(struct perf_kvm *kvm __maybe_unused, 275static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
275 struct event_key *key, 276 struct event_key *key,
276 char decode[20]) 277 char decode[20])
277{ 278{
@@ -286,7 +287,7 @@ static struct kvm_events_ops ioport_events = {
286 .name = "IO Port Access" 287 .name = "IO Port Access"
287}; 288};
288 289
289static bool register_kvm_events_ops(struct perf_kvm *kvm) 290static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
290{ 291{
291 bool ret = true; 292 bool ret = true;
292 293
@@ -311,11 +312,11 @@ struct vcpu_event_record {
311}; 312};
312 313
313 314
314static void init_kvm_event_record(struct perf_kvm *kvm) 315static void init_kvm_event_record(struct perf_kvm_stat *kvm)
315{ 316{
316 int i; 317 unsigned int i;
317 318
318 for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) 319 for (i = 0; i < EVENTS_CACHE_SIZE; i++)
319 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); 320 INIT_LIST_HEAD(&kvm->kvm_events_cache[i]);
320} 321}
321 322
@@ -360,7 +361,7 @@ static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
360 return event; 361 return event;
361} 362}
362 363
363static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm, 364static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
364 struct event_key *key) 365 struct event_key *key)
365{ 366{
366 struct kvm_event *event; 367 struct kvm_event *event;
@@ -369,9 +370,10 @@ static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,
369 BUG_ON(key->key == INVALID_KEY); 370 BUG_ON(key->key == INVALID_KEY);
370 371
371 head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)]; 372 head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)];
372 list_for_each_entry(event, head, hash_entry) 373 list_for_each_entry(event, head, hash_entry) {
373 if (event->key.key == key->key && event->key.info == key->info) 374 if (event->key.key == key->key && event->key.info == key->info)
374 return event; 375 return event;
376 }
375 377
376 event = kvm_alloc_init_event(key); 378 event = kvm_alloc_init_event(key);
377 if (!event) 379 if (!event)
@@ -381,7 +383,7 @@ static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,
381 return event; 383 return event;
382} 384}
383 385
384static bool handle_begin_event(struct perf_kvm *kvm, 386static bool handle_begin_event(struct perf_kvm_stat *kvm,
385 struct vcpu_event_record *vcpu_record, 387 struct vcpu_event_record *vcpu_record,
386 struct event_key *key, u64 timestamp) 388 struct event_key *key, u64 timestamp)
387{ 389{
@@ -416,7 +418,10 @@ static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)
416static bool update_kvm_event(struct kvm_event *event, int vcpu_id, 418static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
417 u64 time_diff) 419 u64 time_diff)
418{ 420{
419 kvm_update_event_stats(&event->total, time_diff); 421 if (vcpu_id == -1) {
422 kvm_update_event_stats(&event->total, time_diff);
423 return true;
424 }
420 425
421 if (!kvm_event_expand(event, vcpu_id)) 426 if (!kvm_event_expand(event, vcpu_id))
422 return false; 427 return false;
@@ -425,13 +430,19 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
425 return true; 430 return true;
426} 431}
427 432
428static bool handle_end_event(struct perf_kvm *kvm, 433static bool handle_end_event(struct perf_kvm_stat *kvm,
429 struct vcpu_event_record *vcpu_record, 434 struct vcpu_event_record *vcpu_record,
430 struct event_key *key, 435 struct event_key *key,
431 u64 timestamp) 436 u64 timestamp)
432{ 437{
433 struct kvm_event *event; 438 struct kvm_event *event;
434 u64 time_begin, time_diff; 439 u64 time_begin, time_diff;
440 int vcpu;
441
442 if (kvm->trace_vcpu == -1)
443 vcpu = -1;
444 else
445 vcpu = vcpu_record->vcpu_id;
435 446
436 event = vcpu_record->last_event; 447 event = vcpu_record->last_event;
437 time_begin = vcpu_record->start_time; 448 time_begin = vcpu_record->start_time;
@@ -461,7 +472,7 @@ static bool handle_end_event(struct perf_kvm *kvm,
461 BUG_ON(timestamp < time_begin); 472 BUG_ON(timestamp < time_begin);
462 473
463 time_diff = timestamp - time_begin; 474 time_diff = timestamp - time_begin;
464 return update_kvm_event(event, vcpu_record->vcpu_id, time_diff); 475 return update_kvm_event(event, vcpu, time_diff);
465} 476}
466 477
467static 478static
@@ -486,7 +497,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
486 return thread->priv; 497 return thread->priv;
487} 498}
488 499
489static bool handle_kvm_event(struct perf_kvm *kvm, 500static bool handle_kvm_event(struct perf_kvm_stat *kvm,
490 struct thread *thread, 501 struct thread *thread,
491 struct perf_evsel *evsel, 502 struct perf_evsel *evsel,
492 struct perf_sample *sample) 503 struct perf_sample *sample)
@@ -498,6 +509,11 @@ static bool handle_kvm_event(struct perf_kvm *kvm,
498 if (!vcpu_record) 509 if (!vcpu_record)
499 return true; 510 return true;
500 511
512 /* only process events for vcpus user cares about */
513 if ((kvm->trace_vcpu != -1) &&
514 (kvm->trace_vcpu != vcpu_record->vcpu_id))
515 return true;
516
501 if (kvm->events_ops->is_begin_event(evsel, sample, &key)) 517 if (kvm->events_ops->is_begin_event(evsel, sample, &key))
502 return handle_begin_event(kvm, vcpu_record, &key, sample->time); 518 return handle_begin_event(kvm, vcpu_record, &key, sample->time);
503 519
@@ -541,7 +557,7 @@ static struct kvm_event_key keys[] = {
541 { NULL, NULL } 557 { NULL, NULL }
542}; 558};
543 559
544static bool select_key(struct perf_kvm *kvm) 560static bool select_key(struct perf_kvm_stat *kvm)
545{ 561{
546 int i; 562 int i;
547 563
@@ -577,7 +593,8 @@ static void insert_to_result(struct rb_root *result, struct kvm_event *event,
577 rb_insert_color(&event->rb, result); 593 rb_insert_color(&event->rb, result);
578} 594}
579 595
580static void update_total_count(struct perf_kvm *kvm, struct kvm_event *event) 596static void
597update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)
581{ 598{
582 int vcpu = kvm->trace_vcpu; 599 int vcpu = kvm->trace_vcpu;
583 600
@@ -590,19 +607,21 @@ static bool event_is_valid(struct kvm_event *event, int vcpu)
590 return !!get_event_count(event, vcpu); 607 return !!get_event_count(event, vcpu);
591} 608}
592 609
593static void sort_result(struct perf_kvm *kvm) 610static void sort_result(struct perf_kvm_stat *kvm)
594{ 611{
595 unsigned int i; 612 unsigned int i;
596 int vcpu = kvm->trace_vcpu; 613 int vcpu = kvm->trace_vcpu;
597 struct kvm_event *event; 614 struct kvm_event *event;
598 615
599 for (i = 0; i < EVENTS_CACHE_SIZE; i++) 616 for (i = 0; i < EVENTS_CACHE_SIZE; i++) {
600 list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) 617 list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) {
601 if (event_is_valid(event, vcpu)) { 618 if (event_is_valid(event, vcpu)) {
602 update_total_count(kvm, event); 619 update_total_count(kvm, event);
603 insert_to_result(&kvm->result, event, 620 insert_to_result(&kvm->result, event,
604 kvm->compare, vcpu); 621 kvm->compare, vcpu);
605 } 622 }
623 }
624 }
606} 625}
607 626
608/* returns left most element of result, and erase it */ 627/* returns left most element of result, and erase it */
@@ -627,7 +646,7 @@ static void print_vcpu_info(int vcpu)
627 pr_info("VCPU %d:\n\n", vcpu); 646 pr_info("VCPU %d:\n\n", vcpu);
628} 647}
629 648
630static void print_result(struct perf_kvm *kvm) 649static void print_result(struct perf_kvm_stat *kvm)
631{ 650{
632 char decode[20]; 651 char decode[20];
633 struct kvm_event *event; 652 struct kvm_event *event;
@@ -659,8 +678,8 @@ static void print_result(struct perf_kvm *kvm)
659 pr_info("\n"); 678 pr_info("\n");
660 } 679 }
661 680
662 pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", 681 pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",
663 (unsigned long long)kvm->total_count, kvm->total_time / 1e3); 682 kvm->total_count, kvm->total_time / 1e3);
664} 683}
665 684
666static int process_sample_event(struct perf_tool *tool, 685static int process_sample_event(struct perf_tool *tool,
@@ -670,7 +689,8 @@ static int process_sample_event(struct perf_tool *tool,
670 struct machine *machine) 689 struct machine *machine)
671{ 690{
672 struct thread *thread = machine__findnew_thread(machine, sample->tid); 691 struct thread *thread = machine__findnew_thread(machine, sample->tid);
673 struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool); 692 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
693 tool);
674 694
675 if (thread == NULL) { 695 if (thread == NULL) {
676 pr_debug("problem processing %d event, skipping it.\n", 696 pr_debug("problem processing %d event, skipping it.\n",
@@ -701,7 +721,7 @@ static int get_cpu_isa(struct perf_session *session)
701 return isa; 721 return isa;
702} 722}
703 723
704static int read_events(struct perf_kvm *kvm) 724static int read_events(struct perf_kvm_stat *kvm)
705{ 725{
706 int ret; 726 int ret;
707 727
@@ -750,7 +770,7 @@ static bool verify_vcpu(int vcpu)
750 return true; 770 return true;
751} 771}
752 772
753static int kvm_events_report_vcpu(struct perf_kvm *kvm) 773static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
754{ 774{
755 int ret = -EINVAL; 775 int ret = -EINVAL;
756 int vcpu = kvm->trace_vcpu; 776 int vcpu = kvm->trace_vcpu;
@@ -798,7 +818,8 @@ static const char * const record_args[] = {
798 _p; \ 818 _p; \
799 }) 819 })
800 820
801static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv) 821static int
822kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
802{ 823{
803 unsigned int rec_argc, i, j; 824 unsigned int rec_argc, i, j;
804 const char **rec_argv; 825 const char **rec_argv;
@@ -821,7 +842,8 @@ static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv)
821 return cmd_record(i, rec_argv, NULL); 842 return cmd_record(i, rec_argv, NULL);
822} 843}
823 844
824static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv) 845static int
846kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
825{ 847{
826 const struct option kvm_events_report_options[] = { 848 const struct option kvm_events_report_options[] = {
827 OPT_STRING(0, "event", &kvm->report_event, "report event", 849 OPT_STRING(0, "event", &kvm->report_event, "report event",
@@ -864,24 +886,37 @@ static void print_kvm_stat_usage(void)
864 printf("\nOtherwise, it is the alias of 'perf stat':\n"); 886 printf("\nOtherwise, it is the alias of 'perf stat':\n");
865} 887}
866 888
867static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv) 889static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
868{ 890{
891 struct perf_kvm_stat kvm = {
892 .file_name = file_name,
893
894 .trace_vcpu = -1,
895 .report_event = "vmexit",
896 .sort_key = "sample",
897
898 .exit_reasons = svm_exit_reasons,
899 .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
900 .exit_reasons_isa = "SVM",
901 };
902
869 if (argc == 1) { 903 if (argc == 1) {
870 print_kvm_stat_usage(); 904 print_kvm_stat_usage();
871 goto perf_stat; 905 goto perf_stat;
872 } 906 }
873 907
874 if (!strncmp(argv[1], "rec", 3)) 908 if (!strncmp(argv[1], "rec", 3))
875 return kvm_events_record(kvm, argc - 1, argv + 1); 909 return kvm_events_record(&kvm, argc - 1, argv + 1);
876 910
877 if (!strncmp(argv[1], "rep", 3)) 911 if (!strncmp(argv[1], "rep", 3))
878 return kvm_events_report(kvm, argc - 1 , argv + 1); 912 return kvm_events_report(&kvm, argc - 1 , argv + 1);
879 913
880perf_stat: 914perf_stat:
881 return cmd_stat(argc, argv, NULL); 915 return cmd_stat(argc, argv, NULL);
882} 916}
917#endif
883 918
884static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv) 919static int __cmd_record(const char *file_name, int argc, const char **argv)
885{ 920{
886 int rec_argc, i = 0, j; 921 int rec_argc, i = 0, j;
887 const char **rec_argv; 922 const char **rec_argv;
@@ -890,7 +925,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
890 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 925 rec_argv = calloc(rec_argc + 1, sizeof(char *));
891 rec_argv[i++] = strdup("record"); 926 rec_argv[i++] = strdup("record");
892 rec_argv[i++] = strdup("-o"); 927 rec_argv[i++] = strdup("-o");
893 rec_argv[i++] = strdup(kvm->file_name); 928 rec_argv[i++] = strdup(file_name);
894 for (j = 1; j < argc; j++, i++) 929 for (j = 1; j < argc; j++, i++)
895 rec_argv[i] = argv[j]; 930 rec_argv[i] = argv[j];
896 931
@@ -899,7 +934,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
899 return cmd_record(i, rec_argv, NULL); 934 return cmd_record(i, rec_argv, NULL);
900} 935}
901 936
902static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv) 937static int __cmd_report(const char *file_name, int argc, const char **argv)
903{ 938{
904 int rec_argc, i = 0, j; 939 int rec_argc, i = 0, j;
905 const char **rec_argv; 940 const char **rec_argv;
@@ -908,7 +943,7 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
908 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 943 rec_argv = calloc(rec_argc + 1, sizeof(char *));
909 rec_argv[i++] = strdup("report"); 944 rec_argv[i++] = strdup("report");
910 rec_argv[i++] = strdup("-i"); 945 rec_argv[i++] = strdup("-i");
911 rec_argv[i++] = strdup(kvm->file_name); 946 rec_argv[i++] = strdup(file_name);
912 for (j = 1; j < argc; j++, i++) 947 for (j = 1; j < argc; j++, i++)
913 rec_argv[i] = argv[j]; 948 rec_argv[i] = argv[j];
914 949
@@ -917,7 +952,8 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
917 return cmd_report(i, rec_argv, NULL); 952 return cmd_report(i, rec_argv, NULL);
918} 953}
919 954
920static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv) 955static int
956__cmd_buildid_list(const char *file_name, int argc, const char **argv)
921{ 957{
922 int rec_argc, i = 0, j; 958 int rec_argc, i = 0, j;
923 const char **rec_argv; 959 const char **rec_argv;
@@ -926,7 +962,7 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
926 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 962 rec_argv = calloc(rec_argc + 1, sizeof(char *));
927 rec_argv[i++] = strdup("buildid-list"); 963 rec_argv[i++] = strdup("buildid-list");
928 rec_argv[i++] = strdup("-i"); 964 rec_argv[i++] = strdup("-i");
929 rec_argv[i++] = strdup(kvm->file_name); 965 rec_argv[i++] = strdup(file_name);
930 for (j = 1; j < argc; j++, i++) 966 for (j = 1; j < argc; j++, i++)
931 rec_argv[i] = argv[j]; 967 rec_argv[i] = argv[j];
932 968
@@ -937,20 +973,11 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
937 973
938int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) 974int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
939{ 975{
940 struct perf_kvm kvm = { 976 const char *file_name = NULL;
941 .trace_vcpu = -1,
942 .report_event = "vmexit",
943 .sort_key = "sample",
944
945 .exit_reasons = svm_exit_reasons,
946 .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
947 .exit_reasons_isa = "SVM",
948 };
949
950 const struct option kvm_options[] = { 977 const struct option kvm_options[] = {
951 OPT_STRING('i', "input", &kvm.file_name, "file", 978 OPT_STRING('i', "input", &file_name, "file",
952 "Input file name"), 979 "Input file name"),
953 OPT_STRING('o', "output", &kvm.file_name, "file", 980 OPT_STRING('o', "output", &file_name, "file",
954 "Output file name"), 981 "Output file name"),
955 OPT_BOOLEAN(0, "guest", &perf_guest, 982 OPT_BOOLEAN(0, "guest", &perf_guest,
956 "Collect guest os data"), 983 "Collect guest os data"),
@@ -985,32 +1012,34 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
985 if (!perf_host) 1012 if (!perf_host)
986 perf_guest = 1; 1013 perf_guest = 1;
987 1014
988 if (!kvm.file_name) { 1015 if (!file_name) {
989 if (perf_host && !perf_guest) 1016 if (perf_host && !perf_guest)
990 kvm.file_name = strdup("perf.data.host"); 1017 file_name = strdup("perf.data.host");
991 else if (!perf_host && perf_guest) 1018 else if (!perf_host && perf_guest)
992 kvm.file_name = strdup("perf.data.guest"); 1019 file_name = strdup("perf.data.guest");
993 else 1020 else
994 kvm.file_name = strdup("perf.data.kvm"); 1021 file_name = strdup("perf.data.kvm");
995 1022
996 if (!kvm.file_name) { 1023 if (!file_name) {
997 pr_err("Failed to allocate memory for filename\n"); 1024 pr_err("Failed to allocate memory for filename\n");
998 return -ENOMEM; 1025 return -ENOMEM;
999 } 1026 }
1000 } 1027 }
1001 1028
1002 if (!strncmp(argv[0], "rec", 3)) 1029 if (!strncmp(argv[0], "rec", 3))
1003 return __cmd_record(&kvm, argc, argv); 1030 return __cmd_record(file_name, argc, argv);
1004 else if (!strncmp(argv[0], "rep", 3)) 1031 else if (!strncmp(argv[0], "rep", 3))
1005 return __cmd_report(&kvm, argc, argv); 1032 return __cmd_report(file_name, argc, argv);
1006 else if (!strncmp(argv[0], "diff", 4)) 1033 else if (!strncmp(argv[0], "diff", 4))
1007 return cmd_diff(argc, argv, NULL); 1034 return cmd_diff(argc, argv, NULL);
1008 else if (!strncmp(argv[0], "top", 3)) 1035 else if (!strncmp(argv[0], "top", 3))
1009 return cmd_top(argc, argv, NULL); 1036 return cmd_top(argc, argv, NULL);
1010 else if (!strncmp(argv[0], "buildid-list", 12)) 1037 else if (!strncmp(argv[0], "buildid-list", 12))
1011 return __cmd_buildid_list(&kvm, argc, argv); 1038 return __cmd_buildid_list(file_name, argc, argv);
1039#if defined(__i386__) || defined(__x86_64__)
1012 else if (!strncmp(argv[0], "stat", 4)) 1040 else if (!strncmp(argv[0], "stat", 4))
1013 return kvm_cmd_stat(&kvm, argc, argv); 1041 return kvm_cmd_stat(file_name, argc, argv);
1042#endif
1014 else 1043 else
1015 usage_with_options(kvm_usage, kvm_options); 1044 usage_with_options(kvm_usage, kvm_options);
1016 1045
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 6f5f328157aa..425830069749 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -335,8 +335,6 @@ alloc_failed:
335 return NULL; 335 return NULL;
336} 336}
337 337
338static const char *input_name;
339
340struct trace_lock_handler { 338struct trace_lock_handler {
341 int (*acquire_event)(struct perf_evsel *evsel, 339 int (*acquire_event)(struct perf_evsel *evsel,
342 struct perf_sample *sample); 340 struct perf_sample *sample);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e9231659754d..774c90713a53 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -31,6 +31,38 @@
31#include <sched.h> 31#include <sched.h>
32#include <sys/mman.h> 32#include <sys/mman.h>
33 33
34#ifndef HAVE_ON_EXIT
35#ifndef ATEXIT_MAX
36#define ATEXIT_MAX 32
37#endif
38static int __on_exit_count = 0;
39typedef void (*on_exit_func_t) (int, void *);
40static on_exit_func_t __on_exit_funcs[ATEXIT_MAX];
41static void *__on_exit_args[ATEXIT_MAX];
42static int __exitcode = 0;
43static void __handle_on_exit_funcs(void);
44static int on_exit(on_exit_func_t function, void *arg);
45#define exit(x) (exit)(__exitcode = (x))
46
47static int on_exit(on_exit_func_t function, void *arg)
48{
49 if (__on_exit_count == ATEXIT_MAX)
50 return -ENOMEM;
51 else if (__on_exit_count == 0)
52 atexit(__handle_on_exit_funcs);
53 __on_exit_funcs[__on_exit_count] = function;
54 __on_exit_args[__on_exit_count++] = arg;
55 return 0;
56}
57
58static void __handle_on_exit_funcs(void)
59{
60 int i;
61 for (i = 0; i < __on_exit_count; i++)
62 __on_exit_funcs[i] (__exitcode, __on_exit_args[i]);
63}
64#endif
65
34enum write_mode_t { 66enum write_mode_t {
35 WRITE_FORCE, 67 WRITE_FORCE,
36 WRITE_APPEND 68 WRITE_APPEND
@@ -192,121 +224,28 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
192 224
193static int perf_record__open(struct perf_record *rec) 225static int perf_record__open(struct perf_record *rec)
194{ 226{
227 char msg[512];
195 struct perf_evsel *pos; 228 struct perf_evsel *pos;
196 struct perf_evlist *evlist = rec->evlist; 229 struct perf_evlist *evlist = rec->evlist;
197 struct perf_session *session = rec->session; 230 struct perf_session *session = rec->session;
198 struct perf_record_opts *opts = &rec->opts; 231 struct perf_record_opts *opts = &rec->opts;
199 int rc = 0; 232 int rc = 0;
200 233
201 perf_evlist__config_attrs(evlist, opts); 234 perf_evlist__config(evlist, opts);
202
203 if (opts->group)
204 perf_evlist__set_leader(evlist);
205 235
206 list_for_each_entry(pos, &evlist->entries, node) { 236 list_for_each_entry(pos, &evlist->entries, node) {
207 struct perf_event_attr *attr = &pos->attr;
208 /*
209 * Check if parse_single_tracepoint_event has already asked for
210 * PERF_SAMPLE_TIME.
211 *
212 * XXX this is kludgy but short term fix for problems introduced by
213 * eac23d1c that broke 'perf script' by having different sample_types
214 * when using multiple tracepoint events when we use a perf binary
215 * that tries to use sample_id_all on an older kernel.
216 *
217 * We need to move counter creation to perf_session, support
218 * different sample_types, etc.
219 */
220 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
221
222fallback_missing_features:
223 if (opts->exclude_guest_missing)
224 attr->exclude_guest = attr->exclude_host = 0;
225retry_sample_id:
226 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
227try_again: 237try_again:
228 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { 238 if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) {
229 int err = errno; 239 if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) {
230
231 if (err == EPERM || err == EACCES) {
232 ui__error_paranoid();
233 rc = -err;
234 goto out;
235 } else if (err == ENODEV && opts->target.cpu_list) {
236 pr_err("No such device - did you specify"
237 " an out-of-range profile CPU?\n");
238 rc = -err;
239 goto out;
240 } else if (err == EINVAL) {
241 if (!opts->exclude_guest_missing &&
242 (attr->exclude_guest || attr->exclude_host)) {
243 pr_debug("Old kernel, cannot exclude "
244 "guest or host samples.\n");
245 opts->exclude_guest_missing = true;
246 goto fallback_missing_features;
247 } else if (!opts->sample_id_all_missing) {
248 /*
249 * Old kernel, no attr->sample_id_type_all field
250 */
251 opts->sample_id_all_missing = true;
252 if (!opts->sample_time && !opts->raw_samples && !time_needed)
253 attr->sample_type &= ~PERF_SAMPLE_TIME;
254
255 goto retry_sample_id;
256 }
257 }
258
259 /*
260 * If it's cycles then fall back to hrtimer
261 * based cpu-clock-tick sw counter, which
262 * is always available even if no PMU support.
263 *
264 * PPC returns ENXIO until 2.6.37 (behavior changed
265 * with commit b0a873e).
266 */
267 if ((err == ENOENT || err == ENXIO)
268 && attr->type == PERF_TYPE_HARDWARE
269 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
270
271 if (verbose) 240 if (verbose)
272 ui__warning("The cycles event is not supported, " 241 ui__warning("%s\n", msg);
273 "trying to fall back to cpu-clock-ticks\n");
274 attr->type = PERF_TYPE_SOFTWARE;
275 attr->config = PERF_COUNT_SW_CPU_CLOCK;
276 if (pos->name) {
277 free(pos->name);
278 pos->name = NULL;
279 }
280 goto try_again; 242 goto try_again;
281 } 243 }
282 244
283 if (err == ENOENT) { 245 rc = -errno;
284 ui__error("The %s event is not supported.\n", 246 perf_evsel__open_strerror(pos, &opts->target,
285 perf_evsel__name(pos)); 247 errno, msg, sizeof(msg));
286 rc = -err; 248 ui__error("%s\n", msg);
287 goto out;
288 }
289
290 printf("\n");
291 error("sys_perf_event_open() syscall returned with %d "
292 "(%s) for event %s. /bin/dmesg may provide "
293 "additional information.\n",
294 err, strerror(err), perf_evsel__name(pos));
295
296#if defined(__i386__) || defined(__x86_64__)
297 if (attr->type == PERF_TYPE_HARDWARE &&
298 err == EOPNOTSUPP) {
299 pr_err("No hardware sampling interrupt available."
300 " No APIC? If so then you can boot the kernel"
301 " with the \"lapic\" boot parameter to"
302 " force-enable it.\n");
303 rc = -err;
304 goto out;
305 }
306#endif
307
308 pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
309 rc = -err;
310 goto out; 249 goto out;
311 } 250 }
312 } 251 }
@@ -326,7 +265,8 @@ try_again:
326 "or try again with a smaller value of -m/--mmap_pages.\n" 265 "or try again with a smaller value of -m/--mmap_pages.\n"
327 "(current value: %d)\n", opts->mmap_pages); 266 "(current value: %d)\n", opts->mmap_pages);
328 rc = -errno; 267 rc = -errno;
329 } else if (!is_power_of_2(opts->mmap_pages)) { 268 } else if (!is_power_of_2(opts->mmap_pages) &&
269 (opts->mmap_pages != UINT_MAX)) {
330 pr_err("--mmap_pages/-m value must be a power of two."); 270 pr_err("--mmap_pages/-m value must be a power of two.");
331 rc = -EINVAL; 271 rc = -EINVAL;
332 } else { 272 } else {
@@ -388,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data)
388{ 328{
389 int err; 329 int err;
390 struct perf_tool *tool = data; 330 struct perf_tool *tool = data;
391
392 if (machine__is_host(machine))
393 return;
394
395 /* 331 /*
396 *As for guest kernel when processing subcommand record&report, 332 *As for guest kernel when processing subcommand record&report,
397 *we arrange module mmap prior to guest kernel mmap and trigger 333 *we arrange module mmap prior to guest kernel mmap and trigger
@@ -460,6 +396,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
460 struct perf_evlist *evsel_list = rec->evlist; 396 struct perf_evlist *evsel_list = rec->evlist;
461 const char *output_name = rec->output_name; 397 const char *output_name = rec->output_name;
462 struct perf_session *session; 398 struct perf_session *session;
399 bool disabled = false;
463 400
464 rec->progname = argv[0]; 401 rec->progname = argv[0];
465 402
@@ -549,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
549 goto out_delete_session; 486 goto out_delete_session;
550 } 487 }
551 488
489 if (!evsel_list->nr_groups)
490 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
491
552 /* 492 /*
553 * perf_session__delete(session) will be called at perf_record__exit() 493 * perf_session__delete(session) will be called at perf_record__exit()
554 */ 494 */
@@ -575,12 +515,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
575 515
576 rec->post_processing_offset = lseek(output, 0, SEEK_CUR); 516 rec->post_processing_offset = lseek(output, 0, SEEK_CUR);
577 517
578 machine = perf_session__find_host_machine(session); 518 machine = &session->machines.host;
579 if (!machine) {
580 pr_err("Couldn't find native kernel information.\n");
581 err = -1;
582 goto out_delete_session;
583 }
584 519
585 if (opts->pipe_output) { 520 if (opts->pipe_output) {
586 err = perf_event__synthesize_attrs(tool, session, 521 err = perf_event__synthesize_attrs(tool, session,
@@ -633,9 +568,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
633 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" 568 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
634 "Check /proc/modules permission or run as root.\n"); 569 "Check /proc/modules permission or run as root.\n");
635 570
636 if (perf_guest) 571 if (perf_guest) {
637 perf_session__process_machines(session, tool, 572 machines__process_guests(&session->machines,
638 perf_event__synthesize_guest_os); 573 perf_event__synthesize_guest_os, tool);
574 }
639 575
640 if (!opts->target.system_wide) 576 if (!opts->target.system_wide)
641 err = perf_event__synthesize_thread_map(tool, evsel_list->threads, 577 err = perf_event__synthesize_thread_map(tool, evsel_list->threads,
@@ -659,7 +595,13 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
659 } 595 }
660 } 596 }
661 597
662 perf_evlist__enable(evsel_list); 598 /*
599 * When perf is starting the traced process, all the events
600 * (apart from group members) have enable_on_exec=1 set,
601 * so don't spoil it by prematurely enabling them.
602 */
603 if (!perf_target__none(&opts->target))
604 perf_evlist__enable(evsel_list);
663 605
664 /* 606 /*
665 * Let the child rip 607 * Let the child rip
@@ -682,8 +624,15 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
682 waking++; 624 waking++;
683 } 625 }
684 626
685 if (done) 627 /*
628 * When perf is starting the traced process, at the end events
629 * die with the process and we wait for that. Thus no need to
630 * disable events in this case.
631 */
632 if (done && !disabled && !perf_target__none(&opts->target)) {
686 perf_evlist__disable(evsel_list); 633 perf_evlist__disable(evsel_list);
634 disabled = true;
635 }
687 } 636 }
688 637
689 if (quiet || signr == SIGUSR1) 638 if (quiet || signr == SIGUSR1)
@@ -819,11 +768,10 @@ static int get_stack_size(char *str, unsigned long *_size)
819} 768}
820#endif /* LIBUNWIND_SUPPORT */ 769#endif /* LIBUNWIND_SUPPORT */
821 770
822static int 771int record_parse_callchain_opt(const struct option *opt,
823parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, 772 const char *arg, int unset)
824 int unset)
825{ 773{
826 struct perf_record *rec = (struct perf_record *)opt->value; 774 struct perf_record_opts *opts = opt->value;
827 char *tok, *name, *saveptr = NULL; 775 char *tok, *name, *saveptr = NULL;
828 char *buf; 776 char *buf;
829 int ret = -1; 777 int ret = -1;
@@ -849,7 +797,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
849 /* Framepointer style */ 797 /* Framepointer style */
850 if (!strncmp(name, "fp", sizeof("fp"))) { 798 if (!strncmp(name, "fp", sizeof("fp"))) {
851 if (!strtok_r(NULL, ",", &saveptr)) { 799 if (!strtok_r(NULL, ",", &saveptr)) {
852 rec->opts.call_graph = CALLCHAIN_FP; 800 opts->call_graph = CALLCHAIN_FP;
853 ret = 0; 801 ret = 0;
854 } else 802 } else
855 pr_err("callchain: No more arguments " 803 pr_err("callchain: No more arguments "
@@ -862,20 +810,20 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
862 const unsigned long default_stack_dump_size = 8192; 810 const unsigned long default_stack_dump_size = 8192;
863 811
864 ret = 0; 812 ret = 0;
865 rec->opts.call_graph = CALLCHAIN_DWARF; 813 opts->call_graph = CALLCHAIN_DWARF;
866 rec->opts.stack_dump_size = default_stack_dump_size; 814 opts->stack_dump_size = default_stack_dump_size;
867 815
868 tok = strtok_r(NULL, ",", &saveptr); 816 tok = strtok_r(NULL, ",", &saveptr);
869 if (tok) { 817 if (tok) {
870 unsigned long size = 0; 818 unsigned long size = 0;
871 819
872 ret = get_stack_size(tok, &size); 820 ret = get_stack_size(tok, &size);
873 rec->opts.stack_dump_size = size; 821 opts->stack_dump_size = size;
874 } 822 }
875 823
876 if (!ret) 824 if (!ret)
877 pr_debug("callchain: stack dump size %d\n", 825 pr_debug("callchain: stack dump size %d\n",
878 rec->opts.stack_dump_size); 826 opts->stack_dump_size);
879#endif /* LIBUNWIND_SUPPORT */ 827#endif /* LIBUNWIND_SUPPORT */
880 } else { 828 } else {
881 pr_err("callchain: Unknown -g option " 829 pr_err("callchain: Unknown -g option "
@@ -888,7 +836,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg,
888 free(buf); 836 free(buf);
889 837
890 if (!ret) 838 if (!ret)
891 pr_debug("callchain: type %d\n", rec->opts.call_graph); 839 pr_debug("callchain: type %d\n", opts->call_graph);
892 840
893 return ret; 841 return ret;
894} 842}
@@ -926,9 +874,9 @@ static struct perf_record record = {
926#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " 874#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
927 875
928#ifdef LIBUNWIND_SUPPORT 876#ifdef LIBUNWIND_SUPPORT
929static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; 877const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
930#else 878#else
931static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; 879const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
932#endif 880#endif
933 881
934/* 882/*
@@ -972,9 +920,9 @@ const struct option record_options[] = {
972 "number of mmap data pages"), 920 "number of mmap data pages"),
973 OPT_BOOLEAN(0, "group", &record.opts.group, 921 OPT_BOOLEAN(0, "group", &record.opts.group,
974 "put the counters into a counter group"), 922 "put the counters into a counter group"),
975 OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]", 923 OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
976 callchain_help, &parse_callchain_opt, 924 "mode[,dump_size]", record_callchain_help,
977 "fp"), 925 &record_parse_callchain_opt, "fp"),
978 OPT_INCR('v', "verbose", &verbose, 926 OPT_INCR('v', "verbose", &verbose,
979 "be more verbose (show counter open errors, etc)"), 927 "be more verbose (show counter open errors, etc)"),
980 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), 928 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index a61725d89d3e..96b5a7fee4bb 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -8,6 +8,7 @@
8#include "builtin.h" 8#include "builtin.h"
9 9
10#include "util/util.h" 10#include "util/util.h"
11#include "util/cache.h"
11 12
12#include "util/annotate.h" 13#include "util/annotate.h"
13#include "util/color.h" 14#include "util/color.h"
@@ -33,13 +34,13 @@
33#include "util/thread.h" 34#include "util/thread.h"
34#include "util/sort.h" 35#include "util/sort.h"
35#include "util/hist.h" 36#include "util/hist.h"
37#include "arch/common.h"
36 38
37#include <linux/bitmap.h> 39#include <linux/bitmap.h>
38 40
39struct perf_report { 41struct perf_report {
40 struct perf_tool tool; 42 struct perf_tool tool;
41 struct perf_session *session; 43 struct perf_session *session;
42 char const *input_name;
43 bool force, use_tui, use_gtk, use_stdio; 44 bool force, use_tui, use_gtk, use_stdio;
44 bool hide_unresolved; 45 bool hide_unresolved;
45 bool dont_use_callchains; 46 bool dont_use_callchains;
@@ -54,6 +55,16 @@ struct perf_report {
54 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 55 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
55}; 56};
56 57
58static int perf_report_config(const char *var, const char *value, void *cb)
59{
60 if (!strcmp(var, "report.group")) {
61 symbol_conf.event_group = perf_config_bool(var, value);
62 return 0;
63 }
64
65 return perf_default_config(var, value, cb);
66}
67
57static int perf_report__add_branch_hist_entry(struct perf_tool *tool, 68static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
58 struct addr_location *al, 69 struct addr_location *al,
59 struct perf_sample *sample, 70 struct perf_sample *sample,
@@ -299,6 +310,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
299 char unit; 310 char unit;
300 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; 311 unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
301 u64 nr_events = self->stats.total_period; 312 u64 nr_events = self->stats.total_period;
313 struct perf_evsel *evsel = hists_to_evsel(self);
314 char buf[512];
315 size_t size = sizeof(buf);
316
317 if (symbol_conf.event_group && evsel->nr_members > 1) {
318 struct perf_evsel *pos;
319
320 perf_evsel__group_desc(evsel, buf, size);
321 evname = buf;
322
323 for_each_group_member(pos, evsel) {
324 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
325 nr_events += pos->hists.stats.total_period;
326 }
327 }
302 328
303 nr_samples = convert_unit(nr_samples, &unit); 329 nr_samples = convert_unit(nr_samples, &unit);
304 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit); 330 ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
@@ -319,6 +345,10 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
319 struct hists *hists = &pos->hists; 345 struct hists *hists = &pos->hists;
320 const char *evname = perf_evsel__name(pos); 346 const char *evname = perf_evsel__name(pos);
321 347
348 if (symbol_conf.event_group &&
349 !perf_evsel__is_group_leader(pos))
350 continue;
351
322 hists__fprintf_nr_sample_events(hists, evname, stdout); 352 hists__fprintf_nr_sample_events(hists, evname, stdout);
323 hists__fprintf(hists, true, 0, 0, stdout); 353 hists__fprintf(hists, true, 0, 0, stdout);
324 fprintf(stdout, "\n\n"); 354 fprintf(stdout, "\n\n");
@@ -372,7 +402,7 @@ static int __cmd_report(struct perf_report *rep)
372 if (ret) 402 if (ret)
373 goto out_delete; 403 goto out_delete;
374 404
375 kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; 405 kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
376 kernel_kmap = map__kmap(kernel_map); 406 kernel_kmap = map__kmap(kernel_map);
377 if (kernel_map == NULL || 407 if (kernel_map == NULL ||
378 (kernel_map->dso->hit && 408 (kernel_map->dso->hit &&
@@ -416,8 +446,16 @@ static int __cmd_report(struct perf_report *rep)
416 hists->symbol_filter_str = rep->symbol_filter_str; 446 hists->symbol_filter_str = rep->symbol_filter_str;
417 447
418 hists__collapse_resort(hists); 448 hists__collapse_resort(hists);
419 hists__output_resort(hists);
420 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; 449 nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
450
451 /* Non-group events are considered as leader */
452 if (symbol_conf.event_group &&
453 !perf_evsel__is_group_leader(pos)) {
454 struct hists *leader_hists = &pos->leader->hists;
455
456 hists__match(leader_hists, hists);
457 hists__link(leader_hists, hists);
458 }
421 } 459 }
422 460
423 if (nr_samples == 0) { 461 if (nr_samples == 0) {
@@ -425,13 +463,25 @@ static int __cmd_report(struct perf_report *rep)
425 goto out_delete; 463 goto out_delete;
426 } 464 }
427 465
466 list_for_each_entry(pos, &session->evlist->entries, node)
467 hists__output_resort(&pos->hists);
468
428 if (use_browser > 0) { 469 if (use_browser > 0) {
429 if (use_browser == 1) { 470 if (use_browser == 1) {
430 perf_evlist__tui_browse_hists(session->evlist, help, 471 ret = perf_evlist__tui_browse_hists(session->evlist,
431 NULL, NULL, 0); 472 help,
473 NULL,
474 &session->header.env);
475 /*
476 * Usually "ret" is the last pressed key, and we only
477 * care if the key notifies us to switch data file.
478 */
479 if (ret != K_SWITCH_INPUT_DATA)
480 ret = 0;
481
432 } else if (use_browser == 2) { 482 } else if (use_browser == 2) {
433 perf_evlist__gtk_browse_hists(session->evlist, help, 483 perf_evlist__gtk_browse_hists(session->evlist, help,
434 NULL, NULL, 0); 484 NULL);
435 } 485 }
436 } else 486 } else
437 perf_evlist__tty_browse_hists(session->evlist, rep, help); 487 perf_evlist__tty_browse_hists(session->evlist, rep, help);
@@ -556,8 +606,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
556 .sample = process_sample_event, 606 .sample = process_sample_event,
557 .mmap = perf_event__process_mmap, 607 .mmap = perf_event__process_mmap,
558 .comm = perf_event__process_comm, 608 .comm = perf_event__process_comm,
559 .exit = perf_event__process_task, 609 .exit = perf_event__process_exit,
560 .fork = perf_event__process_task, 610 .fork = perf_event__process_fork,
561 .lost = perf_event__process_lost, 611 .lost = perf_event__process_lost,
562 .read = process_read_event, 612 .read = process_read_event,
563 .attr = perf_event__process_attr, 613 .attr = perf_event__process_attr,
@@ -570,7 +620,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
570 .pretty_printing_style = "normal", 620 .pretty_printing_style = "normal",
571 }; 621 };
572 const struct option options[] = { 622 const struct option options[] = {
573 OPT_STRING('i', "input", &report.input_name, "file", 623 OPT_STRING('i', "input", &input_name, "file",
574 "input file name"), 624 "input file name"),
575 OPT_INCR('v', "verbose", &verbose, 625 OPT_INCR('v', "verbose", &verbose,
576 "be more verbose (show symbol address, etc)"), 626 "be more verbose (show symbol address, etc)"),
@@ -594,8 +644,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
594 OPT_BOOLEAN(0, "stdio", &report.use_stdio, 644 OPT_BOOLEAN(0, "stdio", &report.use_stdio,
595 "Use the stdio interface"), 645 "Use the stdio interface"),
596 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 646 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
597 "sort by key(s): pid, comm, dso, symbol, parent, dso_to," 647 "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline,"
598 " dso_from, symbol_to, symbol_from, mispredict"), 648 " dso_to, dso_from, symbol_to, symbol_from, mispredict"),
599 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, 649 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
600 "Show sample percentage for different cpu modes"), 650 "Show sample percentage for different cpu modes"),
601 OPT_STRING('p', "parent", &parent_pattern, "regex", 651 OPT_STRING('p', "parent", &parent_pattern, "regex",
@@ -637,6 +687,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
637 "Specify disassembler style (e.g. -M intel for intel syntax)"), 687 "Specify disassembler style (e.g. -M intel for intel syntax)"),
638 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 688 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
639 "Show a column with the sum of periods"), 689 "Show a column with the sum of periods"),
690 OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
691 "Show event group information together"),
640 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "", 692 OPT_CALLBACK_NOOPT('b', "branch-stack", &sort__branch_mode, "",
641 "use branch records for histogram filling", parse_branch_mode), 693 "use branch records for histogram filling", parse_branch_mode),
642 OPT_STRING(0, "objdump", &objdump_path, "path", 694 OPT_STRING(0, "objdump", &objdump_path, "path",
@@ -644,6 +696,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
644 OPT_END() 696 OPT_END()
645 }; 697 };
646 698
699 perf_config(perf_report_config, NULL);
700
647 argc = parse_options(argc, argv, options, report_usage, 0); 701 argc = parse_options(argc, argv, options, report_usage, 0);
648 702
649 if (report.use_stdio) 703 if (report.use_stdio)
@@ -656,13 +710,23 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
656 if (report.inverted_callchain) 710 if (report.inverted_callchain)
657 callchain_param.order = ORDER_CALLER; 711 callchain_param.order = ORDER_CALLER;
658 712
659 if (!report.input_name || !strlen(report.input_name)) { 713 if (!input_name || !strlen(input_name)) {
660 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) 714 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
661 report.input_name = "-"; 715 input_name = "-";
662 else 716 else
663 report.input_name = "perf.data"; 717 input_name = "perf.data";
718 }
719
720 if (strcmp(input_name, "-") != 0)
721 setup_browser(true);
722 else {
723 use_browser = 0;
724 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
725 perf_hpp__init();
664 } 726 }
665 session = perf_session__new(report.input_name, O_RDONLY, 727
728repeat:
729 session = perf_session__new(input_name, O_RDONLY,
666 report.force, false, &report.tool); 730 report.force, false, &report.tool);
667 if (session == NULL) 731 if (session == NULL)
668 return -ENOMEM; 732 return -ENOMEM;
@@ -687,14 +751,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
687 751
688 } 752 }
689 753
690 if (strcmp(report.input_name, "-") != 0) 754 if (setup_sorting() < 0)
691 setup_browser(true); 755 usage_with_options(report_usage, options);
692 else {
693 use_browser = 0;
694 perf_hpp__init();
695 }
696
697 setup_sorting(report_usage, options);
698 756
699 /* 757 /*
700 * Only in the newt browser we are doing integrated annotation, 758 * Only in the newt browser we are doing integrated annotation,
@@ -762,6 +820,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
762 } 820 }
763 821
764 ret = __cmd_report(&report); 822 ret = __cmd_report(&report);
823 if (ret == K_SWITCH_INPUT_DATA) {
824 perf_session__delete(session);
825 goto repeat;
826 } else
827 ret = 0;
828
765error: 829error:
766 perf_session__delete(session); 830 perf_session__delete(session);
767 return ret; 831 return ret;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 3488ead3b60c..138229439a93 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -120,7 +120,6 @@ struct trace_sched_handler {
120 120
121struct perf_sched { 121struct perf_sched {
122 struct perf_tool tool; 122 struct perf_tool tool;
123 const char *input_name;
124 const char *sort_order; 123 const char *sort_order;
125 unsigned long nr_tasks; 124 unsigned long nr_tasks;
126 struct task_desc *pid_to_task[MAX_PID]; 125 struct task_desc *pid_to_task[MAX_PID];
@@ -1460,7 +1459,7 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1460 }; 1459 };
1461 struct perf_session *session; 1460 struct perf_session *session;
1462 1461
1463 session = perf_session__new(sched->input_name, O_RDONLY, 0, false, &sched->tool); 1462 session = perf_session__new(input_name, O_RDONLY, 0, false, &sched->tool);
1464 if (session == NULL) { 1463 if (session == NULL) {
1465 pr_debug("No Memory for session\n"); 1464 pr_debug("No Memory for session\n");
1466 return -1; 1465 return -1;
@@ -1476,9 +1475,9 @@ static int perf_sched__read_events(struct perf_sched *sched, bool destroy,
1476 goto out_delete; 1475 goto out_delete;
1477 } 1476 }
1478 1477
1479 sched->nr_events = session->hists.stats.nr_events[0]; 1478 sched->nr_events = session->stats.nr_events[0];
1480 sched->nr_lost_events = session->hists.stats.total_lost; 1479 sched->nr_lost_events = session->stats.total_lost;
1481 sched->nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST]; 1480 sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST];
1482 } 1481 }
1483 1482
1484 if (destroy) 1483 if (destroy)
@@ -1672,7 +1671,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1672 .sample = perf_sched__process_tracepoint_sample, 1671 .sample = perf_sched__process_tracepoint_sample,
1673 .comm = perf_event__process_comm, 1672 .comm = perf_event__process_comm,
1674 .lost = perf_event__process_lost, 1673 .lost = perf_event__process_lost,
1675 .fork = perf_event__process_task, 1674 .exit = perf_event__process_exit,
1675 .fork = perf_event__process_fork,
1676 .ordered_samples = true, 1676 .ordered_samples = true,
1677 }, 1677 },
1678 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), 1678 .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
@@ -1707,7 +1707,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
1707 OPT_END() 1707 OPT_END()
1708 }; 1708 };
1709 const struct option sched_options[] = { 1709 const struct option sched_options[] = {
1710 OPT_STRING('i', "input", &sched.input_name, "file", 1710 OPT_STRING('i', "input", &input_name, "file",
1711 "input file name"), 1711 "input file name"),
1712 OPT_INCR('v', "verbose", &verbose, 1712 OPT_INCR('v', "verbose", &verbose,
1713 "be more verbose (show symbol address, etc)"), 1713 "be more verbose (show symbol address, etc)"),
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index fb9625083a2e..92d4658f56fb 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -520,8 +520,8 @@ static struct perf_tool perf_script = {
520 .sample = process_sample_event, 520 .sample = process_sample_event,
521 .mmap = perf_event__process_mmap, 521 .mmap = perf_event__process_mmap,
522 .comm = perf_event__process_comm, 522 .comm = perf_event__process_comm,
523 .exit = perf_event__process_task, 523 .exit = perf_event__process_exit,
524 .fork = perf_event__process_task, 524 .fork = perf_event__process_fork,
525 .attr = perf_event__process_attr, 525 .attr = perf_event__process_attr,
526 .event_type = perf_event__process_event_type, 526 .event_type = perf_event__process_event_type,
527 .tracing_data = perf_event__process_tracing_data, 527 .tracing_data = perf_event__process_tracing_data,
@@ -692,7 +692,7 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
692 const char *arg, int unset __maybe_unused) 692 const char *arg, int unset __maybe_unused)
693{ 693{
694 char *tok; 694 char *tok;
695 int i, imax = sizeof(all_output_options) / sizeof(struct output_option); 695 int i, imax = ARRAY_SIZE(all_output_options);
696 int j; 696 int j;
697 int rc = 0; 697 int rc = 0;
698 char *str = strdup(arg); 698 char *str = strdup(arg);
@@ -909,18 +909,6 @@ static const char *ends_with(const char *str, const char *suffix)
909 return NULL; 909 return NULL;
910} 910}
911 911
912static char *ltrim(char *str)
913{
914 int len = strlen(str);
915
916 while (len && isspace(*str)) {
917 len--;
918 str++;
919 }
920
921 return str;
922}
923
924static int read_script_info(struct script_desc *desc, const char *filename) 912static int read_script_info(struct script_desc *desc, const char *filename)
925{ 913{
926 char line[BUFSIZ], *p; 914 char line[BUFSIZ], *p;
@@ -1030,6 +1018,68 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1030} 1018}
1031 1019
1032/* 1020/*
1021 * Some scripts specify the required events in their "xxx-record" file,
1022 * this function will check if the events in perf.data match those
1023 * mentioned in the "xxx-record".
1024 *
1025 * Fixme: All existing "xxx-record" are all in good formats "-e event ",
1026 * which is covered well now. And new parsing code should be added to
1027 * cover the future complexing formats like event groups etc.
1028 */
1029static int check_ev_match(char *dir_name, char *scriptname,
1030 struct perf_session *session)
1031{
1032 char filename[MAXPATHLEN], evname[128];
1033 char line[BUFSIZ], *p;
1034 struct perf_evsel *pos;
1035 int match, len;
1036 FILE *fp;
1037
1038 sprintf(filename, "%s/bin/%s-record", dir_name, scriptname);
1039
1040 fp = fopen(filename, "r");
1041 if (!fp)
1042 return -1;
1043
1044 while (fgets(line, sizeof(line), fp)) {
1045 p = ltrim(line);
1046 if (*p == '#')
1047 continue;
1048
1049 while (strlen(p)) {
1050 p = strstr(p, "-e");
1051 if (!p)
1052 break;
1053
1054 p += 2;
1055 p = ltrim(p);
1056 len = strcspn(p, " \t");
1057 if (!len)
1058 break;
1059
1060 snprintf(evname, len + 1, "%s", p);
1061
1062 match = 0;
1063 list_for_each_entry(pos,
1064 &session->evlist->entries, node) {
1065 if (!strcmp(perf_evsel__name(pos), evname)) {
1066 match = 1;
1067 break;
1068 }
1069 }
1070
1071 if (!match) {
1072 fclose(fp);
1073 return -1;
1074 }
1075 }
1076 }
1077
1078 fclose(fp);
1079 return 0;
1080}
1081
1082/*
1033 * Return -1 if none is found, otherwise the actual scripts number. 1083 * Return -1 if none is found, otherwise the actual scripts number.
1034 * 1084 *
1035 * Currently the only user of this function is the script browser, which 1085 * Currently the only user of this function is the script browser, which
@@ -1039,17 +1089,23 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1039int find_scripts(char **scripts_array, char **scripts_path_array) 1089int find_scripts(char **scripts_array, char **scripts_path_array)
1040{ 1090{
1041 struct dirent *script_next, *lang_next, script_dirent, lang_dirent; 1091 struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
1042 char scripts_path[MAXPATHLEN]; 1092 char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN];
1043 DIR *scripts_dir, *lang_dir; 1093 DIR *scripts_dir, *lang_dir;
1044 char lang_path[MAXPATHLEN]; 1094 struct perf_session *session;
1045 char *temp; 1095 char *temp;
1046 int i = 0; 1096 int i = 0;
1047 1097
1098 session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
1099 if (!session)
1100 return -1;
1101
1048 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1102 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
1049 1103
1050 scripts_dir = opendir(scripts_path); 1104 scripts_dir = opendir(scripts_path);
1051 if (!scripts_dir) 1105 if (!scripts_dir) {
1106 perf_session__delete(session);
1052 return -1; 1107 return -1;
1108 }
1053 1109
1054 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { 1110 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
1055 snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, 1111 snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path,
@@ -1077,10 +1133,18 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1077 snprintf(scripts_array[i], 1133 snprintf(scripts_array[i],
1078 (temp - script_dirent.d_name) + 1, 1134 (temp - script_dirent.d_name) + 1,
1079 "%s", script_dirent.d_name); 1135 "%s", script_dirent.d_name);
1136
1137 if (check_ev_match(lang_path,
1138 scripts_array[i], session))
1139 continue;
1140
1080 i++; 1141 i++;
1081 } 1142 }
1143 closedir(lang_dir);
1082 } 1144 }
1083 1145
1146 closedir(scripts_dir);
1147 perf_session__delete(session);
1084 return i; 1148 return i;
1085} 1149}
1086 1150
@@ -1175,7 +1239,6 @@ static int have_cmd(int argc, const char **argv)
1175int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 1239int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1176{ 1240{
1177 bool show_full_info = false; 1241 bool show_full_info = false;
1178 const char *input_name = NULL;
1179 char *rec_script_path = NULL; 1242 char *rec_script_path = NULL;
1180 char *rep_script_path = NULL; 1243 char *rep_script_path = NULL;
1181 struct perf_session *session; 1244 struct perf_session *session;
@@ -1412,7 +1475,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1412 return -1; 1475 return -1;
1413 } 1476 }
1414 1477
1415 perf_session__fprintf_info(session, stdout, show_full_info); 1478 if (!script_name && !generate_script_lang)
1479 perf_session__fprintf_info(session, stdout, show_full_info);
1416 1480
1417 if (!no_callchain) 1481 if (!no_callchain)
1418 symbol_conf.use_callchain = true; 1482 symbol_conf.use_callchain = true;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 93b9011fa3e2..99848761f573 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -57,6 +57,7 @@
57#include "util/thread.h" 57#include "util/thread.h"
58#include "util/thread_map.h" 58#include "util/thread_map.h"
59 59
60#include <stdlib.h>
60#include <sys/prctl.h> 61#include <sys/prctl.h>
61#include <locale.h> 62#include <locale.h>
62 63
@@ -64,6 +65,11 @@
64#define CNTR_NOT_SUPPORTED "<not supported>" 65#define CNTR_NOT_SUPPORTED "<not supported>"
65#define CNTR_NOT_COUNTED "<not counted>" 66#define CNTR_NOT_COUNTED "<not counted>"
66 67
68static void print_stat(int argc, const char **argv);
69static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
70static void print_counter(struct perf_evsel *counter, char *prefix);
71static void print_aggr_socket(char *prefix);
72
67static struct perf_evlist *evsel_list; 73static struct perf_evlist *evsel_list;
68 74
69static struct perf_target target = { 75static struct perf_target target = {
@@ -74,6 +80,7 @@ static int run_count = 1;
74static bool no_inherit = false; 80static bool no_inherit = false;
75static bool scale = true; 81static bool scale = true;
76static bool no_aggr = false; 82static bool no_aggr = false;
83static bool aggr_socket = false;
77static pid_t child_pid = -1; 84static pid_t child_pid = -1;
78static bool null_run = false; 85static bool null_run = false;
79static int detailed_run = 0; 86static int detailed_run = 0;
@@ -83,6 +90,12 @@ static const char *csv_sep = NULL;
83static bool csv_output = false; 90static bool csv_output = false;
84static bool group = false; 91static bool group = false;
85static FILE *output = NULL; 92static FILE *output = NULL;
93static const char *pre_cmd = NULL;
94static const char *post_cmd = NULL;
95static bool sync_run = false;
96static unsigned int interval = 0;
97static struct timespec ref_time;
98static struct cpu_map *sock_map;
86 99
87static volatile int done = 0; 100static volatile int done = 0;
88 101
@@ -90,6 +103,28 @@ struct perf_stat {
90 struct stats res_stats[3]; 103 struct stats res_stats[3];
91}; 104};
92 105
106static inline void diff_timespec(struct timespec *r, struct timespec *a,
107 struct timespec *b)
108{
109 r->tv_sec = a->tv_sec - b->tv_sec;
110 if (a->tv_nsec < b->tv_nsec) {
111 r->tv_nsec = a->tv_nsec + 1000000000L - b->tv_nsec;
112 r->tv_sec--;
113 } else {
114 r->tv_nsec = a->tv_nsec - b->tv_nsec ;
115 }
116}
117
118static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
119{
120 return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
121}
122
123static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
124{
125 return perf_evsel__cpus(evsel)->nr;
126}
127
93static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 128static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
94{ 129{
95 evsel->priv = zalloc(sizeof(struct perf_stat)); 130 evsel->priv = zalloc(sizeof(struct perf_stat));
@@ -102,14 +137,27 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
102 evsel->priv = NULL; 137 evsel->priv = NULL;
103} 138}
104 139
105static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) 140static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
106{ 141{
107 return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; 142 void *addr;
143 size_t sz;
144
145 sz = sizeof(*evsel->counts) +
146 (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values));
147
148 addr = zalloc(sz);
149 if (!addr)
150 return -ENOMEM;
151
152 evsel->prev_raw_counts = addr;
153
154 return 0;
108} 155}
109 156
110static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) 157static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
111{ 158{
112 return perf_evsel__cpus(evsel)->nr; 159 free(evsel->prev_raw_counts);
160 evsel->prev_raw_counts = NULL;
113} 161}
114 162
115static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 163static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
@@ -125,12 +173,9 @@ static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
125static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; 173static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
126static struct stats walltime_nsecs_stats; 174static struct stats walltime_nsecs_stats;
127 175
128static int create_perf_stat_counter(struct perf_evsel *evsel, 176static int create_perf_stat_counter(struct perf_evsel *evsel)
129 struct perf_evsel *first)
130{ 177{
131 struct perf_event_attr *attr = &evsel->attr; 178 struct perf_event_attr *attr = &evsel->attr;
132 bool exclude_guest_missing = false;
133 int ret;
134 179
135 if (scale) 180 if (scale)
136 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 181 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -138,37 +183,16 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
138 183
139 attr->inherit = !no_inherit; 184 attr->inherit = !no_inherit;
140 185
141retry: 186 if (perf_target__has_cpu(&target))
142 if (exclude_guest_missing) 187 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
143 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
144
145 if (perf_target__has_cpu(&target)) {
146 ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
147 if (ret)
148 goto check_ret;
149 return 0;
150 }
151 188
152 if (!perf_target__has_task(&target) && (!group || evsel == first)) { 189 if (!perf_target__has_task(&target) &&
190 perf_evsel__is_group_leader(evsel)) {
153 attr->disabled = 1; 191 attr->disabled = 1;
154 attr->enable_on_exec = 1; 192 attr->enable_on_exec = 1;
155 } 193 }
156 194
157 ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); 195 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
158 if (!ret)
159 return 0;
160 /* fall through */
161check_ret:
162 if (ret && errno == EINVAL) {
163 if (!exclude_guest_missing &&
164 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
165 pr_debug("Old kernel, cannot exclude "
166 "guest or host samples.\n");
167 exclude_guest_missing = true;
168 goto retry;
169 }
170 }
171 return ret;
172} 196}
173 197
174/* 198/*
@@ -265,15 +289,79 @@ static int read_counter(struct perf_evsel *counter)
265 return 0; 289 return 0;
266} 290}
267 291
268static int run_perf_stat(int argc __maybe_unused, const char **argv) 292static void print_interval(void)
293{
294 static int num_print_interval;
295 struct perf_evsel *counter;
296 struct perf_stat *ps;
297 struct timespec ts, rs;
298 char prefix[64];
299
300 if (no_aggr) {
301 list_for_each_entry(counter, &evsel_list->entries, node) {
302 ps = counter->priv;
303 memset(ps->res_stats, 0, sizeof(ps->res_stats));
304 read_counter(counter);
305 }
306 } else {
307 list_for_each_entry(counter, &evsel_list->entries, node) {
308 ps = counter->priv;
309 memset(ps->res_stats, 0, sizeof(ps->res_stats));
310 read_counter_aggr(counter);
311 }
312 }
313 clock_gettime(CLOCK_MONOTONIC, &ts);
314 diff_timespec(&rs, &ts, &ref_time);
315 sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
316
317 if (num_print_interval == 0 && !csv_output) {
318 if (aggr_socket)
319 fprintf(output, "# time socket cpus counts events\n");
320 else if (no_aggr)
321 fprintf(output, "# time CPU counts events\n");
322 else
323 fprintf(output, "# time counts events\n");
324 }
325
326 if (++num_print_interval == 25)
327 num_print_interval = 0;
328
329 if (aggr_socket)
330 print_aggr_socket(prefix);
331 else if (no_aggr) {
332 list_for_each_entry(counter, &evsel_list->entries, node)
333 print_counter(counter, prefix);
334 } else {
335 list_for_each_entry(counter, &evsel_list->entries, node)
336 print_counter_aggr(counter, prefix);
337 }
338}
339
340static int __run_perf_stat(int argc __maybe_unused, const char **argv)
269{ 341{
342 char msg[512];
270 unsigned long long t0, t1; 343 unsigned long long t0, t1;
271 struct perf_evsel *counter, *first; 344 struct perf_evsel *counter;
345 struct timespec ts;
272 int status = 0; 346 int status = 0;
273 int child_ready_pipe[2], go_pipe[2]; 347 int child_ready_pipe[2], go_pipe[2];
274 const bool forks = (argc > 0); 348 const bool forks = (argc > 0);
275 char buf; 349 char buf;
276 350
351 if (interval) {
352 ts.tv_sec = interval / 1000;
353 ts.tv_nsec = (interval % 1000) * 1000000;
354 } else {
355 ts.tv_sec = 1;
356 ts.tv_nsec = 0;
357 }
358
359 if (aggr_socket
360 && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) {
361 perror("cannot build socket map");
362 return -1;
363 }
364
277 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 365 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
278 perror("failed to create pipes"); 366 perror("failed to create pipes");
279 return -1; 367 return -1;
@@ -328,10 +416,8 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
328 if (group) 416 if (group)
329 perf_evlist__set_leader(evsel_list); 417 perf_evlist__set_leader(evsel_list);
330 418
331 first = perf_evlist__first(evsel_list);
332
333 list_for_each_entry(counter, &evsel_list->entries, node) { 419 list_for_each_entry(counter, &evsel_list->entries, node) {
334 if (create_perf_stat_counter(counter, first) < 0) { 420 if (create_perf_stat_counter(counter) < 0) {
335 /* 421 /*
336 * PPC returns ENXIO for HW counters until 2.6.37 422 * PPC returns ENXIO for HW counters until 2.6.37
337 * (behavior changed with commit b0a873e). 423 * (behavior changed with commit b0a873e).
@@ -346,20 +432,13 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
346 continue; 432 continue;
347 } 433 }
348 434
349 if (errno == EPERM || errno == EACCES) { 435 perf_evsel__open_strerror(counter, &target,
350 error("You may not have permission to collect %sstats.\n" 436 errno, msg, sizeof(msg));
351 "\t Consider tweaking" 437 ui__error("%s\n", msg);
352 " /proc/sys/kernel/perf_event_paranoid or running as root.", 438
353 target.system_wide ? "system-wide " : "");
354 } else {
355 error("open_counter returned with %d (%s). "
356 "/bin/dmesg may provide additional information.\n",
357 errno, strerror(errno));
358 }
359 if (child_pid != -1) 439 if (child_pid != -1)
360 kill(child_pid, SIGTERM); 440 kill(child_pid, SIGTERM);
361 441
362 pr_err("Not all events could be opened.\n");
363 return -1; 442 return -1;
364 } 443 }
365 counter->supported = true; 444 counter->supported = true;
@@ -375,14 +454,25 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
375 * Enable counters and exec the command: 454 * Enable counters and exec the command:
376 */ 455 */
377 t0 = rdclock(); 456 t0 = rdclock();
457 clock_gettime(CLOCK_MONOTONIC, &ref_time);
378 458
379 if (forks) { 459 if (forks) {
380 close(go_pipe[1]); 460 close(go_pipe[1]);
461 if (interval) {
462 while (!waitpid(child_pid, &status, WNOHANG)) {
463 nanosleep(&ts, NULL);
464 print_interval();
465 }
466 }
381 wait(&status); 467 wait(&status);
382 if (WIFSIGNALED(status)) 468 if (WIFSIGNALED(status))
383 psignal(WTERMSIG(status), argv[0]); 469 psignal(WTERMSIG(status), argv[0]);
384 } else { 470 } else {
385 while(!done) sleep(1); 471 while (!done) {
472 nanosleep(&ts, NULL);
473 if (interval)
474 print_interval();
475 }
386 } 476 }
387 477
388 t1 = rdclock(); 478 t1 = rdclock();
@@ -405,6 +495,32 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
405 return WEXITSTATUS(status); 495 return WEXITSTATUS(status);
406} 496}
407 497
498static int run_perf_stat(int argc __maybe_unused, const char **argv)
499{
500 int ret;
501
502 if (pre_cmd) {
503 ret = system(pre_cmd);
504 if (ret)
505 return ret;
506 }
507
508 if (sync_run)
509 sync();
510
511 ret = __run_perf_stat(argc, argv);
512 if (ret)
513 return ret;
514
515 if (post_cmd) {
516 ret = system(post_cmd);
517 if (ret)
518 return ret;
519 }
520
521 return ret;
522}
523
408static void print_noise_pct(double total, double avg) 524static void print_noise_pct(double total, double avg)
409{ 525{
410 double pct = rel_stddev_stats(total, avg); 526 double pct = rel_stddev_stats(total, avg);
@@ -426,13 +542,21 @@ static void print_noise(struct perf_evsel *evsel, double avg)
426 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); 542 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
427} 543}
428 544
429static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) 545static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
430{ 546{
431 double msecs = avg / 1e6; 547 double msecs = avg / 1e6;
432 char cpustr[16] = { '\0', }; 548 char cpustr[16] = { '\0', };
433 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; 549 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s";
434 550
435 if (no_aggr) 551 if (aggr_socket)
552 sprintf(cpustr, "S%*d%s%*d%s",
553 csv_output ? 0 : -5,
554 cpu,
555 csv_sep,
556 csv_output ? 0 : 4,
557 nr,
558 csv_sep);
559 else if (no_aggr)
436 sprintf(cpustr, "CPU%*d%s", 560 sprintf(cpustr, "CPU%*d%s",
437 csv_output ? 0 : -4, 561 csv_output ? 0 : -4,
438 perf_evsel__cpus(evsel)->map[cpu], csv_sep); 562 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
@@ -442,7 +566,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
442 if (evsel->cgrp) 566 if (evsel->cgrp)
443 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 567 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
444 568
445 if (csv_output) 569 if (csv_output || interval)
446 return; 570 return;
447 571
448 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 572 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
@@ -631,7 +755,7 @@ static void print_ll_cache_misses(int cpu,
631 fprintf(output, " of all LL-cache hits "); 755 fprintf(output, " of all LL-cache hits ");
632} 756}
633 757
634static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) 758static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
635{ 759{
636 double total, ratio = 0.0; 760 double total, ratio = 0.0;
637 char cpustr[16] = { '\0', }; 761 char cpustr[16] = { '\0', };
@@ -644,7 +768,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
644 else 768 else
645 fmt = "%s%18.0f%s%-25s"; 769 fmt = "%s%18.0f%s%-25s";
646 770
647 if (no_aggr) 771 if (aggr_socket)
772 sprintf(cpustr, "S%*d%s%*d%s",
773 csv_output ? 0 : -5,
774 cpu,
775 csv_sep,
776 csv_output ? 0 : 4,
777 nr,
778 csv_sep);
779 else if (no_aggr)
648 sprintf(cpustr, "CPU%*d%s", 780 sprintf(cpustr, "CPU%*d%s",
649 csv_output ? 0 : -4, 781 csv_output ? 0 : -4,
650 perf_evsel__cpus(evsel)->map[cpu], csv_sep); 782 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
@@ -656,12 +788,11 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
656 if (evsel->cgrp) 788 if (evsel->cgrp)
657 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 789 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
658 790
659 if (csv_output) 791 if (csv_output || interval)
660 return; 792 return;
661 793
662 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) { 794 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
663 total = avg_stats(&runtime_cycles_stats[cpu]); 795 total = avg_stats(&runtime_cycles_stats[cpu]);
664
665 if (total) 796 if (total)
666 ratio = avg / total; 797 ratio = avg / total;
667 798
@@ -751,16 +882,83 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
751 } 882 }
752} 883}
753 884
885static void print_aggr_socket(char *prefix)
886{
887 struct perf_evsel *counter;
888 u64 ena, run, val;
889 int cpu, s, s2, sock, nr;
890
891 if (!sock_map)
892 return;
893
894 for (s = 0; s < sock_map->nr; s++) {
895 sock = cpu_map__socket(sock_map, s);
896 list_for_each_entry(counter, &evsel_list->entries, node) {
897 val = ena = run = 0;
898 nr = 0;
899 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
900 s2 = cpu_map__get_socket(evsel_list->cpus, cpu);
901 if (s2 != sock)
902 continue;
903 val += counter->counts->cpu[cpu].val;
904 ena += counter->counts->cpu[cpu].ena;
905 run += counter->counts->cpu[cpu].run;
906 nr++;
907 }
908 if (prefix)
909 fprintf(output, "%s", prefix);
910
911 if (run == 0 || ena == 0) {
912 fprintf(output, "S%*d%s%*d%s%*s%s%*s",
913 csv_output ? 0 : -5,
914 s,
915 csv_sep,
916 csv_output ? 0 : 4,
917 nr,
918 csv_sep,
919 csv_output ? 0 : 18,
920 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
921 csv_sep,
922 csv_output ? 0 : -24,
923 perf_evsel__name(counter));
924 if (counter->cgrp)
925 fprintf(output, "%s%s",
926 csv_sep, counter->cgrp->name);
927
928 fputc('\n', output);
929 continue;
930 }
931
932 if (nsec_counter(counter))
933 nsec_printout(sock, nr, counter, val);
934 else
935 abs_printout(sock, nr, counter, val);
936
937 if (!csv_output) {
938 print_noise(counter, 1.0);
939
940 if (run != ena)
941 fprintf(output, " (%.2f%%)",
942 100.0 * run / ena);
943 }
944 fputc('\n', output);
945 }
946 }
947}
948
754/* 949/*
755 * Print out the results of a single counter: 950 * Print out the results of a single counter:
756 * aggregated counts in system-wide mode 951 * aggregated counts in system-wide mode
757 */ 952 */
758static void print_counter_aggr(struct perf_evsel *counter) 953static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
759{ 954{
760 struct perf_stat *ps = counter->priv; 955 struct perf_stat *ps = counter->priv;
761 double avg = avg_stats(&ps->res_stats[0]); 956 double avg = avg_stats(&ps->res_stats[0]);
762 int scaled = counter->counts->scaled; 957 int scaled = counter->counts->scaled;
763 958
959 if (prefix)
960 fprintf(output, "%s", prefix);
961
764 if (scaled == -1) { 962 if (scaled == -1) {
765 fprintf(output, "%*s%s%*s", 963 fprintf(output, "%*s%s%*s",
766 csv_output ? 0 : 18, 964 csv_output ? 0 : 18,
@@ -777,9 +975,9 @@ static void print_counter_aggr(struct perf_evsel *counter)
777 } 975 }
778 976
779 if (nsec_counter(counter)) 977 if (nsec_counter(counter))
780 nsec_printout(-1, counter, avg); 978 nsec_printout(-1, 0, counter, avg);
781 else 979 else
782 abs_printout(-1, counter, avg); 980 abs_printout(-1, 0, counter, avg);
783 981
784 print_noise(counter, avg); 982 print_noise(counter, avg);
785 983
@@ -803,7 +1001,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
803 * Print out the results of a single counter: 1001 * Print out the results of a single counter:
804 * does not use aggregated count in system-wide 1002 * does not use aggregated count in system-wide
805 */ 1003 */
806static void print_counter(struct perf_evsel *counter) 1004static void print_counter(struct perf_evsel *counter, char *prefix)
807{ 1005{
808 u64 ena, run, val; 1006 u64 ena, run, val;
809 int cpu; 1007 int cpu;
@@ -812,6 +1010,10 @@ static void print_counter(struct perf_evsel *counter)
812 val = counter->counts->cpu[cpu].val; 1010 val = counter->counts->cpu[cpu].val;
813 ena = counter->counts->cpu[cpu].ena; 1011 ena = counter->counts->cpu[cpu].ena;
814 run = counter->counts->cpu[cpu].run; 1012 run = counter->counts->cpu[cpu].run;
1013
1014 if (prefix)
1015 fprintf(output, "%s", prefix);
1016
815 if (run == 0 || ena == 0) { 1017 if (run == 0 || ena == 0) {
816 fprintf(output, "CPU%*d%s%*s%s%*s", 1018 fprintf(output, "CPU%*d%s%*s%s%*s",
817 csv_output ? 0 : -4, 1019 csv_output ? 0 : -4,
@@ -831,9 +1033,9 @@ static void print_counter(struct perf_evsel *counter)
831 } 1033 }
832 1034
833 if (nsec_counter(counter)) 1035 if (nsec_counter(counter))
834 nsec_printout(cpu, counter, val); 1036 nsec_printout(cpu, 0, counter, val);
835 else 1037 else
836 abs_printout(cpu, counter, val); 1038 abs_printout(cpu, 0, counter, val);
837 1039
838 if (!csv_output) { 1040 if (!csv_output) {
839 print_noise(counter, 1.0); 1041 print_noise(counter, 1.0);
@@ -871,12 +1073,14 @@ static void print_stat(int argc, const char **argv)
871 fprintf(output, ":\n\n"); 1073 fprintf(output, ":\n\n");
872 } 1074 }
873 1075
874 if (no_aggr) { 1076 if (aggr_socket)
1077 print_aggr_socket(NULL);
1078 else if (no_aggr) {
875 list_for_each_entry(counter, &evsel_list->entries, node) 1079 list_for_each_entry(counter, &evsel_list->entries, node)
876 print_counter(counter); 1080 print_counter(counter, NULL);
877 } else { 1081 } else {
878 list_for_each_entry(counter, &evsel_list->entries, node) 1082 list_for_each_entry(counter, &evsel_list->entries, node)
879 print_counter_aggr(counter); 1083 print_counter_aggr(counter, NULL);
880 } 1084 }
881 1085
882 if (!csv_output) { 1086 if (!csv_output) {
@@ -897,7 +1101,7 @@ static volatile int signr = -1;
897 1101
898static void skip_signal(int signo) 1102static void skip_signal(int signo)
899{ 1103{
900 if(child_pid == -1) 1104 if ((child_pid == -1) || interval)
901 done = 1; 1105 done = 1;
902 1106
903 signr = signo; 1107 signr = signo;
@@ -1069,8 +1273,7 @@ static int add_default_attributes(void)
1069 1273
1070int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) 1274int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1071{ 1275{
1072 bool append_file = false, 1276 bool append_file = false;
1073 sync_run = false;
1074 int output_fd = 0; 1277 int output_fd = 0;
1075 const char *output_name = NULL; 1278 const char *output_name = NULL;
1076 const struct option options[] = { 1279 const struct option options[] = {
@@ -1114,6 +1317,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1114 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"), 1317 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1115 OPT_INTEGER(0, "log-fd", &output_fd, 1318 OPT_INTEGER(0, "log-fd", &output_fd,
1116 "log output to fd, instead of stderr"), 1319 "log output to fd, instead of stderr"),
1320 OPT_STRING(0, "pre", &pre_cmd, "command",
1321 "command to run prior to the measured command"),
1322 OPT_STRING(0, "post", &post_cmd, "command",
1323 "command to run after to the measured command"),
1324 OPT_UINTEGER('I', "interval-print", &interval,
1325 "print counts at regular interval in ms (>= 100)"),
1326 OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"),
1117 OPT_END() 1327 OPT_END()
1118 }; 1328 };
1119 const char * const stat_usage[] = { 1329 const char * const stat_usage[] = {
@@ -1200,6 +1410,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1200 usage_with_options(stat_usage, options); 1410 usage_with_options(stat_usage, options);
1201 } 1411 }
1202 1412
1413 if (aggr_socket) {
1414 if (!perf_target__has_cpu(&target)) {
1415 fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n");
1416 usage_with_options(stat_usage, options);
1417 }
1418 no_aggr = true;
1419 }
1420
1203 if (add_default_attributes()) 1421 if (add_default_attributes())
1204 goto out; 1422 goto out;
1205 1423
@@ -1214,12 +1432,23 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1214 usage_with_options(stat_usage, options); 1432 usage_with_options(stat_usage, options);
1215 return -1; 1433 return -1;
1216 } 1434 }
1435 if (interval && interval < 100) {
1436 pr_err("print interval must be >= 100ms\n");
1437 usage_with_options(stat_usage, options);
1438 return -1;
1439 }
1217 1440
1218 list_for_each_entry(pos, &evsel_list->entries, node) { 1441 list_for_each_entry(pos, &evsel_list->entries, node) {
1219 if (perf_evsel__alloc_stat_priv(pos) < 0 || 1442 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
1220 perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) 1443 perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0)
1221 goto out_free_fd; 1444 goto out_free_fd;
1222 } 1445 }
1446 if (interval) {
1447 list_for_each_entry(pos, &evsel_list->entries, node) {
1448 if (perf_evsel__alloc_prev_raw_counts(pos) < 0)
1449 goto out_free_fd;
1450 }
1451 }
1223 1452
1224 /* 1453 /*
1225 * We dont want to block the signals - that would cause 1454 * We dont want to block the signals - that would cause
@@ -1229,6 +1458,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1229 */ 1458 */
1230 atexit(sig_atexit); 1459 atexit(sig_atexit);
1231 signal(SIGINT, skip_signal); 1460 signal(SIGINT, skip_signal);
1461 signal(SIGCHLD, skip_signal);
1232 signal(SIGALRM, skip_signal); 1462 signal(SIGALRM, skip_signal);
1233 signal(SIGABRT, skip_signal); 1463 signal(SIGABRT, skip_signal);
1234 1464
@@ -1238,17 +1468,17 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1238 fprintf(output, "[ perf stat: executing run #%d ... ]\n", 1468 fprintf(output, "[ perf stat: executing run #%d ... ]\n",
1239 run_idx + 1); 1469 run_idx + 1);
1240 1470
1241 if (sync_run)
1242 sync();
1243
1244 status = run_perf_stat(argc, argv); 1471 status = run_perf_stat(argc, argv);
1245 } 1472 }
1246 1473
1247 if (status != -1) 1474 if (status != -1 && !interval)
1248 print_stat(argc, argv); 1475 print_stat(argc, argv);
1249out_free_fd: 1476out_free_fd:
1250 list_for_each_entry(pos, &evsel_list->entries, node) 1477 list_for_each_entry(pos, &evsel_list->entries, node) {
1251 perf_evsel__free_stat_priv(pos); 1478 perf_evsel__free_stat_priv(pos);
1479 perf_evsel__free_counts(pos);
1480 perf_evsel__free_prev_raw_counts(pos);
1481 }
1252 perf_evlist__delete_maps(evsel_list); 1482 perf_evlist__delete_maps(evsel_list);
1253out: 1483out:
1254 perf_evlist__delete(evsel_list); 1484 perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
deleted file mode 100644
index 484f26cc0c00..000000000000
--- a/tools/perf/builtin-test.c
+++ /dev/null
@@ -1,1547 +0,0 @@
1/*
2 * builtin-test.c
3 *
4 * Builtin regression testing command: ever growing number of sanity tests
5 */
6#include "builtin.h"
7
8#include "util/cache.h"
9#include "util/debug.h"
10#include "util/debugfs.h"
11#include "util/evlist.h"
12#include "util/parse-options.h"
13#include "util/parse-events.h"
14#include "util/symbol.h"
15#include "util/thread_map.h"
16#include "util/pmu.h"
17#include "event-parse.h"
18#include "../../include/linux/hw_breakpoint.h"
19
20#include <sys/mman.h>
21
22static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
23 struct symbol *sym)
24{
25 bool *visited = symbol__priv(sym);
26 *visited = true;
27 return 0;
28}
29
30static int test__vmlinux_matches_kallsyms(void)
31{
32 int err = -1;
33 struct rb_node *nd;
34 struct symbol *sym;
35 struct map *kallsyms_map, *vmlinux_map;
36 struct machine kallsyms, vmlinux;
37 enum map_type type = MAP__FUNCTION;
38 long page_size = sysconf(_SC_PAGE_SIZE);
39 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
40
41 /*
42 * Step 1:
43 *
44 * Init the machines that will hold kernel, modules obtained from
45 * both vmlinux + .ko files and from /proc/kallsyms split by modules.
46 */
47 machine__init(&kallsyms, "", HOST_KERNEL_ID);
48 machine__init(&vmlinux, "", HOST_KERNEL_ID);
49
50 /*
51 * Step 2:
52 *
53 * Create the kernel maps for kallsyms and the DSO where we will then
54 * load /proc/kallsyms. Also create the modules maps from /proc/modules
55 * and find the .ko files that match them in /lib/modules/`uname -r`/.
56 */
57 if (machine__create_kernel_maps(&kallsyms) < 0) {
58 pr_debug("machine__create_kernel_maps ");
59 return -1;
60 }
61
62 /*
63 * Step 3:
64 *
65 * Load and split /proc/kallsyms into multiple maps, one per module.
66 */
67 if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) {
68 pr_debug("dso__load_kallsyms ");
69 goto out;
70 }
71
72 /*
73 * Step 4:
74 *
75 * kallsyms will be internally on demand sorted by name so that we can
76 * find the reference relocation * symbol, i.e. the symbol we will use
77 * to see if the running kernel was relocated by checking if it has the
78 * same value in the vmlinux file we load.
79 */
80 kallsyms_map = machine__kernel_map(&kallsyms, type);
81
82 sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL);
83 if (sym == NULL) {
84 pr_debug("dso__find_symbol_by_name ");
85 goto out;
86 }
87
88 ref_reloc_sym.addr = sym->start;
89
90 /*
91 * Step 5:
92 *
93 * Now repeat step 2, this time for the vmlinux file we'll auto-locate.
94 */
95 if (machine__create_kernel_maps(&vmlinux) < 0) {
96 pr_debug("machine__create_kernel_maps ");
97 goto out;
98 }
99
100 vmlinux_map = machine__kernel_map(&vmlinux, type);
101 map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym;
102
103 /*
104 * Step 6:
105 *
106 * Locate a vmlinux file in the vmlinux path that has a buildid that
107 * matches the one of the running kernel.
108 *
109 * While doing that look if we find the ref reloc symbol, if we find it
110 * we'll have its ref_reloc_symbol.unrelocated_addr and then
111 * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
112 * to fixup the symbols.
113 */
114 if (machine__load_vmlinux_path(&vmlinux, type,
115 vmlinux_matches_kallsyms_filter) <= 0) {
116 pr_debug("machine__load_vmlinux_path ");
117 goto out;
118 }
119
120 err = 0;
121 /*
122 * Step 7:
123 *
124 * Now look at the symbols in the vmlinux DSO and check if we find all of them
125 * in the kallsyms dso. For the ones that are in both, check its names and
126 * end addresses too.
127 */
128 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
129 struct symbol *pair, *first_pair;
130 bool backwards = true;
131
132 sym = rb_entry(nd, struct symbol, rb_node);
133
134 if (sym->start == sym->end)
135 continue;
136
137 first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
138 pair = first_pair;
139
140 if (pair && pair->start == sym->start) {
141next_pair:
142 if (strcmp(sym->name, pair->name) == 0) {
143 /*
144 * kallsyms don't have the symbol end, so we
145 * set that by using the next symbol start - 1,
146 * in some cases we get this up to a page
147 * wrong, trace_kmalloc when I was developing
148 * this code was one such example, 2106 bytes
149 * off the real size. More than that and we
150 * _really_ have a problem.
151 */
152 s64 skew = sym->end - pair->end;
153 if (llabs(skew) < page_size)
154 continue;
155
156 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
157 sym->start, sym->name, sym->end, pair->end);
158 } else {
159 struct rb_node *nnd;
160detour:
161 nnd = backwards ? rb_prev(&pair->rb_node) :
162 rb_next(&pair->rb_node);
163 if (nnd) {
164 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
165
166 if (next->start == sym->start) {
167 pair = next;
168 goto next_pair;
169 }
170 }
171
172 if (backwards) {
173 backwards = false;
174 pair = first_pair;
175 goto detour;
176 }
177
178 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
179 sym->start, sym->name, pair->name);
180 }
181 } else
182 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
183
184 err = -1;
185 }
186
187 if (!verbose)
188 goto out;
189
190 pr_info("Maps only in vmlinux:\n");
191
192 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
193 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
194 /*
195 * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
196 * the kernel will have the path for the vmlinux file being used,
197 * so use the short name, less descriptive but the same ("[kernel]" in
198 * both cases.
199 */
200 pair = map_groups__find_by_name(&kallsyms.kmaps, type,
201 (pos->dso->kernel ?
202 pos->dso->short_name :
203 pos->dso->name));
204 if (pair)
205 pair->priv = 1;
206 else
207 map__fprintf(pos, stderr);
208 }
209
210 pr_info("Maps in vmlinux with a different name in kallsyms:\n");
211
212 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
213 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
214
215 pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
216 if (pair == NULL || pair->priv)
217 continue;
218
219 if (pair->start == pos->start) {
220 pair->priv = 1;
221 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
222 pos->start, pos->end, pos->pgoff, pos->dso->name);
223 if (pos->pgoff != pair->pgoff || pos->end != pair->end)
224 pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
225 pair->start, pair->end, pair->pgoff);
226 pr_info(" %s\n", pair->dso->name);
227 pair->priv = 1;
228 }
229 }
230
231 pr_info("Maps only in kallsyms:\n");
232
233 for (nd = rb_first(&kallsyms.kmaps.maps[type]);
234 nd; nd = rb_next(nd)) {
235 struct map *pos = rb_entry(nd, struct map, rb_node);
236
237 if (!pos->priv)
238 map__fprintf(pos, stderr);
239 }
240out:
241 return err;
242}
243
244#include "util/cpumap.h"
245#include "util/evsel.h"
246#include <sys/types.h>
247
248static int trace_event__id(const char *evname)
249{
250 char *filename;
251 int err = -1, fd;
252
253 if (asprintf(&filename,
254 "%s/syscalls/%s/id",
255 tracing_events_path, evname) < 0)
256 return -1;
257
258 fd = open(filename, O_RDONLY);
259 if (fd >= 0) {
260 char id[16];
261 if (read(fd, id, sizeof(id)) > 0)
262 err = atoi(id);
263 close(fd);
264 }
265
266 free(filename);
267 return err;
268}
269
270static int test__open_syscall_event(void)
271{
272 int err = -1, fd;
273 struct thread_map *threads;
274 struct perf_evsel *evsel;
275 struct perf_event_attr attr;
276 unsigned int nr_open_calls = 111, i;
277 int id = trace_event__id("sys_enter_open");
278
279 if (id < 0) {
280 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
281 return -1;
282 }
283
284 threads = thread_map__new(-1, getpid(), UINT_MAX);
285 if (threads == NULL) {
286 pr_debug("thread_map__new\n");
287 return -1;
288 }
289
290 memset(&attr, 0, sizeof(attr));
291 attr.type = PERF_TYPE_TRACEPOINT;
292 attr.config = id;
293 evsel = perf_evsel__new(&attr, 0);
294 if (evsel == NULL) {
295 pr_debug("perf_evsel__new\n");
296 goto out_thread_map_delete;
297 }
298
299 if (perf_evsel__open_per_thread(evsel, threads) < 0) {
300 pr_debug("failed to open counter: %s, "
301 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
302 strerror(errno));
303 goto out_evsel_delete;
304 }
305
306 for (i = 0; i < nr_open_calls; ++i) {
307 fd = open("/etc/passwd", O_RDONLY);
308 close(fd);
309 }
310
311 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
312 pr_debug("perf_evsel__read_on_cpu\n");
313 goto out_close_fd;
314 }
315
316 if (evsel->counts->cpu[0].val != nr_open_calls) {
317 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
318 nr_open_calls, evsel->counts->cpu[0].val);
319 goto out_close_fd;
320 }
321
322 err = 0;
323out_close_fd:
324 perf_evsel__close_fd(evsel, 1, threads->nr);
325out_evsel_delete:
326 perf_evsel__delete(evsel);
327out_thread_map_delete:
328 thread_map__delete(threads);
329 return err;
330}
331
332#include <sched.h>
333
334static int test__open_syscall_event_on_all_cpus(void)
335{
336 int err = -1, fd, cpu;
337 struct thread_map *threads;
338 struct cpu_map *cpus;
339 struct perf_evsel *evsel;
340 struct perf_event_attr attr;
341 unsigned int nr_open_calls = 111, i;
342 cpu_set_t cpu_set;
343 int id = trace_event__id("sys_enter_open");
344
345 if (id < 0) {
346 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
347 return -1;
348 }
349
350 threads = thread_map__new(-1, getpid(), UINT_MAX);
351 if (threads == NULL) {
352 pr_debug("thread_map__new\n");
353 return -1;
354 }
355
356 cpus = cpu_map__new(NULL);
357 if (cpus == NULL) {
358 pr_debug("cpu_map__new\n");
359 goto out_thread_map_delete;
360 }
361
362
363 CPU_ZERO(&cpu_set);
364
365 memset(&attr, 0, sizeof(attr));
366 attr.type = PERF_TYPE_TRACEPOINT;
367 attr.config = id;
368 evsel = perf_evsel__new(&attr, 0);
369 if (evsel == NULL) {
370 pr_debug("perf_evsel__new\n");
371 goto out_thread_map_delete;
372 }
373
374 if (perf_evsel__open(evsel, cpus, threads) < 0) {
375 pr_debug("failed to open counter: %s, "
376 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
377 strerror(errno));
378 goto out_evsel_delete;
379 }
380
381 for (cpu = 0; cpu < cpus->nr; ++cpu) {
382 unsigned int ncalls = nr_open_calls + cpu;
383 /*
384 * XXX eventually lift this restriction in a way that
385 * keeps perf building on older glibc installations
386 * without CPU_ALLOC. 1024 cpus in 2010 still seems
387 * a reasonable upper limit tho :-)
388 */
389 if (cpus->map[cpu] >= CPU_SETSIZE) {
390 pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
391 continue;
392 }
393
394 CPU_SET(cpus->map[cpu], &cpu_set);
395 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
396 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
397 cpus->map[cpu],
398 strerror(errno));
399 goto out_close_fd;
400 }
401 for (i = 0; i < ncalls; ++i) {
402 fd = open("/etc/passwd", O_RDONLY);
403 close(fd);
404 }
405 CPU_CLR(cpus->map[cpu], &cpu_set);
406 }
407
408 /*
409 * Here we need to explicitely preallocate the counts, as if
410 * we use the auto allocation it will allocate just for 1 cpu,
411 * as we start by cpu 0.
412 */
413 if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
414 pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
415 goto out_close_fd;
416 }
417
418 err = 0;
419
420 for (cpu = 0; cpu < cpus->nr; ++cpu) {
421 unsigned int expected;
422
423 if (cpus->map[cpu] >= CPU_SETSIZE)
424 continue;
425
426 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
427 pr_debug("perf_evsel__read_on_cpu\n");
428 err = -1;
429 break;
430 }
431
432 expected = nr_open_calls + cpu;
433 if (evsel->counts->cpu[cpu].val != expected) {
434 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
435 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
436 err = -1;
437 }
438 }
439
440out_close_fd:
441 perf_evsel__close_fd(evsel, 1, threads->nr);
442out_evsel_delete:
443 perf_evsel__delete(evsel);
444out_thread_map_delete:
445 thread_map__delete(threads);
446 return err;
447}
448
449/*
450 * This test will generate random numbers of calls to some getpid syscalls,
451 * then establish an mmap for a group of events that are created to monitor
452 * the syscalls.
453 *
454 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
455 * sample.id field to map back to its respective perf_evsel instance.
456 *
457 * Then it checks if the number of syscalls reported as perf events by
458 * the kernel corresponds to the number of syscalls made.
459 */
460static int test__basic_mmap(void)
461{
462 int err = -1;
463 union perf_event *event;
464 struct thread_map *threads;
465 struct cpu_map *cpus;
466 struct perf_evlist *evlist;
467 struct perf_event_attr attr = {
468 .type = PERF_TYPE_TRACEPOINT,
469 .read_format = PERF_FORMAT_ID,
470 .sample_type = PERF_SAMPLE_ID,
471 .watermark = 0,
472 };
473 cpu_set_t cpu_set;
474 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
475 "getpgid", };
476 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
477 (void*)getpgid };
478#define nsyscalls ARRAY_SIZE(syscall_names)
479 int ids[nsyscalls];
480 unsigned int nr_events[nsyscalls],
481 expected_nr_events[nsyscalls], i, j;
482 struct perf_evsel *evsels[nsyscalls], *evsel;
483
484 for (i = 0; i < nsyscalls; ++i) {
485 char name[64];
486
487 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
488 ids[i] = trace_event__id(name);
489 if (ids[i] < 0) {
490 pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
491 return -1;
492 }
493 nr_events[i] = 0;
494 expected_nr_events[i] = random() % 257;
495 }
496
497 threads = thread_map__new(-1, getpid(), UINT_MAX);
498 if (threads == NULL) {
499 pr_debug("thread_map__new\n");
500 return -1;
501 }
502
503 cpus = cpu_map__new(NULL);
504 if (cpus == NULL) {
505 pr_debug("cpu_map__new\n");
506 goto out_free_threads;
507 }
508
509 CPU_ZERO(&cpu_set);
510 CPU_SET(cpus->map[0], &cpu_set);
511 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
512 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
513 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
514 cpus->map[0], strerror(errno));
515 goto out_free_cpus;
516 }
517
518 evlist = perf_evlist__new(cpus, threads);
519 if (evlist == NULL) {
520 pr_debug("perf_evlist__new\n");
521 goto out_free_cpus;
522 }
523
524 /* anonymous union fields, can't be initialized above */
525 attr.wakeup_events = 1;
526 attr.sample_period = 1;
527
528 for (i = 0; i < nsyscalls; ++i) {
529 attr.config = ids[i];
530 evsels[i] = perf_evsel__new(&attr, i);
531 if (evsels[i] == NULL) {
532 pr_debug("perf_evsel__new\n");
533 goto out_free_evlist;
534 }
535
536 perf_evlist__add(evlist, evsels[i]);
537
538 if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
539 pr_debug("failed to open counter: %s, "
540 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
541 strerror(errno));
542 goto out_close_fd;
543 }
544 }
545
546 if (perf_evlist__mmap(evlist, 128, true) < 0) {
547 pr_debug("failed to mmap events: %d (%s)\n", errno,
548 strerror(errno));
549 goto out_close_fd;
550 }
551
552 for (i = 0; i < nsyscalls; ++i)
553 for (j = 0; j < expected_nr_events[i]; ++j) {
554 int foo = syscalls[i]();
555 ++foo;
556 }
557
558 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
559 struct perf_sample sample;
560
561 if (event->header.type != PERF_RECORD_SAMPLE) {
562 pr_debug("unexpected %s event\n",
563 perf_event__name(event->header.type));
564 goto out_munmap;
565 }
566
567 err = perf_evlist__parse_sample(evlist, event, &sample);
568 if (err) {
569 pr_err("Can't parse sample, err = %d\n", err);
570 goto out_munmap;
571 }
572
573 evsel = perf_evlist__id2evsel(evlist, sample.id);
574 if (evsel == NULL) {
575 pr_debug("event with id %" PRIu64
576 " doesn't map to an evsel\n", sample.id);
577 goto out_munmap;
578 }
579 nr_events[evsel->idx]++;
580 }
581
582 list_for_each_entry(evsel, &evlist->entries, node) {
583 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
584 pr_debug("expected %d %s events, got %d\n",
585 expected_nr_events[evsel->idx],
586 perf_evsel__name(evsel), nr_events[evsel->idx]);
587 goto out_munmap;
588 }
589 }
590
591 err = 0;
592out_munmap:
593 perf_evlist__munmap(evlist);
594out_close_fd:
595 for (i = 0; i < nsyscalls; ++i)
596 perf_evsel__close_fd(evsels[i], 1, threads->nr);
597out_free_evlist:
598 perf_evlist__delete(evlist);
599out_free_cpus:
600 cpu_map__delete(cpus);
601out_free_threads:
602 thread_map__delete(threads);
603 return err;
604#undef nsyscalls
605}
606
607static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
608 size_t *sizep)
609{
610 cpu_set_t *mask;
611 size_t size;
612 int i, cpu = -1, nrcpus = 1024;
613realloc:
614 mask = CPU_ALLOC(nrcpus);
615 size = CPU_ALLOC_SIZE(nrcpus);
616 CPU_ZERO_S(size, mask);
617
618 if (sched_getaffinity(pid, size, mask) == -1) {
619 CPU_FREE(mask);
620 if (errno == EINVAL && nrcpus < (1024 << 8)) {
621 nrcpus = nrcpus << 2;
622 goto realloc;
623 }
624 perror("sched_getaffinity");
625 return -1;
626 }
627
628 for (i = 0; i < nrcpus; i++) {
629 if (CPU_ISSET_S(i, size, mask)) {
630 if (cpu == -1) {
631 cpu = i;
632 *maskp = mask;
633 *sizep = size;
634 } else
635 CPU_CLR_S(i, size, mask);
636 }
637 }
638
639 if (cpu == -1)
640 CPU_FREE(mask);
641
642 return cpu;
643}
644
645static int test__PERF_RECORD(void)
646{
647 struct perf_record_opts opts = {
648 .target = {
649 .uid = UINT_MAX,
650 .uses_mmap = true,
651 },
652 .no_delay = true,
653 .freq = 10,
654 .mmap_pages = 256,
655 };
656 cpu_set_t *cpu_mask = NULL;
657 size_t cpu_mask_size = 0;
658 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
659 struct perf_evsel *evsel;
660 struct perf_sample sample;
661 const char *cmd = "sleep";
662 const char *argv[] = { cmd, "1", NULL, };
663 char *bname;
664 u64 prev_time = 0;
665 bool found_cmd_mmap = false,
666 found_libc_mmap = false,
667 found_vdso_mmap = false,
668 found_ld_mmap = false;
669 int err = -1, errs = 0, i, wakeups = 0;
670 u32 cpu;
671 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
672
673 if (evlist == NULL || argv == NULL) {
674 pr_debug("Not enough memory to create evlist\n");
675 goto out;
676 }
677
678 /*
679 * We need at least one evsel in the evlist, use the default
680 * one: "cycles".
681 */
682 err = perf_evlist__add_default(evlist);
683 if (err < 0) {
684 pr_debug("Not enough memory to create evsel\n");
685 goto out_delete_evlist;
686 }
687
688 /*
689 * Create maps of threads and cpus to monitor. In this case
690 * we start with all threads and cpus (-1, -1) but then in
691 * perf_evlist__prepare_workload we'll fill in the only thread
692 * we're monitoring, the one forked there.
693 */
694 err = perf_evlist__create_maps(evlist, &opts.target);
695 if (err < 0) {
696 pr_debug("Not enough memory to create thread/cpu maps\n");
697 goto out_delete_evlist;
698 }
699
700 /*
701 * Prepare the workload in argv[] to run, it'll fork it, and then wait
702 * for perf_evlist__start_workload() to exec it. This is done this way
703 * so that we have time to open the evlist (calling sys_perf_event_open
704 * on all the fds) and then mmap them.
705 */
706 err = perf_evlist__prepare_workload(evlist, &opts, argv);
707 if (err < 0) {
708 pr_debug("Couldn't run the workload!\n");
709 goto out_delete_evlist;
710 }
711
712 /*
713 * Config the evsels, setting attr->comm on the first one, etc.
714 */
715 evsel = perf_evlist__first(evlist);
716 evsel->attr.sample_type |= PERF_SAMPLE_CPU;
717 evsel->attr.sample_type |= PERF_SAMPLE_TID;
718 evsel->attr.sample_type |= PERF_SAMPLE_TIME;
719 perf_evlist__config_attrs(evlist, &opts);
720
721 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask,
722 &cpu_mask_size);
723 if (err < 0) {
724 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
725 goto out_delete_evlist;
726 }
727
728 cpu = err;
729
730 /*
731 * So that we can check perf_sample.cpu on all the samples.
732 */
733 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) {
734 pr_debug("sched_setaffinity: %s\n", strerror(errno));
735 goto out_free_cpu_mask;
736 }
737
738 /*
739 * Call sys_perf_event_open on all the fds on all the evsels,
740 * grouping them if asked to.
741 */
742 err = perf_evlist__open(evlist);
743 if (err < 0) {
744 pr_debug("perf_evlist__open: %s\n", strerror(errno));
745 goto out_delete_evlist;
746 }
747
748 /*
749 * mmap the first fd on a given CPU and ask for events for the other
750 * fds in the same CPU to be injected in the same mmap ring buffer
751 * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)).
752 */
753 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
754 if (err < 0) {
755 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
756 goto out_delete_evlist;
757 }
758
759 /*
760 * Now that all is properly set up, enable the events, they will
761 * count just on workload.pid, which will start...
762 */
763 perf_evlist__enable(evlist);
764
765 /*
766 * Now!
767 */
768 perf_evlist__start_workload(evlist);
769
770 while (1) {
771 int before = total_events;
772
773 for (i = 0; i < evlist->nr_mmaps; i++) {
774 union perf_event *event;
775
776 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
777 const u32 type = event->header.type;
778 const char *name = perf_event__name(type);
779
780 ++total_events;
781 if (type < PERF_RECORD_MAX)
782 nr_events[type]++;
783
784 err = perf_evlist__parse_sample(evlist, event, &sample);
785 if (err < 0) {
786 if (verbose)
787 perf_event__fprintf(event, stderr);
788 pr_debug("Couldn't parse sample\n");
789 goto out_err;
790 }
791
792 if (verbose) {
793 pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
794 perf_event__fprintf(event, stderr);
795 }
796
797 if (prev_time > sample.time) {
798 pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
799 name, prev_time, sample.time);
800 ++errs;
801 }
802
803 prev_time = sample.time;
804
805 if (sample.cpu != cpu) {
806 pr_debug("%s with unexpected cpu, expected %d, got %d\n",
807 name, cpu, sample.cpu);
808 ++errs;
809 }
810
811 if ((pid_t)sample.pid != evlist->workload.pid) {
812 pr_debug("%s with unexpected pid, expected %d, got %d\n",
813 name, evlist->workload.pid, sample.pid);
814 ++errs;
815 }
816
817 if ((pid_t)sample.tid != evlist->workload.pid) {
818 pr_debug("%s with unexpected tid, expected %d, got %d\n",
819 name, evlist->workload.pid, sample.tid);
820 ++errs;
821 }
822
823 if ((type == PERF_RECORD_COMM ||
824 type == PERF_RECORD_MMAP ||
825 type == PERF_RECORD_FORK ||
826 type == PERF_RECORD_EXIT) &&
827 (pid_t)event->comm.pid != evlist->workload.pid) {
828 pr_debug("%s with unexpected pid/tid\n", name);
829 ++errs;
830 }
831
832 if ((type == PERF_RECORD_COMM ||
833 type == PERF_RECORD_MMAP) &&
834 event->comm.pid != event->comm.tid) {
835 pr_debug("%s with different pid/tid!\n", name);
836 ++errs;
837 }
838
839 switch (type) {
840 case PERF_RECORD_COMM:
841 if (strcmp(event->comm.comm, cmd)) {
842 pr_debug("%s with unexpected comm!\n", name);
843 ++errs;
844 }
845 break;
846 case PERF_RECORD_EXIT:
847 goto found_exit;
848 case PERF_RECORD_MMAP:
849 bname = strrchr(event->mmap.filename, '/');
850 if (bname != NULL) {
851 if (!found_cmd_mmap)
852 found_cmd_mmap = !strcmp(bname + 1, cmd);
853 if (!found_libc_mmap)
854 found_libc_mmap = !strncmp(bname + 1, "libc", 4);
855 if (!found_ld_mmap)
856 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
857 } else if (!found_vdso_mmap)
858 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
859 break;
860
861 case PERF_RECORD_SAMPLE:
862 /* Just ignore samples for now */
863 break;
864 default:
865 pr_debug("Unexpected perf_event->header.type %d!\n",
866 type);
867 ++errs;
868 }
869 }
870 }
871
872 /*
873 * We don't use poll here because at least at 3.1 times the
874 * PERF_RECORD_{!SAMPLE} events don't honour
875 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
876 */
877 if (total_events == before && false)
878 poll(evlist->pollfd, evlist->nr_fds, -1);
879
880 sleep(1);
881 if (++wakeups > 5) {
882 pr_debug("No PERF_RECORD_EXIT event!\n");
883 break;
884 }
885 }
886
887found_exit:
888 if (nr_events[PERF_RECORD_COMM] > 1) {
889 pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
890 ++errs;
891 }
892
893 if (nr_events[PERF_RECORD_COMM] == 0) {
894 pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
895 ++errs;
896 }
897
898 if (!found_cmd_mmap) {
899 pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
900 ++errs;
901 }
902
903 if (!found_libc_mmap) {
904 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
905 ++errs;
906 }
907
908 if (!found_ld_mmap) {
909 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
910 ++errs;
911 }
912
913 if (!found_vdso_mmap) {
914 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
915 ++errs;
916 }
917out_err:
918 perf_evlist__munmap(evlist);
919out_free_cpu_mask:
920 CPU_FREE(cpu_mask);
921out_delete_evlist:
922 perf_evlist__delete(evlist);
923out:
924 return (err < 0 || errs > 0) ? -1 : 0;
925}
926
927
928#if defined(__x86_64__) || defined(__i386__)
929
930#define barrier() asm volatile("" ::: "memory")
931
932static u64 rdpmc(unsigned int counter)
933{
934 unsigned int low, high;
935
936 asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
937
938 return low | ((u64)high) << 32;
939}
940
941static u64 rdtsc(void)
942{
943 unsigned int low, high;
944
945 asm volatile("rdtsc" : "=a" (low), "=d" (high));
946
947 return low | ((u64)high) << 32;
948}
949
950static u64 mmap_read_self(void *addr)
951{
952 struct perf_event_mmap_page *pc = addr;
953 u32 seq, idx, time_mult = 0, time_shift = 0;
954 u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
955
956 do {
957 seq = pc->lock;
958 barrier();
959
960 enabled = pc->time_enabled;
961 running = pc->time_running;
962
963 if (enabled != running) {
964 cyc = rdtsc();
965 time_mult = pc->time_mult;
966 time_shift = pc->time_shift;
967 time_offset = pc->time_offset;
968 }
969
970 idx = pc->index;
971 count = pc->offset;
972 if (idx)
973 count += rdpmc(idx - 1);
974
975 barrier();
976 } while (pc->lock != seq);
977
978 if (enabled != running) {
979 u64 quot, rem;
980
981 quot = (cyc >> time_shift);
982 rem = cyc & ((1 << time_shift) - 1);
983 delta = time_offset + quot * time_mult +
984 ((rem * time_mult) >> time_shift);
985
986 enabled += delta;
987 if (idx)
988 running += delta;
989
990 quot = count / running;
991 rem = count % running;
992 count = quot * enabled + (rem * enabled) / running;
993 }
994
995 return count;
996}
997
998/*
999 * If the RDPMC instruction faults then signal this back to the test parent task:
1000 */
1001static void segfault_handler(int sig __maybe_unused,
1002 siginfo_t *info __maybe_unused,
1003 void *uc __maybe_unused)
1004{
1005 exit(-1);
1006}
1007
1008static int __test__rdpmc(void)
1009{
1010 long page_size = sysconf(_SC_PAGE_SIZE);
1011 volatile int tmp = 0;
1012 u64 i, loops = 1000;
1013 int n;
1014 int fd;
1015 void *addr;
1016 struct perf_event_attr attr = {
1017 .type = PERF_TYPE_HARDWARE,
1018 .config = PERF_COUNT_HW_INSTRUCTIONS,
1019 .exclude_kernel = 1,
1020 };
1021 u64 delta_sum = 0;
1022 struct sigaction sa;
1023
1024 sigfillset(&sa.sa_mask);
1025 sa.sa_sigaction = segfault_handler;
1026 sigaction(SIGSEGV, &sa, NULL);
1027
1028 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
1029 if (fd < 0) {
1030 pr_err("Error: sys_perf_event_open() syscall returned "
1031 "with %d (%s)\n", fd, strerror(errno));
1032 return -1;
1033 }
1034
1035 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
1036 if (addr == (void *)(-1)) {
1037 pr_err("Error: mmap() syscall returned with (%s)\n",
1038 strerror(errno));
1039 goto out_close;
1040 }
1041
1042 for (n = 0; n < 6; n++) {
1043 u64 stamp, now, delta;
1044
1045 stamp = mmap_read_self(addr);
1046
1047 for (i = 0; i < loops; i++)
1048 tmp++;
1049
1050 now = mmap_read_self(addr);
1051 loops *= 10;
1052
1053 delta = now - stamp;
1054 pr_debug("%14d: %14Lu\n", n, (long long)delta);
1055
1056 delta_sum += delta;
1057 }
1058
1059 munmap(addr, page_size);
1060 pr_debug(" ");
1061out_close:
1062 close(fd);
1063
1064 if (!delta_sum)
1065 return -1;
1066
1067 return 0;
1068}
1069
1070static int test__rdpmc(void)
1071{
1072 int status = 0;
1073 int wret = 0;
1074 int ret;
1075 int pid;
1076
1077 pid = fork();
1078 if (pid < 0)
1079 return -1;
1080
1081 if (!pid) {
1082 ret = __test__rdpmc();
1083
1084 exit(ret);
1085 }
1086
1087 wret = waitpid(pid, &status, 0);
1088 if (wret < 0 || status)
1089 return -1;
1090
1091 return 0;
1092}
1093
1094#endif
1095
1096static int test__perf_pmu(void)
1097{
1098 return perf_pmu__test();
1099}
1100
1101static int perf_evsel__roundtrip_cache_name_test(void)
1102{
1103 char name[128];
1104 int type, op, err = 0, ret = 0, i, idx;
1105 struct perf_evsel *evsel;
1106 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
1107
1108 if (evlist == NULL)
1109 return -ENOMEM;
1110
1111 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
1112 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
1113 /* skip invalid cache type */
1114 if (!perf_evsel__is_cache_op_valid(type, op))
1115 continue;
1116
1117 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
1118 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
1119 name, sizeof(name));
1120 err = parse_events(evlist, name, 0);
1121 if (err)
1122 ret = err;
1123 }
1124 }
1125 }
1126
1127 idx = 0;
1128 evsel = perf_evlist__first(evlist);
1129
1130 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
1131 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
1132 /* skip invalid cache type */
1133 if (!perf_evsel__is_cache_op_valid(type, op))
1134 continue;
1135
1136 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
1137 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
1138 name, sizeof(name));
1139 if (evsel->idx != idx)
1140 continue;
1141
1142 ++idx;
1143
1144 if (strcmp(perf_evsel__name(evsel), name)) {
1145 pr_debug("%s != %s\n", perf_evsel__name(evsel), name);
1146 ret = -1;
1147 }
1148
1149 evsel = perf_evsel__next(evsel);
1150 }
1151 }
1152 }
1153
1154 perf_evlist__delete(evlist);
1155 return ret;
1156}
1157
1158static int __perf_evsel__name_array_test(const char *names[], int nr_names)
1159{
1160 int i, err;
1161 struct perf_evsel *evsel;
1162 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
1163
1164 if (evlist == NULL)
1165 return -ENOMEM;
1166
1167 for (i = 0; i < nr_names; ++i) {
1168 err = parse_events(evlist, names[i], 0);
1169 if (err) {
1170 pr_debug("failed to parse event '%s', err %d\n",
1171 names[i], err);
1172 goto out_delete_evlist;
1173 }
1174 }
1175
1176 err = 0;
1177 list_for_each_entry(evsel, &evlist->entries, node) {
1178 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) {
1179 --err;
1180 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]);
1181 }
1182 }
1183
1184out_delete_evlist:
1185 perf_evlist__delete(evlist);
1186 return err;
1187}
1188
1189#define perf_evsel__name_array_test(names) \
1190 __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
1191
1192static int perf_evsel__roundtrip_name_test(void)
1193{
1194 int err = 0, ret = 0;
1195
1196 err = perf_evsel__name_array_test(perf_evsel__hw_names);
1197 if (err)
1198 ret = err;
1199
1200 err = perf_evsel__name_array_test(perf_evsel__sw_names);
1201 if (err)
1202 ret = err;
1203
1204 err = perf_evsel__roundtrip_cache_name_test();
1205 if (err)
1206 ret = err;
1207
1208 return ret;
1209}
1210
1211static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
1212 int size, bool should_be_signed)
1213{
1214 struct format_field *field = perf_evsel__field(evsel, name);
1215 int is_signed;
1216 int ret = 0;
1217
1218 if (field == NULL) {
1219 pr_debug("%s: \"%s\" field not found!\n", evsel->name, name);
1220 return -1;
1221 }
1222
1223 is_signed = !!(field->flags | FIELD_IS_SIGNED);
1224 if (should_be_signed && !is_signed) {
1225 pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
1226 evsel->name, name, is_signed, should_be_signed);
1227 ret = -1;
1228 }
1229
1230 if (field->size != size) {
1231 pr_debug("%s: \"%s\" size (%d) should be %d!\n",
1232 evsel->name, name, field->size, size);
1233 ret = -1;
1234 }
1235
1236 return ret;
1237}
1238
1239static int perf_evsel__tp_sched_test(void)
1240{
1241 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0);
1242 int ret = 0;
1243
1244 if (evsel == NULL) {
1245 pr_debug("perf_evsel__new\n");
1246 return -1;
1247 }
1248
1249 if (perf_evsel__test_field(evsel, "prev_comm", 16, true))
1250 ret = -1;
1251
1252 if (perf_evsel__test_field(evsel, "prev_pid", 4, true))
1253 ret = -1;
1254
1255 if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
1256 ret = -1;
1257
1258 if (perf_evsel__test_field(evsel, "prev_state", 8, true))
1259 ret = -1;
1260
1261 if (perf_evsel__test_field(evsel, "next_comm", 16, true))
1262 ret = -1;
1263
1264 if (perf_evsel__test_field(evsel, "next_pid", 4, true))
1265 ret = -1;
1266
1267 if (perf_evsel__test_field(evsel, "next_prio", 4, true))
1268 ret = -1;
1269
1270 perf_evsel__delete(evsel);
1271
1272 evsel = perf_evsel__newtp("sched", "sched_wakeup", 0);
1273
1274 if (perf_evsel__test_field(evsel, "comm", 16, true))
1275 ret = -1;
1276
1277 if (perf_evsel__test_field(evsel, "pid", 4, true))
1278 ret = -1;
1279
1280 if (perf_evsel__test_field(evsel, "prio", 4, true))
1281 ret = -1;
1282
1283 if (perf_evsel__test_field(evsel, "success", 4, true))
1284 ret = -1;
1285
1286 if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
1287 ret = -1;
1288
1289 return ret;
1290}
1291
1292static int test__syscall_open_tp_fields(void)
1293{
1294 struct perf_record_opts opts = {
1295 .target = {
1296 .uid = UINT_MAX,
1297 .uses_mmap = true,
1298 },
1299 .no_delay = true,
1300 .freq = 1,
1301 .mmap_pages = 256,
1302 .raw_samples = true,
1303 };
1304 const char *filename = "/etc/passwd";
1305 int flags = O_RDONLY | O_DIRECTORY;
1306 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
1307 struct perf_evsel *evsel;
1308 int err = -1, i, nr_events = 0, nr_polls = 0;
1309
1310 if (evlist == NULL) {
1311 pr_debug("%s: perf_evlist__new\n", __func__);
1312 goto out;
1313 }
1314
1315 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
1316 if (evsel == NULL) {
1317 pr_debug("%s: perf_evsel__newtp\n", __func__);
1318 goto out_delete_evlist;
1319 }
1320
1321 perf_evlist__add(evlist, evsel);
1322
1323 err = perf_evlist__create_maps(evlist, &opts.target);
1324 if (err < 0) {
1325 pr_debug("%s: perf_evlist__create_maps\n", __func__);
1326 goto out_delete_evlist;
1327 }
1328
1329 perf_evsel__config(evsel, &opts, evsel);
1330
1331 evlist->threads->map[0] = getpid();
1332
1333 err = perf_evlist__open(evlist);
1334 if (err < 0) {
1335 pr_debug("perf_evlist__open: %s\n", strerror(errno));
1336 goto out_delete_evlist;
1337 }
1338
1339 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1340 if (err < 0) {
1341 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
1342 goto out_delete_evlist;
1343 }
1344
1345 perf_evlist__enable(evlist);
1346
1347 /*
1348 * Generate the event:
1349 */
1350 open(filename, flags);
1351
1352 while (1) {
1353 int before = nr_events;
1354
1355 for (i = 0; i < evlist->nr_mmaps; i++) {
1356 union perf_event *event;
1357
1358 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1359 const u32 type = event->header.type;
1360 int tp_flags;
1361 struct perf_sample sample;
1362
1363 ++nr_events;
1364
1365 if (type != PERF_RECORD_SAMPLE)
1366 continue;
1367
1368 err = perf_evsel__parse_sample(evsel, event, &sample);
1369 if (err) {
1370 pr_err("Can't parse sample, err = %d\n", err);
1371 goto out_munmap;
1372 }
1373
1374 tp_flags = perf_evsel__intval(evsel, &sample, "flags");
1375
1376 if (flags != tp_flags) {
1377 pr_debug("%s: Expected flags=%#x, got %#x\n",
1378 __func__, flags, tp_flags);
1379 goto out_munmap;
1380 }
1381
1382 goto out_ok;
1383 }
1384 }
1385
1386 if (nr_events == before)
1387 poll(evlist->pollfd, evlist->nr_fds, 10);
1388
1389 if (++nr_polls > 5) {
1390 pr_debug("%s: no events!\n", __func__);
1391 goto out_munmap;
1392 }
1393 }
1394out_ok:
1395 err = 0;
1396out_munmap:
1397 perf_evlist__munmap(evlist);
1398out_delete_evlist:
1399 perf_evlist__delete(evlist);
1400out:
1401 return err;
1402}
1403
1404static struct test {
1405 const char *desc;
1406 int (*func)(void);
1407} tests[] = {
1408 {
1409 .desc = "vmlinux symtab matches kallsyms",
1410 .func = test__vmlinux_matches_kallsyms,
1411 },
1412 {
1413 .desc = "detect open syscall event",
1414 .func = test__open_syscall_event,
1415 },
1416 {
1417 .desc = "detect open syscall event on all cpus",
1418 .func = test__open_syscall_event_on_all_cpus,
1419 },
1420 {
1421 .desc = "read samples using the mmap interface",
1422 .func = test__basic_mmap,
1423 },
1424 {
1425 .desc = "parse events tests",
1426 .func = parse_events__test,
1427 },
1428#if defined(__x86_64__) || defined(__i386__)
1429 {
1430 .desc = "x86 rdpmc test",
1431 .func = test__rdpmc,
1432 },
1433#endif
1434 {
1435 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
1436 .func = test__PERF_RECORD,
1437 },
1438 {
1439 .desc = "Test perf pmu format parsing",
1440 .func = test__perf_pmu,
1441 },
1442 {
1443 .desc = "Test dso data interface",
1444 .func = dso__test_data,
1445 },
1446 {
1447 .desc = "roundtrip evsel->name check",
1448 .func = perf_evsel__roundtrip_name_test,
1449 },
1450 {
1451 .desc = "Check parsing of sched tracepoints fields",
1452 .func = perf_evsel__tp_sched_test,
1453 },
1454 {
1455 .desc = "Generate and check syscalls:sys_enter_open event fields",
1456 .func = test__syscall_open_tp_fields,
1457 },
1458 {
1459 .func = NULL,
1460 },
1461};
1462
1463static bool perf_test__matches(int curr, int argc, const char *argv[])
1464{
1465 int i;
1466
1467 if (argc == 0)
1468 return true;
1469
1470 for (i = 0; i < argc; ++i) {
1471 char *end;
1472 long nr = strtoul(argv[i], &end, 10);
1473
1474 if (*end == '\0') {
1475 if (nr == curr + 1)
1476 return true;
1477 continue;
1478 }
1479
1480 if (strstr(tests[curr].desc, argv[i]))
1481 return true;
1482 }
1483
1484 return false;
1485}
1486
1487static int __cmd_test(int argc, const char *argv[])
1488{
1489 int i = 0;
1490
1491 while (tests[i].func) {
1492 int curr = i++, err;
1493
1494 if (!perf_test__matches(curr, argc, argv))
1495 continue;
1496
1497 pr_info("%2d: %s:", i, tests[curr].desc);
1498 pr_debug("\n--- start ---\n");
1499 err = tests[curr].func();
1500 pr_debug("---- end ----\n%s:", tests[curr].desc);
1501 pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
1502 }
1503
1504 return 0;
1505}
1506
1507static int perf_test__list(int argc, const char **argv)
1508{
1509 int i = 0;
1510
1511 while (tests[i].func) {
1512 int curr = i++;
1513
1514 if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
1515 continue;
1516
1517 pr_info("%2d: %s\n", i, tests[curr].desc);
1518 }
1519
1520 return 0;
1521}
1522
1523int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
1524{
1525 const char * const test_usage[] = {
1526 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
1527 NULL,
1528 };
1529 const struct option test_options[] = {
1530 OPT_INCR('v', "verbose", &verbose,
1531 "be more verbose (show symbol address, etc)"),
1532 OPT_END()
1533 };
1534
1535 argc = parse_options(argc, argv, test_options, test_usage, 0);
1536 if (argc >= 1 && !strcmp(argv[0], "list"))
1537 return perf_test__list(argc, argv);
1538
1539 symbol_conf.priv_size = sizeof(int);
1540 symbol_conf.sort_by_name = true;
1541 symbol_conf.try_vmlinux_path = true;
1542
1543 if (symbol__init() < 0)
1544 return -1;
1545
1546 return __cmd_test(argc, argv);
1547}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index f251b613b2f3..ab4cf232b852 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -965,7 +965,7 @@ static void write_svg_file(const char *filename)
965 svg_close(); 965 svg_close();
966} 966}
967 967
968static int __cmd_timechart(const char *input_name, const char *output_name) 968static int __cmd_timechart(const char *output_name)
969{ 969{
970 struct perf_tool perf_timechart = { 970 struct perf_tool perf_timechart = {
971 .comm = process_comm_event, 971 .comm = process_comm_event,
@@ -1061,7 +1061,6 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
1061int cmd_timechart(int argc, const char **argv, 1061int cmd_timechart(int argc, const char **argv,
1062 const char *prefix __maybe_unused) 1062 const char *prefix __maybe_unused)
1063{ 1063{
1064 const char *input_name;
1065 const char *output_name = "output.svg"; 1064 const char *output_name = "output.svg";
1066 const struct option options[] = { 1065 const struct option options[] = {
1067 OPT_STRING('i', "input", &input_name, "file", "input file name"), 1066 OPT_STRING('i', "input", &input_name, "file", "input file name"),
@@ -1092,5 +1091,5 @@ int cmd_timechart(int argc, const char **argv,
1092 1091
1093 setup_pager(); 1092 setup_pager();
1094 1093
1095 return __cmd_timechart(input_name, output_name); 1094 return __cmd_timechart(output_name);
1096} 1095}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ff6db8086805..72f6eb7b4173 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -26,6 +26,7 @@
26#include "util/color.h" 26#include "util/color.h"
27#include "util/evlist.h" 27#include "util/evlist.h"
28#include "util/evsel.h" 28#include "util/evsel.h"
29#include "util/machine.h"
29#include "util/session.h" 30#include "util/session.h"
30#include "util/symbol.h" 31#include "util/symbol.h"
31#include "util/thread.h" 32#include "util/thread.h"
@@ -67,27 +68,7 @@
67#include <linux/unistd.h> 68#include <linux/unistd.h>
68#include <linux/types.h> 69#include <linux/types.h>
69 70
70void get_term_dimensions(struct winsize *ws) 71static volatile int done;
71{
72 char *s = getenv("LINES");
73
74 if (s != NULL) {
75 ws->ws_row = atoi(s);
76 s = getenv("COLUMNS");
77 if (s != NULL) {
78 ws->ws_col = atoi(s);
79 if (ws->ws_row && ws->ws_col)
80 return;
81 }
82 }
83#ifdef TIOCGWINSZ
84 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
85 ws->ws_row && ws->ws_col)
86 return;
87#endif
88 ws->ws_row = 25;
89 ws->ws_col = 80;
90}
91 72
92static void perf_top__update_print_entries(struct perf_top *top) 73static void perf_top__update_print_entries(struct perf_top *top)
93{ 74{
@@ -452,8 +433,10 @@ static int perf_top__key_mapped(struct perf_top *top, int c)
452 return 0; 433 return 0;
453} 434}
454 435
455static void perf_top__handle_keypress(struct perf_top *top, int c) 436static bool perf_top__handle_keypress(struct perf_top *top, int c)
456{ 437{
438 bool ret = true;
439
457 if (!perf_top__key_mapped(top, c)) { 440 if (!perf_top__key_mapped(top, c)) {
458 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 441 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
459 struct termios tc, save; 442 struct termios tc, save;
@@ -474,7 +457,7 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
474 457
475 tcsetattr(0, TCSAFLUSH, &save); 458 tcsetattr(0, TCSAFLUSH, &save);
476 if (!perf_top__key_mapped(top, c)) 459 if (!perf_top__key_mapped(top, c))
477 return; 460 return ret;
478 } 461 }
479 462
480 switch (c) { 463 switch (c) {
@@ -536,7 +519,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
536 printf("exiting.\n"); 519 printf("exiting.\n");
537 if (top->dump_symtab) 520 if (top->dump_symtab)
538 perf_session__fprintf_dsos(top->session, stderr); 521 perf_session__fprintf_dsos(top->session, stderr);
539 exit(0); 522 ret = false;
523 break;
540 case 's': 524 case 's':
541 perf_top__prompt_symbol(top, "Enter details symbol"); 525 perf_top__prompt_symbol(top, "Enter details symbol");
542 break; 526 break;
@@ -559,6 +543,8 @@ static void perf_top__handle_keypress(struct perf_top *top, int c)
559 default: 543 default:
560 break; 544 break;
561 } 545 }
546
547 return ret;
562} 548}
563 549
564static void perf_top__sort_new_samples(void *arg) 550static void perf_top__sort_new_samples(void *arg)
@@ -581,6 +567,11 @@ static void *display_thread_tui(void *arg)
581 struct perf_evsel *pos; 567 struct perf_evsel *pos;
582 struct perf_top *top = arg; 568 struct perf_top *top = arg;
583 const char *help = "For a higher level overview, try: perf top --sort comm,dso"; 569 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
570 struct hist_browser_timer hbt = {
571 .timer = perf_top__sort_new_samples,
572 .arg = top,
573 .refresh = top->delay_secs,
574 };
584 575
585 perf_top__sort_new_samples(top); 576 perf_top__sort_new_samples(top);
586 577
@@ -590,14 +581,12 @@ static void *display_thread_tui(void *arg)
590 * via --uid. 581 * via --uid.
591 */ 582 */
592 list_for_each_entry(pos, &top->evlist->entries, node) 583 list_for_each_entry(pos, &top->evlist->entries, node)
593 pos->hists.uid_filter_str = top->target.uid_str; 584 pos->hists.uid_filter_str = top->record_opts.target.uid_str;
594 585
595 perf_evlist__tui_browse_hists(top->evlist, help, 586 perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
596 perf_top__sort_new_samples, 587 &top->session->header.env);
597 top, top->delay_secs);
598 588
599 exit_browser(0); 589 done = 1;
600 exit(0);
601 return NULL; 590 return NULL;
602} 591}
603 592
@@ -621,7 +610,7 @@ repeat:
621 /* trash return*/ 610 /* trash return*/
622 getc(stdin); 611 getc(stdin);
623 612
624 while (1) { 613 while (!done) {
625 perf_top__print_sym_table(top); 614 perf_top__print_sym_table(top);
626 /* 615 /*
627 * Either timeout expired or we got an EINTR due to SIGWINCH, 616 * Either timeout expired or we got an EINTR due to SIGWINCH,
@@ -635,15 +624,14 @@ repeat:
635 continue; 624 continue;
636 /* Fall trhu */ 625 /* Fall trhu */
637 default: 626 default:
638 goto process_hotkey; 627 c = getc(stdin);
628 tcsetattr(0, TCSAFLUSH, &save);
629
630 if (perf_top__handle_keypress(top, c))
631 goto repeat;
632 done = 1;
639 } 633 }
640 } 634 }
641process_hotkey:
642 c = getc(stdin);
643 tcsetattr(0, TCSAFLUSH, &save);
644
645 perf_top__handle_keypress(top, c);
646 goto repeat;
647 635
648 return NULL; 636 return NULL;
649} 637}
@@ -711,7 +699,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
711 static struct intlist *seen; 699 static struct intlist *seen;
712 700
713 if (!seen) 701 if (!seen)
714 seen = intlist__new(); 702 seen = intlist__new(NULL);
715 703
716 if (!intlist__has_entry(seen, event->ip.pid)) { 704 if (!intlist__has_entry(seen, event->ip.pid)) {
717 pr_err("Can't find guest [%d]'s kernel information\n", 705 pr_err("Can't find guest [%d]'s kernel information\n",
@@ -722,8 +710,8 @@ static void perf_event__process_sample(struct perf_tool *tool,
722 } 710 }
723 711
724 if (!machine) { 712 if (!machine) {
725 pr_err("%u unprocessable samples recorded.", 713 pr_err("%u unprocessable samples recorded.\r",
726 top->session->hists.stats.nr_unprocessable_samples++); 714 top->session->stats.nr_unprocessable_samples++);
727 return; 715 return;
728 } 716 }
729 717
@@ -842,13 +830,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
842 ++top->us_samples; 830 ++top->us_samples;
843 if (top->hide_user_symbols) 831 if (top->hide_user_symbols)
844 continue; 832 continue;
845 machine = perf_session__find_host_machine(session); 833 machine = &session->machines.host;
846 break; 834 break;
847 case PERF_RECORD_MISC_KERNEL: 835 case PERF_RECORD_MISC_KERNEL:
848 ++top->kernel_samples; 836 ++top->kernel_samples;
849 if (top->hide_kernel_symbols) 837 if (top->hide_kernel_symbols)
850 continue; 838 continue;
851 machine = perf_session__find_host_machine(session); 839 machine = &session->machines.host;
852 break; 840 break;
853 case PERF_RECORD_MISC_GUEST_KERNEL: 841 case PERF_RECORD_MISC_GUEST_KERNEL:
854 ++top->guest_kernel_samples; 842 ++top->guest_kernel_samples;
@@ -871,9 +859,9 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
871 &sample, machine); 859 &sample, machine);
872 } else if (event->header.type < PERF_RECORD_MAX) { 860 } else if (event->header.type < PERF_RECORD_MAX) {
873 hists__inc_nr_events(&evsel->hists, event->header.type); 861 hists__inc_nr_events(&evsel->hists, event->header.type);
874 perf_event__process(&top->tool, event, &sample, machine); 862 machine__process_event(machine, event);
875 } else 863 } else
876 ++session->hists.stats.nr_unknown_events; 864 ++session->stats.nr_unknown_events;
877 } 865 }
878} 866}
879 867
@@ -885,119 +873,42 @@ static void perf_top__mmap_read(struct perf_top *top)
885 perf_top__mmap_read_idx(top, i); 873 perf_top__mmap_read_idx(top, i);
886} 874}
887 875
888static void perf_top__start_counters(struct perf_top *top) 876static int perf_top__start_counters(struct perf_top *top)
889{ 877{
878 char msg[512];
890 struct perf_evsel *counter; 879 struct perf_evsel *counter;
891 struct perf_evlist *evlist = top->evlist; 880 struct perf_evlist *evlist = top->evlist;
881 struct perf_record_opts *opts = &top->record_opts;
892 882
893 if (top->group) 883 perf_evlist__config(evlist, opts);
894 perf_evlist__set_leader(evlist);
895 884
896 list_for_each_entry(counter, &evlist->entries, node) { 885 list_for_each_entry(counter, &evlist->entries, node) {
897 struct perf_event_attr *attr = &counter->attr;
898
899 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
900
901 if (top->freq) {
902 attr->sample_type |= PERF_SAMPLE_PERIOD;
903 attr->freq = 1;
904 attr->sample_freq = top->freq;
905 }
906
907 if (evlist->nr_entries > 1) {
908 attr->sample_type |= PERF_SAMPLE_ID;
909 attr->read_format |= PERF_FORMAT_ID;
910 }
911
912 if (perf_target__has_cpu(&top->target))
913 attr->sample_type |= PERF_SAMPLE_CPU;
914
915 if (symbol_conf.use_callchain)
916 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
917
918 attr->mmap = 1;
919 attr->comm = 1;
920 attr->inherit = top->inherit;
921fallback_missing_features:
922 if (top->exclude_guest_missing)
923 attr->exclude_guest = attr->exclude_host = 0;
924retry_sample_id:
925 attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
926try_again: 886try_again:
927 if (perf_evsel__open(counter, top->evlist->cpus, 887 if (perf_evsel__open(counter, top->evlist->cpus,
928 top->evlist->threads) < 0) { 888 top->evlist->threads) < 0) {
929 int err = errno; 889 if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) {
930
931 if (err == EPERM || err == EACCES) {
932 ui__error_paranoid();
933 goto out_err;
934 } else if (err == EINVAL) {
935 if (!top->exclude_guest_missing &&
936 (attr->exclude_guest || attr->exclude_host)) {
937 pr_debug("Old kernel, cannot exclude "
938 "guest or host samples.\n");
939 top->exclude_guest_missing = true;
940 goto fallback_missing_features;
941 } else if (!top->sample_id_all_missing) {
942 /*
943 * Old kernel, no attr->sample_id_type_all field
944 */
945 top->sample_id_all_missing = true;
946 goto retry_sample_id;
947 }
948 }
949 /*
950 * If it's cycles then fall back to hrtimer
951 * based cpu-clock-tick sw counter, which
952 * is always available even if no PMU support:
953 */
954 if ((err == ENOENT || err == ENXIO) &&
955 (attr->type == PERF_TYPE_HARDWARE) &&
956 (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
957
958 if (verbose) 890 if (verbose)
959 ui__warning("Cycles event not supported,\n" 891 ui__warning("%s\n", msg);
960 "trying to fall back to cpu-clock-ticks\n");
961
962 attr->type = PERF_TYPE_SOFTWARE;
963 attr->config = PERF_COUNT_SW_CPU_CLOCK;
964 if (counter->name) {
965 free(counter->name);
966 counter->name = NULL;
967 }
968 goto try_again; 892 goto try_again;
969 } 893 }
970 894
971 if (err == ENOENT) { 895 perf_evsel__open_strerror(counter, &opts->target,
972 ui__error("The %s event is not supported.\n", 896 errno, msg, sizeof(msg));
973 perf_evsel__name(counter)); 897 ui__error("%s\n", msg);
974 goto out_err;
975 } else if (err == EMFILE) {
976 ui__error("Too many events are opened.\n"
977 "Try again after reducing the number of events\n");
978 goto out_err;
979 }
980
981 ui__error("The sys_perf_event_open() syscall "
982 "returned with %d (%s). /bin/dmesg "
983 "may provide additional information.\n"
984 "No CONFIG_PERF_EVENTS=y kernel support "
985 "configured?\n", err, strerror(err));
986 goto out_err; 898 goto out_err;
987 } 899 }
988 } 900 }
989 901
990 if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { 902 if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
991 ui__error("Failed to mmap with %d (%s)\n", 903 ui__error("Failed to mmap with %d (%s)\n",
992 errno, strerror(errno)); 904 errno, strerror(errno));
993 goto out_err; 905 goto out_err;
994 } 906 }
995 907
996 return; 908 return 0;
997 909
998out_err: 910out_err:
999 exit_browser(0); 911 return -1;
1000 exit(0);
1001} 912}
1002 913
1003static int perf_top__setup_sample_type(struct perf_top *top) 914static int perf_top__setup_sample_type(struct perf_top *top)
@@ -1007,7 +918,7 @@ static int perf_top__setup_sample_type(struct perf_top *top)
1007 ui__error("Selected -g but \"sym\" not present in --sort/-s."); 918 ui__error("Selected -g but \"sym\" not present in --sort/-s.");
1008 return -EINVAL; 919 return -EINVAL;
1009 } 920 }
1010 } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { 921 } else if (callchain_param.mode != CHAIN_NONE) {
1011 if (callchain_register_param(&callchain_param) < 0) { 922 if (callchain_register_param(&callchain_param) < 0) {
1012 ui__error("Can't register callchain params.\n"); 923 ui__error("Can't register callchain params.\n");
1013 return -EINVAL; 924 return -EINVAL;
@@ -1019,6 +930,7 @@ static int perf_top__setup_sample_type(struct perf_top *top)
1019 930
1020static int __cmd_top(struct perf_top *top) 931static int __cmd_top(struct perf_top *top)
1021{ 932{
933 struct perf_record_opts *opts = &top->record_opts;
1022 pthread_t thread; 934 pthread_t thread;
1023 int ret; 935 int ret;
1024 /* 936 /*
@@ -1033,26 +945,42 @@ static int __cmd_top(struct perf_top *top)
1033 if (ret) 945 if (ret)
1034 goto out_delete; 946 goto out_delete;
1035 947
1036 if (perf_target__has_task(&top->target)) 948 if (perf_target__has_task(&opts->target))
1037 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 949 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
1038 perf_event__process, 950 perf_event__process,
1039 &top->session->host_machine); 951 &top->session->machines.host);
1040 else 952 else
1041 perf_event__synthesize_threads(&top->tool, perf_event__process, 953 perf_event__synthesize_threads(&top->tool, perf_event__process,
1042 &top->session->host_machine); 954 &top->session->machines.host);
1043 perf_top__start_counters(top); 955
956 ret = perf_top__start_counters(top);
957 if (ret)
958 goto out_delete;
959
1044 top->session->evlist = top->evlist; 960 top->session->evlist = top->evlist;
1045 perf_session__set_id_hdr_size(top->session); 961 perf_session__set_id_hdr_size(top->session);
1046 962
963 /*
964 * When perf is starting the traced process, all the events (apart from
965 * group members) have enable_on_exec=1 set, so don't spoil it by
966 * prematurely enabling them.
967 *
968 * XXX 'top' still doesn't start workloads like record, trace, but should,
969 * so leave the check here.
970 */
971 if (!perf_target__none(&opts->target))
972 perf_evlist__enable(top->evlist);
973
1047 /* Wait for a minimal set of events before starting the snapshot */ 974 /* Wait for a minimal set of events before starting the snapshot */
1048 poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 975 poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1049 976
1050 perf_top__mmap_read(top); 977 perf_top__mmap_read(top);
1051 978
979 ret = -1;
1052 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : 980 if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
1053 display_thread), top)) { 981 display_thread), top)) {
1054 ui__error("Could not create display thread.\n"); 982 ui__error("Could not create display thread.\n");
1055 exit(-1); 983 goto out_delete;
1056 } 984 }
1057 985
1058 if (top->realtime_prio) { 986 if (top->realtime_prio) {
@@ -1061,11 +989,11 @@ static int __cmd_top(struct perf_top *top)
1061 param.sched_priority = top->realtime_prio; 989 param.sched_priority = top->realtime_prio;
1062 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 990 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
1063 ui__error("Could not set realtime priority.\n"); 991 ui__error("Could not set realtime priority.\n");
1064 exit(-1); 992 goto out_delete;
1065 } 993 }
1066 } 994 }
1067 995
1068 while (1) { 996 while (!done) {
1069 u64 hits = top->samples; 997 u64 hits = top->samples;
1070 998
1071 perf_top__mmap_read(top); 999 perf_top__mmap_read(top);
@@ -1074,126 +1002,67 @@ static int __cmd_top(struct perf_top *top)
1074 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); 1002 ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1075 } 1003 }
1076 1004
1005 ret = 0;
1077out_delete: 1006out_delete:
1078 perf_session__delete(top->session); 1007 perf_session__delete(top->session);
1079 top->session = NULL; 1008 top->session = NULL;
1080 1009
1081 return 0; 1010 return ret;
1082} 1011}
1083 1012
1084static int 1013static int
1085parse_callchain_opt(const struct option *opt, const char *arg, int unset) 1014parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1086{ 1015{
1087 struct perf_top *top = (struct perf_top *)opt->value;
1088 char *tok, *tok2;
1089 char *endptr;
1090
1091 /* 1016 /*
1092 * --no-call-graph 1017 * --no-call-graph
1093 */ 1018 */
1094 if (unset) { 1019 if (unset)
1095 top->dont_use_callchains = true;
1096 return 0; 1020 return 0;
1097 }
1098 1021
1099 symbol_conf.use_callchain = true; 1022 symbol_conf.use_callchain = true;
1100 1023
1101 if (!arg) 1024 return record_parse_callchain_opt(opt, arg, unset);
1102 return 0;
1103
1104 tok = strtok((char *)arg, ",");
1105 if (!tok)
1106 return -1;
1107
1108 /* get the output mode */
1109 if (!strncmp(tok, "graph", strlen(arg)))
1110 callchain_param.mode = CHAIN_GRAPH_ABS;
1111
1112 else if (!strncmp(tok, "flat", strlen(arg)))
1113 callchain_param.mode = CHAIN_FLAT;
1114
1115 else if (!strncmp(tok, "fractal", strlen(arg)))
1116 callchain_param.mode = CHAIN_GRAPH_REL;
1117
1118 else if (!strncmp(tok, "none", strlen(arg))) {
1119 callchain_param.mode = CHAIN_NONE;
1120 symbol_conf.use_callchain = false;
1121
1122 return 0;
1123 } else
1124 return -1;
1125
1126 /* get the min percentage */
1127 tok = strtok(NULL, ",");
1128 if (!tok)
1129 goto setup;
1130
1131 callchain_param.min_percent = strtod(tok, &endptr);
1132 if (tok == endptr)
1133 return -1;
1134
1135 /* get the print limit */
1136 tok2 = strtok(NULL, ",");
1137 if (!tok2)
1138 goto setup;
1139
1140 if (tok2[0] != 'c') {
1141 callchain_param.print_limit = strtod(tok2, &endptr);
1142 tok2 = strtok(NULL, ",");
1143 if (!tok2)
1144 goto setup;
1145 }
1146
1147 /* get the call chain order */
1148 if (!strcmp(tok2, "caller"))
1149 callchain_param.order = ORDER_CALLER;
1150 else if (!strcmp(tok2, "callee"))
1151 callchain_param.order = ORDER_CALLEE;
1152 else
1153 return -1;
1154setup:
1155 if (callchain_register_param(&callchain_param) < 0) {
1156 fprintf(stderr, "Can't register callchain params\n");
1157 return -1;
1158 }
1159 return 0;
1160} 1025}
1161 1026
1162int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1027int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1163{ 1028{
1164 struct perf_evsel *pos;
1165 int status; 1029 int status;
1166 char errbuf[BUFSIZ]; 1030 char errbuf[BUFSIZ];
1167 struct perf_top top = { 1031 struct perf_top top = {
1168 .count_filter = 5, 1032 .count_filter = 5,
1169 .delay_secs = 2, 1033 .delay_secs = 2,
1170 .freq = 4000, /* 4 KHz */ 1034 .record_opts = {
1171 .mmap_pages = 128, 1035 .mmap_pages = UINT_MAX,
1172 .sym_pcnt_filter = 5, 1036 .user_freq = UINT_MAX,
1173 .target = { 1037 .user_interval = ULLONG_MAX,
1174 .uses_mmap = true, 1038 .freq = 4000, /* 4 KHz */
1039 .target = {
1040 .uses_mmap = true,
1041 },
1175 }, 1042 },
1043 .sym_pcnt_filter = 5,
1176 }; 1044 };
1177 char callchain_default_opt[] = "fractal,0.5,callee"; 1045 struct perf_record_opts *opts = &top.record_opts;
1046 struct perf_target *target = &opts->target;
1178 const struct option options[] = { 1047 const struct option options[] = {
1179 OPT_CALLBACK('e', "event", &top.evlist, "event", 1048 OPT_CALLBACK('e', "event", &top.evlist, "event",
1180 "event selector. use 'perf list' to list available events", 1049 "event selector. use 'perf list' to list available events",
1181 parse_events_option), 1050 parse_events_option),
1182 OPT_INTEGER('c', "count", &top.default_interval, 1051 OPT_U64('c', "count", &opts->user_interval, "event period to sample"),
1183 "event period to sample"), 1052 OPT_STRING('p', "pid", &target->pid, "pid",
1184 OPT_STRING('p', "pid", &top.target.pid, "pid",
1185 "profile events on existing process id"), 1053 "profile events on existing process id"),
1186 OPT_STRING('t', "tid", &top.target.tid, "tid", 1054 OPT_STRING('t', "tid", &target->tid, "tid",
1187 "profile events on existing thread id"), 1055 "profile events on existing thread id"),
1188 OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide, 1056 OPT_BOOLEAN('a', "all-cpus", &target->system_wide,
1189 "system-wide collection from all CPUs"), 1057 "system-wide collection from all CPUs"),
1190 OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu", 1058 OPT_STRING('C', "cpu", &target->cpu_list, "cpu",
1191 "list of cpus to monitor"), 1059 "list of cpus to monitor"),
1192 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1060 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1193 "file", "vmlinux pathname"), 1061 "file", "vmlinux pathname"),
1194 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, 1062 OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1195 "hide kernel symbols"), 1063 "hide kernel symbols"),
1196 OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), 1064 OPT_UINTEGER('m', "mmap-pages", &opts->mmap_pages,
1065 "number of mmap data pages"),
1197 OPT_INTEGER('r', "realtime", &top.realtime_prio, 1066 OPT_INTEGER('r', "realtime", &top.realtime_prio,
1198 "collect data with this RT SCHED_FIFO priority"), 1067 "collect data with this RT SCHED_FIFO priority"),
1199 OPT_INTEGER('d', "delay", &top.delay_secs, 1068 OPT_INTEGER('d', "delay", &top.delay_secs,
@@ -1202,16 +1071,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1202 "dump the symbol table used for profiling"), 1071 "dump the symbol table used for profiling"),
1203 OPT_INTEGER('f', "count-filter", &top.count_filter, 1072 OPT_INTEGER('f', "count-filter", &top.count_filter,
1204 "only display functions with more events than this"), 1073 "only display functions with more events than this"),
1205 OPT_BOOLEAN('g', "group", &top.group, 1074 OPT_BOOLEAN('g', "group", &opts->group,
1206 "put the counters into a counter group"), 1075 "put the counters into a counter group"),
1207 OPT_BOOLEAN('i', "inherit", &top.inherit, 1076 OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit,
1208 "child tasks inherit counters"), 1077 "child tasks do not inherit counters"),
1209 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", 1078 OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
1210 "symbol to annotate"), 1079 "symbol to annotate"),
1211 OPT_BOOLEAN('z', "zero", &top.zero, 1080 OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"),
1212 "zero history across updates"), 1081 OPT_UINTEGER('F', "freq", &opts->user_freq, "profile at this frequency"),
1213 OPT_INTEGER('F', "freq", &top.freq,
1214 "profile at this frequency"),
1215 OPT_INTEGER('E', "entries", &top.print_entries, 1082 OPT_INTEGER('E', "entries", &top.print_entries,
1216 "display this many functions"), 1083 "display this many functions"),
1217 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, 1084 OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
@@ -1224,10 +1091,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1224 "sort by key(s): pid, comm, dso, symbol, parent"), 1091 "sort by key(s): pid, comm, dso, symbol, parent"),
1225 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 1092 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1226 "Show a column with the number of samples"), 1093 "Show a column with the number of samples"),
1227 OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", 1094 OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
1228 "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " 1095 "mode[,dump_size]", record_callchain_help,
1229 "Default: fractal,0.5,callee", &parse_callchain_opt, 1096 &parse_callchain_opt, "fp"),
1230 callchain_default_opt),
1231 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, 1097 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1232 "Show a column with the sum of periods"), 1098 "Show a column with the sum of periods"),
1233 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 1099 OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
@@ -1242,7 +1108,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1242 "Display raw encoding of assembly instructions (default)"), 1108 "Display raw encoding of assembly instructions (default)"),
1243 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1109 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1244 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1110 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1245 OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"), 1111 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
1246 OPT_END() 1112 OPT_END()
1247 }; 1113 };
1248 const char * const top_usage[] = { 1114 const char * const top_usage[] = {
@@ -1263,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1263 if (sort_order == default_sort_order) 1129 if (sort_order == default_sort_order)
1264 sort_order = "dso,symbol"; 1130 sort_order = "dso,symbol";
1265 1131
1266 setup_sorting(top_usage, options); 1132 if (setup_sorting() < 0)
1133 usage_with_options(top_usage, options);
1267 1134
1268 if (top.use_stdio) 1135 if (top.use_stdio)
1269 use_browser = 0; 1136 use_browser = 0;
@@ -1272,33 +1139,33 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1272 1139
1273 setup_browser(false); 1140 setup_browser(false);
1274 1141
1275 status = perf_target__validate(&top.target); 1142 status = perf_target__validate(target);
1276 if (status) { 1143 if (status) {
1277 perf_target__strerror(&top.target, status, errbuf, BUFSIZ); 1144 perf_target__strerror(target, status, errbuf, BUFSIZ);
1278 ui__warning("%s", errbuf); 1145 ui__warning("%s", errbuf);
1279 } 1146 }
1280 1147
1281 status = perf_target__parse_uid(&top.target); 1148 status = perf_target__parse_uid(target);
1282 if (status) { 1149 if (status) {
1283 int saved_errno = errno; 1150 int saved_errno = errno;
1284 1151
1285 perf_target__strerror(&top.target, status, errbuf, BUFSIZ); 1152 perf_target__strerror(target, status, errbuf, BUFSIZ);
1286 ui__error("%s", errbuf); 1153 ui__error("%s", errbuf);
1287 1154
1288 status = -saved_errno; 1155 status = -saved_errno;
1289 goto out_delete_evlist; 1156 goto out_delete_evlist;
1290 } 1157 }
1291 1158
1292 if (perf_target__none(&top.target)) 1159 if (perf_target__none(target))
1293 top.target.system_wide = true; 1160 target->system_wide = true;
1294 1161
1295 if (perf_evlist__create_maps(top.evlist, &top.target) < 0) 1162 if (perf_evlist__create_maps(top.evlist, target) < 0)
1296 usage_with_options(top_usage, options); 1163 usage_with_options(top_usage, options);
1297 1164
1298 if (!top.evlist->nr_entries && 1165 if (!top.evlist->nr_entries &&
1299 perf_evlist__add_default(top.evlist) < 0) { 1166 perf_evlist__add_default(top.evlist) < 0) {
1300 ui__error("Not enough memory for event selector list\n"); 1167 ui__error("Not enough memory for event selector list\n");
1301 return -ENOMEM; 1168 goto out_delete_maps;
1302 } 1169 }
1303 1170
1304 symbol_conf.nr_events = top.evlist->nr_entries; 1171 symbol_conf.nr_events = top.evlist->nr_entries;
@@ -1306,24 +1173,22 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1306 if (top.delay_secs < 1) 1173 if (top.delay_secs < 1)
1307 top.delay_secs = 1; 1174 top.delay_secs = 1;
1308 1175
1176 if (opts->user_interval != ULLONG_MAX)
1177 opts->default_interval = opts->user_interval;
1178 if (opts->user_freq != UINT_MAX)
1179 opts->freq = opts->user_freq;
1180
1309 /* 1181 /*
1310 * User specified count overrides default frequency. 1182 * User specified count overrides default frequency.
1311 */ 1183 */
1312 if (top.default_interval) 1184 if (opts->default_interval)
1313 top.freq = 0; 1185 opts->freq = 0;
1314 else if (top.freq) { 1186 else if (opts->freq) {
1315 top.default_interval = top.freq; 1187 opts->default_interval = opts->freq;
1316 } else { 1188 } else {
1317 ui__error("frequency and count are zero, aborting\n"); 1189 ui__error("frequency and count are zero, aborting\n");
1318 exit(EXIT_FAILURE); 1190 status = -EINVAL;
1319 } 1191 goto out_delete_maps;
1320
1321 list_for_each_entry(pos, &top.evlist->entries, node) {
1322 /*
1323 * Fill in the ones not specifically initialized via -c:
1324 */
1325 if (!pos->attr.sample_period)
1326 pos->attr.sample_period = top.default_interval;
1327 } 1192 }
1328 1193
1329 top.sym_evsel = perf_evlist__first(top.evlist); 1194 top.sym_evsel = perf_evlist__first(top.evlist);
@@ -1356,6 +1221,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1356 1221
1357 status = __cmd_top(&top); 1222 status = __cmd_top(&top);
1358 1223
1224out_delete_maps:
1225 perf_evlist__delete_maps(top.evlist);
1359out_delete_evlist: 1226out_delete_evlist:
1360 perf_evlist__delete(top.evlist); 1227 perf_evlist__delete(top.evlist);
1361 1228
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 7aaee39f6774..d222d7fc7e96 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1,5 +1,8 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "util/color.h"
2#include "util/evlist.h" 3#include "util/evlist.h"
4#include "util/machine.h"
5#include "util/thread.h"
3#include "util/parse-options.h" 6#include "util/parse-options.h"
4#include "util/thread_map.h" 7#include "util/thread_map.h"
5#include "event-parse.h" 8#include "event-parse.h"
@@ -13,15 +16,18 @@ static struct syscall_fmt {
13 bool errmsg; 16 bool errmsg;
14 bool timeout; 17 bool timeout;
15} syscall_fmts[] = { 18} syscall_fmts[] = {
19 { .name = "access", .errmsg = true, },
16 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, 20 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
17 { .name = "fstat", .errmsg = true, .alias = "newfstat", }, 21 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
18 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, 22 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
19 { .name = "futex", .errmsg = true, }, 23 { .name = "futex", .errmsg = true, },
24 { .name = "open", .errmsg = true, },
20 { .name = "poll", .errmsg = true, .timeout = true, }, 25 { .name = "poll", .errmsg = true, .timeout = true, },
21 { .name = "ppoll", .errmsg = true, .timeout = true, }, 26 { .name = "ppoll", .errmsg = true, .timeout = true, },
22 { .name = "read", .errmsg = true, }, 27 { .name = "read", .errmsg = true, },
23 { .name = "recvfrom", .errmsg = true, }, 28 { .name = "recvfrom", .errmsg = true, },
24 { .name = "select", .errmsg = true, .timeout = true, }, 29 { .name = "select", .errmsg = true, .timeout = true, },
30 { .name = "socket", .errmsg = true, },
25 { .name = "stat", .errmsg = true, .alias = "newstat", }, 31 { .name = "stat", .errmsg = true, .alias = "newstat", },
26}; 32};
27 33
@@ -43,6 +49,57 @@ struct syscall {
43 struct syscall_fmt *fmt; 49 struct syscall_fmt *fmt;
44}; 50};
45 51
52static size_t fprintf_duration(unsigned long t, FILE *fp)
53{
54 double duration = (double)t / NSEC_PER_MSEC;
55 size_t printed = fprintf(fp, "(");
56
57 if (duration >= 1.0)
58 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
59 else if (duration >= 0.01)
60 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
61 else
62 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
63 return printed + fprintf(stdout, "): ");
64}
65
66struct thread_trace {
67 u64 entry_time;
68 u64 exit_time;
69 bool entry_pending;
70 unsigned long nr_events;
71 char *entry_str;
72 double runtime_ms;
73};
74
75static struct thread_trace *thread_trace__new(void)
76{
77 return zalloc(sizeof(struct thread_trace));
78}
79
80static struct thread_trace *thread__trace(struct thread *thread)
81{
82 struct thread_trace *ttrace;
83
84 if (thread == NULL)
85 goto fail;
86
87 if (thread->priv == NULL)
88 thread->priv = thread_trace__new();
89
90 if (thread->priv == NULL)
91 goto fail;
92
93 ttrace = thread->priv;
94 ++ttrace->nr_events;
95
96 return ttrace;
97fail:
98 color_fprintf(stdout, PERF_COLOR_RED,
99 "WARNING: not enough memory, dropping samples!\n");
100 return NULL;
101}
102
46struct trace { 103struct trace {
47 int audit_machine; 104 int audit_machine;
48 struct { 105 struct {
@@ -50,8 +107,96 @@ struct trace {
50 struct syscall *table; 107 struct syscall *table;
51 } syscalls; 108 } syscalls;
52 struct perf_record_opts opts; 109 struct perf_record_opts opts;
110 struct machine host;
111 u64 base_time;
112 unsigned long nr_events;
113 bool sched;
114 bool multiple_threads;
115 double duration_filter;
116 double runtime_ms;
53}; 117};
54 118
119static bool trace__filter_duration(struct trace *trace, double t)
120{
121 return t < (trace->duration_filter * NSEC_PER_MSEC);
122}
123
124static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
125{
126 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
127
128 return fprintf(fp, "%10.3f ", ts);
129}
130
131static bool done = false;
132
133static void sig_handler(int sig __maybe_unused)
134{
135 done = true;
136}
137
138static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
139 u64 duration, u64 tstamp, FILE *fp)
140{
141 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
142 printed += fprintf_duration(duration, fp);
143
144 if (trace->multiple_threads)
145 printed += fprintf(fp, "%d ", thread->pid);
146
147 return printed;
148}
149
150static int trace__process_event(struct machine *machine, union perf_event *event)
151{
152 int ret = 0;
153
154 switch (event->header.type) {
155 case PERF_RECORD_LOST:
156 color_fprintf(stdout, PERF_COLOR_RED,
157 "LOST %" PRIu64 " events!\n", event->lost.lost);
158 ret = machine__process_lost_event(machine, event);
159 default:
160 ret = machine__process_event(machine, event);
161 break;
162 }
163
164 return ret;
165}
166
167static int trace__tool_process(struct perf_tool *tool __maybe_unused,
168 union perf_event *event,
169 struct perf_sample *sample __maybe_unused,
170 struct machine *machine)
171{
172 return trace__process_event(machine, event);
173}
174
175static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
176{
177 int err = symbol__init();
178
179 if (err)
180 return err;
181
182 machine__init(&trace->host, "", HOST_KERNEL_ID);
183 machine__create_kernel_maps(&trace->host);
184
185 if (perf_target__has_task(&trace->opts.target)) {
186 err = perf_event__synthesize_thread_map(NULL, evlist->threads,
187 trace__tool_process,
188 &trace->host);
189 } else {
190 err = perf_event__synthesize_threads(NULL, trace__tool_process,
191 &trace->host);
192 }
193
194 if (err)
195 symbol__exit();
196
197 return err;
198}
199
55static int trace__read_syscall_info(struct trace *trace, int id) 200static int trace__read_syscall_info(struct trace *trace, int id)
56{ 201{
57 char tp_name[128]; 202 char tp_name[128];
@@ -93,7 +238,8 @@ static int trace__read_syscall_info(struct trace *trace, int id)
93 return sc->tp_format != NULL ? 0 : -1; 238 return sc->tp_format != NULL ? 0 : -1;
94} 239}
95 240
96static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FILE *fp) 241static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
242 unsigned long *args)
97{ 243{
98 int i = 0; 244 int i = 0;
99 size_t printed = 0; 245 size_t printed = 0;
@@ -102,12 +248,15 @@ static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FIL
102 struct format_field *field; 248 struct format_field *field;
103 249
104 for (field = sc->tp_format->format.fields->next; field; field = field->next) { 250 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
105 printed += fprintf(fp, "%s%s: %ld", printed ? ", " : "", 251 printed += scnprintf(bf + printed, size - printed,
106 field->name, args[i++]); 252 "%s%s: %ld", printed ? ", " : "",
253 field->name, args[i++]);
107 } 254 }
108 } else { 255 } else {
109 while (i < 6) { 256 while (i < 6) {
110 printed += fprintf(fp, "%sarg%d: %ld", printed ? ", " : "", i, args[i]); 257 printed += scnprintf(bf + printed, size - printed,
258 "%sarg%d: %ld",
259 printed ? ", " : "", i, args[i]);
111 ++i; 260 ++i;
112 } 261 }
113 } 262 }
@@ -139,17 +288,24 @@ static struct syscall *trace__syscall_info(struct trace *trace,
139 return &trace->syscalls.table[id]; 288 return &trace->syscalls.table[id];
140 289
141out_cant_read: 290out_cant_read:
142 printf("Problems reading syscall %d information\n", id); 291 printf("Problems reading syscall %d", id);
292 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
293 printf("(%s)", trace->syscalls.table[id].name);
294 puts(" information");
143 return NULL; 295 return NULL;
144} 296}
145 297
146static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, 298static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
147 struct perf_sample *sample) 299 struct perf_sample *sample)
148{ 300{
301 char *msg;
149 void *args; 302 void *args;
303 size_t printed = 0;
304 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
150 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 305 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
306 struct thread_trace *ttrace = thread__trace(thread);
151 307
152 if (sc == NULL) 308 if (ttrace == NULL || sc == NULL)
153 return -1; 309 return -1;
154 310
155 args = perf_evsel__rawptr(evsel, sample, "args"); 311 args = perf_evsel__rawptr(evsel, sample, "args");
@@ -158,8 +314,27 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
158 return -1; 314 return -1;
159 } 315 }
160 316
161 printf("%s(", sc->name); 317 ttrace = thread->priv;
162 syscall__fprintf_args(sc, args, stdout); 318
319 if (ttrace->entry_str == NULL) {
320 ttrace->entry_str = malloc(1024);
321 if (!ttrace->entry_str)
322 return -1;
323 }
324
325 ttrace->entry_time = sample->time;
326 msg = ttrace->entry_str;
327 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
328
329 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
330
331 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
332 if (!trace->duration_filter) {
333 trace__fprintf_entry_head(trace, thread, 1, sample->time, stdout);
334 printf("%-70s\n", ttrace->entry_str);
335 }
336 } else
337 ttrace->entry_pending = true;
163 338
164 return 0; 339 return 0;
165} 340}
@@ -168,13 +343,37 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
168 struct perf_sample *sample) 343 struct perf_sample *sample)
169{ 344{
170 int ret; 345 int ret;
346 u64 duration = 0;
347 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
348 struct thread_trace *ttrace = thread__trace(thread);
171 struct syscall *sc = trace__syscall_info(trace, evsel, sample); 349 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
172 350
173 if (sc == NULL) 351 if (ttrace == NULL || sc == NULL)
174 return -1; 352 return -1;
175 353
176 ret = perf_evsel__intval(evsel, sample, "ret"); 354 ret = perf_evsel__intval(evsel, sample, "ret");
177 355
356 ttrace = thread->priv;
357
358 ttrace->exit_time = sample->time;
359
360 if (ttrace->entry_time) {
361 duration = sample->time - ttrace->entry_time;
362 if (trace__filter_duration(trace, duration))
363 goto out;
364 } else if (trace->duration_filter)
365 goto out;
366
367 trace__fprintf_entry_head(trace, thread, duration, sample->time, stdout);
368
369 if (ttrace->entry_pending) {
370 printf("%-70s", ttrace->entry_str);
371 } else {
372 printf(" ... [");
373 color_fprintf(stdout, PERF_COLOR_YELLOW, "continued");
374 printf("]: %s()", sc->name);
375 }
376
178 if (ret < 0 && sc->fmt && sc->fmt->errmsg) { 377 if (ret < 0 && sc->fmt && sc->fmt->errmsg) {
179 char bf[256]; 378 char bf[256];
180 const char *emsg = strerror_r(-ret, bf, sizeof(bf)), 379 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
@@ -187,14 +386,44 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
187 printf(") = %d", ret); 386 printf(") = %d", ret);
188 387
189 putchar('\n'); 388 putchar('\n');
389out:
390 ttrace->entry_pending = false;
391
392 return 0;
393}
394
395static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
396 struct perf_sample *sample)
397{
398 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
399 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
400 struct thread *thread = machine__findnew_thread(&trace->host, sample->tid);
401 struct thread_trace *ttrace = thread__trace(thread);
402
403 if (ttrace == NULL)
404 goto out_dump;
405
406 ttrace->runtime_ms += runtime_ms;
407 trace->runtime_ms += runtime_ms;
408 return 0;
409
410out_dump:
411 printf("%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
412 evsel->name,
413 perf_evsel__strval(evsel, sample, "comm"),
414 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
415 runtime,
416 perf_evsel__intval(evsel, sample, "vruntime"));
190 return 0; 417 return 0;
191} 418}
192 419
193static int trace__run(struct trace *trace) 420static int trace__run(struct trace *trace, int argc, const char **argv)
194{ 421{
195 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 422 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
196 struct perf_evsel *evsel; 423 struct perf_evsel *evsel;
197 int err = -1, i, nr_events = 0, before; 424 int err = -1, i;
425 unsigned long before;
426 const bool forks = argc > 0;
198 427
199 if (evlist == NULL) { 428 if (evlist == NULL) {
200 printf("Not enough memory to run!\n"); 429 printf("Not enough memory to run!\n");
@@ -207,13 +436,37 @@ static int trace__run(struct trace *trace)
207 goto out_delete_evlist; 436 goto out_delete_evlist;
208 } 437 }
209 438
439 if (trace->sched &&
440 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
441 trace__sched_stat_runtime)) {
442 printf("Couldn't read the sched_stat_runtime tracepoint information!\n");
443 goto out_delete_evlist;
444 }
445
210 err = perf_evlist__create_maps(evlist, &trace->opts.target); 446 err = perf_evlist__create_maps(evlist, &trace->opts.target);
211 if (err < 0) { 447 if (err < 0) {
212 printf("Problems parsing the target to trace, check your options!\n"); 448 printf("Problems parsing the target to trace, check your options!\n");
213 goto out_delete_evlist; 449 goto out_delete_evlist;
214 } 450 }
215 451
216 perf_evlist__config_attrs(evlist, &trace->opts); 452 err = trace__symbols_init(trace, evlist);
453 if (err < 0) {
454 printf("Problems initializing symbol libraries!\n");
455 goto out_delete_evlist;
456 }
457
458 perf_evlist__config(evlist, &trace->opts);
459
460 signal(SIGCHLD, sig_handler);
461 signal(SIGINT, sig_handler);
462
463 if (forks) {
464 err = perf_evlist__prepare_workload(evlist, &trace->opts, argv);
465 if (err < 0) {
466 printf("Couldn't run the workload!\n");
467 goto out_delete_evlist;
468 }
469 }
217 470
218 err = perf_evlist__open(evlist); 471 err = perf_evlist__open(evlist);
219 if (err < 0) { 472 if (err < 0) {
@@ -228,8 +481,13 @@ static int trace__run(struct trace *trace)
228 } 481 }
229 482
230 perf_evlist__enable(evlist); 483 perf_evlist__enable(evlist);
484
485 if (forks)
486 perf_evlist__start_workload(evlist);
487
488 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
231again: 489again:
232 before = nr_events; 490 before = trace->nr_events;
233 491
234 for (i = 0; i < evlist->nr_mmaps; i++) { 492 for (i = 0; i < evlist->nr_mmaps; i++) {
235 union perf_event *event; 493 union perf_event *event;
@@ -239,19 +497,7 @@ again:
239 tracepoint_handler handler; 497 tracepoint_handler handler;
240 struct perf_sample sample; 498 struct perf_sample sample;
241 499
242 ++nr_events; 500 ++trace->nr_events;
243
244 switch (type) {
245 case PERF_RECORD_SAMPLE:
246 break;
247 case PERF_RECORD_LOST:
248 printf("LOST %" PRIu64 " events!\n", event->lost.lost);
249 continue;
250 default:
251 printf("Unexpected %s event, skipping...\n",
252 perf_event__name(type));
253 continue;
254 }
255 501
256 err = perf_evlist__parse_sample(evlist, event, &sample); 502 err = perf_evlist__parse_sample(evlist, event, &sample);
257 if (err) { 503 if (err) {
@@ -259,14 +505,26 @@ again:
259 continue; 505 continue;
260 } 506 }
261 507
508 if (trace->base_time == 0)
509 trace->base_time = sample.time;
510
511 if (type != PERF_RECORD_SAMPLE) {
512 trace__process_event(&trace->host, event);
513 continue;
514 }
515
262 evsel = perf_evlist__id2evsel(evlist, sample.id); 516 evsel = perf_evlist__id2evsel(evlist, sample.id);
263 if (evsel == NULL) { 517 if (evsel == NULL) {
264 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); 518 printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
265 continue; 519 continue;
266 } 520 }
267 521
268 if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) 522 if (sample.raw_data == NULL) {
269 printf("%d ", sample.tid); 523 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
524 perf_evsel__name(evsel), sample.tid,
525 sample.cpu, sample.raw_size);
526 continue;
527 }
270 528
271 if (sample.raw_data == NULL) { 529 if (sample.raw_data == NULL) {
272 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", 530 printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
@@ -280,8 +538,15 @@ again:
280 } 538 }
281 } 539 }
282 540
283 if (nr_events == before) 541 if (trace->nr_events == before) {
542 if (done)
543 goto out_delete_evlist;
544
284 poll(evlist->pollfd, evlist->nr_fds, -1); 545 poll(evlist->pollfd, evlist->nr_fds, -1);
546 }
547
548 if (done)
549 perf_evlist__disable(evlist);
285 550
286 goto again; 551 goto again;
287 552
@@ -291,10 +556,65 @@ out:
291 return err; 556 return err;
292} 557}
293 558
559static size_t trace__fprintf_threads_header(FILE *fp)
560{
561 size_t printed;
562
563 printed = fprintf(fp, "\n _____________________________________________________________________\n");
564 printed += fprintf(fp," __) Summary of events (__\n\n");
565 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
566 printed += fprintf(fp," _____________________________________________________________________\n\n");
567
568 return printed;
569}
570
571static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
572{
573 size_t printed = trace__fprintf_threads_header(fp);
574 struct rb_node *nd;
575
576 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
577 struct thread *thread = rb_entry(nd, struct thread, rb_node);
578 struct thread_trace *ttrace = thread->priv;
579 const char *color;
580 double ratio;
581
582 if (ttrace == NULL)
583 continue;
584
585 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
586
587 color = PERF_COLOR_NORMAL;
588 if (ratio > 50.0)
589 color = PERF_COLOR_RED;
590 else if (ratio > 25.0)
591 color = PERF_COLOR_GREEN;
592 else if (ratio > 5.0)
593 color = PERF_COLOR_YELLOW;
594
595 printed += color_fprintf(fp, color, "%20s", thread->comm);
596 printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events);
597 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
598 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
599 }
600
601 return printed;
602}
603
604static int trace__set_duration(const struct option *opt, const char *str,
605 int unset __maybe_unused)
606{
607 struct trace *trace = opt->value;
608
609 trace->duration_filter = atof(str);
610 return 0;
611}
612
294int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) 613int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
295{ 614{
296 const char * const trace_usage[] = { 615 const char * const trace_usage[] = {
297 "perf trace [<options>]", 616 "perf trace [<options>] [<command>]",
617 "perf trace [<options>] -- <command> [<options>]",
298 NULL 618 NULL
299 }; 619 };
300 struct trace trace = { 620 struct trace trace = {
@@ -328,21 +648,38 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
328 "number of mmap data pages"), 648 "number of mmap data pages"),
329 OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user", 649 OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user",
330 "user to profile"), 650 "user to profile"),
651 OPT_CALLBACK(0, "duration", &trace, "float",
652 "show only events with duration > N.M ms",
653 trace__set_duration),
654 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
331 OPT_END() 655 OPT_END()
332 }; 656 };
333 int err; 657 int err;
658 char bf[BUFSIZ];
334 659
335 argc = parse_options(argc, argv, trace_options, trace_usage, 0); 660 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
336 if (argc) 661
337 usage_with_options(trace_usage, trace_options); 662 err = perf_target__validate(&trace.opts.target);
663 if (err) {
664 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
665 printf("%s", bf);
666 return err;
667 }
338 668
339 err = perf_target__parse_uid(&trace.opts.target); 669 err = perf_target__parse_uid(&trace.opts.target);
340 if (err) { 670 if (err) {
341 char bf[BUFSIZ];
342 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); 671 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
343 printf("%s", bf); 672 printf("%s", bf);
344 return err; 673 return err;
345 } 674 }
346 675
347 return trace__run(&trace); 676 if (!argc && perf_target__none(&trace.opts.target))
677 trace.opts.target.system_wide = true;
678
679 err = trace__run(&trace, argc, argv);
680
681 if (trace.sched && !err)
682 trace__fprintf_thread_summary(&trace, stdout);
683
684 return err;
348} 685}
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index 4add41bb0c7e..b4eabb44e381 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -43,6 +43,15 @@ int main(void)
43} 43}
44endef 44endef
45 45
46define SOURCE_BIONIC
47#include <android/api-level.h>
48
49int main(void)
50{
51 return __ANDROID_API__;
52}
53endef
54
46define SOURCE_ELF_MMAP 55define SOURCE_ELF_MMAP
47#include <libelf.h> 56#include <libelf.h>
48int main(void) 57int main(void)
@@ -112,7 +121,10 @@ define SOURCE_PYTHON_VERSION
112#if PY_VERSION_HEX >= 0x03000000 121#if PY_VERSION_HEX >= 0x03000000
113 #error 122 #error
114#endif 123#endif
115int main(void){} 124int main(void)
125{
126 return 0;
127}
116endef 128endef
117define SOURCE_PYTHON_EMBED 129define SOURCE_PYTHON_EMBED
118#include <Python.h> 130#include <Python.h>
@@ -203,4 +215,24 @@ int main(void)
203 return audit_open(); 215 return audit_open();
204} 216}
205endef 217endef
206endif \ No newline at end of file 218endif
219
220define SOURCE_ON_EXIT
221#include <stdio.h>
222
223int main(void)
224{
225 return on_exit(NULL, NULL);
226}
227endef
228
229define SOURCE_LIBNUMA
230#include <numa.h>
231#include <numaif.h>
232
233int main(void)
234{
235 numa_available();
236 return 0;
237}
238endef \ No newline at end of file
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index 8046182a19eb..8ef3bd30a549 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -13,7 +13,7 @@ newline := $(newline)
13# what should replace a newline when escaping 13# what should replace a newline when escaping
14# newlines; the default is a bizarre string. 14# newlines; the default is a bizarre string.
15# 15#
16nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n) 16nl-escape = $(if $(1),$(1),m822df3020w6a44id34bt574ctac44eb9f4n)
17 17
18# escape-nl 18# escape-nl
19# 19#
@@ -173,16 +173,22 @@ _ge-abspath = $(if $(is-executable),$(1))
173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default) 173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
174# 174#
175define get-executable-or-default 175define get-executable-or-default
176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2))) 176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2),$(1)))
177endef 177endef
178_ge_attempt = $(or $(get-executable),$(_gea_warn),$(call _gea_err,$(2))) 178_ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2)))
179_gea_warn = $(warning The path '$(1)' is not executable.) 179_gea_warn = $(warning The path '$(1)' is not executable.)
180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) 180_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
181 181
182# try-cc 182# try-cc
183# Usage: option = $(call try-cc, source-to-build, cc-options) 183# Usage: option = $(call try-cc, source-to-build, cc-options, msg)
184ifndef V
185TRY_CC_OUTPUT= > /dev/null 2>&1
186endif
187TRY_CC_MSG=echo " CHK $(3)" 1>&2;
188
184try-cc = $(shell sh -c \ 189try-cc = $(shell sh -c \
185 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \ 190 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
191 $(TRY_CC_MSG) \
186 echo "$(1)" | \ 192 echo "$(1)" | \
187 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \ 193 $(CC) -x c - $(2) -o "$$TMP" $(TRY_CC_OUTPUT) && echo y; \
188 rm -f "$$TMP"') 194 rm -f "$$TMP"')
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 6d50eb0b4251..095b88207cd3 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -24,6 +24,7 @@ const char perf_more_info_string[] =
24 24
25int use_browser = -1; 25int use_browser = -1;
26static int use_pager = -1; 26static int use_pager = -1;
27const char *input_name;
27 28
28struct cmd_struct { 29struct cmd_struct {
29 const char *cmd; 30 const char *cmd;
@@ -84,21 +85,26 @@ int check_pager_config(const char *cmd)
84 return c.val; 85 return c.val;
85} 86}
86 87
87static int tui_command_config(const char *var, const char *value, void *data) 88static int browser_command_config(const char *var, const char *value, void *data)
88{ 89{
89 struct pager_config *c = data; 90 struct pager_config *c = data;
90 if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd)) 91 if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd))
91 c->val = perf_config_bool(var, value); 92 c->val = perf_config_bool(var, value);
93 if (!prefixcmp(var, "gtk.") && !strcmp(var + 4, c->cmd))
94 c->val = perf_config_bool(var, value) ? 2 : 0;
92 return 0; 95 return 0;
93} 96}
94 97
95/* returns 0 for "no tui", 1 for "use tui", and -1 for "not specified" */ 98/*
96static int check_tui_config(const char *cmd) 99 * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk",
100 * and -1 for "not specified"
101 */
102static int check_browser_config(const char *cmd)
97{ 103{
98 struct pager_config c; 104 struct pager_config c;
99 c.cmd = cmd; 105 c.cmd = cmd;
100 c.val = -1; 106 c.val = -1;
101 perf_config(tui_command_config, &c); 107 perf_config(browser_command_config, &c);
102 return c.val; 108 return c.val;
103} 109}
104 110
@@ -301,7 +307,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
301 prefix = NULL; /* setup_perf_directory(); */ 307 prefix = NULL; /* setup_perf_directory(); */
302 308
303 if (use_browser == -1) 309 if (use_browser == -1)
304 use_browser = check_tui_config(p->cmd); 310 use_browser = check_browser_config(p->cmd);
305 311
306 if (use_pager == -1 && p->option & RUN_SETUP) 312 if (use_pager == -1 && p->option & RUN_SETUP)
307 use_pager = check_pager_config(p->cmd); 313 use_pager = check_pager_config(p->cmd);
@@ -322,14 +328,23 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
322 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) 328 if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
323 return 0; 329 return 0;
324 330
331 status = 1;
325 /* Check for ENOSPC and EIO errors.. */ 332 /* Check for ENOSPC and EIO errors.. */
326 if (fflush(stdout)) 333 if (fflush(stdout)) {
327 die("write failure on standard output: %s", strerror(errno)); 334 fprintf(stderr, "write failure on standard output: %s", strerror(errno));
328 if (ferror(stdout)) 335 goto out;
329 die("unknown write failure on standard output"); 336 }
330 if (fclose(stdout)) 337 if (ferror(stdout)) {
331 die("close failed on standard output: %s", strerror(errno)); 338 fprintf(stderr, "unknown write failure on standard output");
332 return 0; 339 goto out;
340 }
341 if (fclose(stdout)) {
342 fprintf(stderr, "close failed on standard output: %s", strerror(errno));
343 goto out;
344 }
345 status = 0;
346out:
347 return status;
333} 348}
334 349
335static void handle_internal_command(int argc, const char **argv) 350static void handle_internal_command(int argc, const char **argv)
@@ -440,6 +455,8 @@ int main(int argc, const char **argv)
440{ 455{
441 const char *cmd; 456 const char *cmd;
442 457
458 page_size = sysconf(_SC_PAGE_SIZE);
459
443 cmd = perf_extract_argv0_path(argv[0]); 460 cmd = perf_extract_argv0_path(argv[0]);
444 if (!cmd) 461 if (!cmd)
445 cmd = "perf-help"; 462 cmd = "perf-help";
@@ -459,7 +476,8 @@ int main(int argc, const char **argv)
459 cmd += 5; 476 cmd += 5;
460 argv[0] = cmd; 477 argv[0] = cmd;
461 handle_internal_command(argc, argv); 478 handle_internal_command(argc, argv);
462 die("cannot handle %s internally", cmd); 479 fprintf(stderr, "cannot handle %s internally", cmd);
480 goto out;
463 } 481 }
464 482
465 /* Look for flags.. */ 483 /* Look for flags.. */
@@ -477,10 +495,12 @@ int main(int argc, const char **argv)
477 printf("\n usage: %s\n\n", perf_usage_string); 495 printf("\n usage: %s\n\n", perf_usage_string);
478 list_common_cmds_help(); 496 list_common_cmds_help();
479 printf("\n %s\n\n", perf_more_info_string); 497 printf("\n %s\n\n", perf_more_info_string);
480 exit(1); 498 goto out;
481 } 499 }
482 cmd = argv[0]; 500 cmd = argv[0];
483 501
502 test_attr__init();
503
484 /* 504 /*
485 * We use PATH to find perf commands, but we prepend some higher 505 * We use PATH to find perf commands, but we prepend some higher
486 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH 506 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
@@ -507,7 +527,7 @@ int main(int argc, const char **argv)
507 fprintf(stderr, "Expansion of alias '%s' failed; " 527 fprintf(stderr, "Expansion of alias '%s' failed; "
508 "'%s' is not a perf-command\n", 528 "'%s' is not a perf-command\n",
509 cmd, argv[0]); 529 cmd, argv[0]);
510 exit(1); 530 goto out;
511 } 531 }
512 if (!done_help) { 532 if (!done_help) {
513 cmd = argv[0] = help_unknown_cmd(cmd); 533 cmd = argv[0] = help_unknown_cmd(cmd);
@@ -518,6 +538,6 @@ int main(int argc, const char **argv)
518 538
519 fprintf(stderr, "Failed to run command '%s': %s\n", 539 fprintf(stderr, "Failed to run command '%s': %s\n",
520 cmd, strerror(errno)); 540 cmd, strerror(errno));
521 541out:
522 return 1; 542 return 1;
523} 543}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index c50985eaec41..74659ecf93e0 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -1,12 +1,9 @@
1#ifndef _PERF_PERF_H 1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H 2#define _PERF_PERF_H
3 3
4struct winsize; 4#include <asm/unistd.h>
5
6void get_term_dimensions(struct winsize *ws);
7 5
8#if defined(__i386__) 6#if defined(__i386__)
9#include "../../arch/x86/include/asm/unistd.h"
10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 7#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
11#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 8#define cpu_relax() asm volatile("rep; nop" ::: "memory");
12#define CPUINFO_PROC "model name" 9#define CPUINFO_PROC "model name"
@@ -16,7 +13,6 @@ void get_term_dimensions(struct winsize *ws);
16#endif 13#endif
17 14
18#if defined(__x86_64__) 15#if defined(__x86_64__)
19#include "../../arch/x86/include/asm/unistd.h"
20#define rmb() asm volatile("lfence" ::: "memory") 16#define rmb() asm volatile("lfence" ::: "memory")
21#define cpu_relax() asm volatile("rep; nop" ::: "memory"); 17#define cpu_relax() asm volatile("rep; nop" ::: "memory");
22#define CPUINFO_PROC "model name" 18#define CPUINFO_PROC "model name"
@@ -26,20 +22,18 @@ void get_term_dimensions(struct winsize *ws);
26#endif 22#endif
27 23
28#ifdef __powerpc__ 24#ifdef __powerpc__
29#include "../../arch/powerpc/include/asm/unistd.h" 25#include "../../arch/powerpc/include/uapi/asm/unistd.h"
30#define rmb() asm volatile ("sync" ::: "memory") 26#define rmb() asm volatile ("sync" ::: "memory")
31#define cpu_relax() asm volatile ("" ::: "memory"); 27#define cpu_relax() asm volatile ("" ::: "memory");
32#define CPUINFO_PROC "cpu" 28#define CPUINFO_PROC "cpu"
33#endif 29#endif
34 30
35#ifdef __s390__ 31#ifdef __s390__
36#include "../../arch/s390/include/asm/unistd.h"
37#define rmb() asm volatile("bcr 15,0" ::: "memory") 32#define rmb() asm volatile("bcr 15,0" ::: "memory")
38#define cpu_relax() asm volatile("" ::: "memory"); 33#define cpu_relax() asm volatile("" ::: "memory");
39#endif 34#endif
40 35
41#ifdef __sh__ 36#ifdef __sh__
42#include "../../arch/sh/include/asm/unistd.h"
43#if defined(__SH4A__) || defined(__SH5__) 37#if defined(__SH4A__) || defined(__SH5__)
44# define rmb() asm volatile("synco" ::: "memory") 38# define rmb() asm volatile("synco" ::: "memory")
45#else 39#else
@@ -50,35 +44,30 @@ void get_term_dimensions(struct winsize *ws);
50#endif 44#endif
51 45
52#ifdef __hppa__ 46#ifdef __hppa__
53#include "../../arch/parisc/include/asm/unistd.h"
54#define rmb() asm volatile("" ::: "memory") 47#define rmb() asm volatile("" ::: "memory")
55#define cpu_relax() asm volatile("" ::: "memory"); 48#define cpu_relax() asm volatile("" ::: "memory");
56#define CPUINFO_PROC "cpu" 49#define CPUINFO_PROC "cpu"
57#endif 50#endif
58 51
59#ifdef __sparc__ 52#ifdef __sparc__
60#include "../../arch/sparc/include/uapi/asm/unistd.h"
61#define rmb() asm volatile("":::"memory") 53#define rmb() asm volatile("":::"memory")
62#define cpu_relax() asm volatile("":::"memory") 54#define cpu_relax() asm volatile("":::"memory")
63#define CPUINFO_PROC "cpu" 55#define CPUINFO_PROC "cpu"
64#endif 56#endif
65 57
66#ifdef __alpha__ 58#ifdef __alpha__
67#include "../../arch/alpha/include/asm/unistd.h"
68#define rmb() asm volatile("mb" ::: "memory") 59#define rmb() asm volatile("mb" ::: "memory")
69#define cpu_relax() asm volatile("" ::: "memory") 60#define cpu_relax() asm volatile("" ::: "memory")
70#define CPUINFO_PROC "cpu model" 61#define CPUINFO_PROC "cpu model"
71#endif 62#endif
72 63
73#ifdef __ia64__ 64#ifdef __ia64__
74#include "../../arch/ia64/include/asm/unistd.h"
75#define rmb() asm volatile ("mf" ::: "memory") 65#define rmb() asm volatile ("mf" ::: "memory")
76#define cpu_relax() asm volatile ("hint @pause" ::: "memory") 66#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
77#define CPUINFO_PROC "model name" 67#define CPUINFO_PROC "model name"
78#endif 68#endif
79 69
80#ifdef __arm__ 70#ifdef __arm__
81#include "../../arch/arm/include/asm/unistd.h"
82/* 71/*
83 * Use the __kuser_memory_barrier helper in the CPU helper page. See 72 * Use the __kuser_memory_barrier helper in the CPU helper page. See
84 * arch/arm/kernel/entry-armv.S in the kernel source for details. 73 * arch/arm/kernel/entry-armv.S in the kernel source for details.
@@ -89,13 +78,11 @@ void get_term_dimensions(struct winsize *ws);
89#endif 78#endif
90 79
91#ifdef __aarch64__ 80#ifdef __aarch64__
92#include "../../arch/arm64/include/asm/unistd.h"
93#define rmb() asm volatile("dmb ld" ::: "memory") 81#define rmb() asm volatile("dmb ld" ::: "memory")
94#define cpu_relax() asm volatile("yield" ::: "memory") 82#define cpu_relax() asm volatile("yield" ::: "memory")
95#endif 83#endif
96 84
97#ifdef __mips__ 85#ifdef __mips__
98#include "../../arch/mips/include/asm/unistd.h"
99#define rmb() asm volatile( \ 86#define rmb() asm volatile( \
100 ".set mips2\n\t" \ 87 ".set mips2\n\t" \
101 "sync\n\t" \ 88 "sync\n\t" \
@@ -107,41 +94,27 @@ void get_term_dimensions(struct winsize *ws);
107#define CPUINFO_PROC "cpu model" 94#define CPUINFO_PROC "cpu model"
108#endif 95#endif
109 96
97#ifdef __arc__
98#define rmb() asm volatile("" ::: "memory")
99#define cpu_relax() rmb()
100#define CPUINFO_PROC "Processor"
101#endif
102
103#ifdef __metag__
104#define rmb() asm volatile("" ::: "memory")
105#define cpu_relax() asm volatile("" ::: "memory")
106#define CPUINFO_PROC "CPU"
107#endif
108
110#include <time.h> 109#include <time.h>
111#include <unistd.h> 110#include <unistd.h>
112#include <sys/types.h> 111#include <sys/types.h>
113#include <sys/syscall.h> 112#include <sys/syscall.h>
114 113
115#include "../../include/uapi/linux/perf_event.h" 114#include <linux/perf_event.h>
116#include "util/types.h" 115#include "util/types.h"
117#include <stdbool.h> 116#include <stdbool.h>
118 117
119struct perf_mmap {
120 void *base;
121 int mask;
122 unsigned int prev;
123};
124
125static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
126{
127 struct perf_event_mmap_page *pc = mm->base;
128 int head = pc->data_head;
129 rmb();
130 return head;
131}
132
133static inline void perf_mmap__write_tail(struct perf_mmap *md,
134 unsigned long tail)
135{
136 struct perf_event_mmap_page *pc = md->base;
137
138 /*
139 * ensure all reads are done before we write the tail out.
140 */
141 /* mb(); */
142 pc->data_tail = tail;
143}
144
145/* 118/*
146 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all 119 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
147 * counters in the current task. 120 * counters in the current task.
@@ -174,13 +147,25 @@ static inline unsigned long long rdclock(void)
174 (void) (&_min1 == &_min2); \ 147 (void) (&_min1 == &_min2); \
175 _min1 < _min2 ? _min1 : _min2; }) 148 _min1 < _min2 ? _min1 : _min2; })
176 149
150extern bool test_attr__enabled;
151void test_attr__init(void);
152void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
153 int fd, int group_fd, unsigned long flags);
154
177static inline int 155static inline int
178sys_perf_event_open(struct perf_event_attr *attr, 156sys_perf_event_open(struct perf_event_attr *attr,
179 pid_t pid, int cpu, int group_fd, 157 pid_t pid, int cpu, int group_fd,
180 unsigned long flags) 158 unsigned long flags)
181{ 159{
182 return syscall(__NR_perf_event_open, attr, pid, cpu, 160 int fd;
183 group_fd, flags); 161
162 fd = syscall(__NR_perf_event_open, attr, pid, cpu,
163 group_fd, flags);
164
165 if (unlikely(test_attr__enabled))
166 test_attr__open(attr, pid, cpu, fd, group_fd, flags);
167
168 return fd;
184} 169}
185 170
186#define MAX_COUNTERS 256 171#define MAX_COUNTERS 256
@@ -208,6 +193,7 @@ struct branch_stack {
208 struct branch_entry entries[0]; 193 struct branch_entry entries[0];
209}; 194};
210 195
196extern const char *input_name;
211extern bool perf_host, perf_guest; 197extern bool perf_host, perf_guest;
212extern const char perf_version_string[]; 198extern const char perf_version_string[];
213 199
@@ -233,8 +219,6 @@ struct perf_record_opts {
233 bool raw_samples; 219 bool raw_samples;
234 bool sample_address; 220 bool sample_address;
235 bool sample_time; 221 bool sample_time;
236 bool sample_id_all_missing;
237 bool exclude_guest_missing;
238 bool period; 222 bool period;
239 unsigned int freq; 223 unsigned int freq;
240 unsigned int mmap_pages; 224 unsigned int mmap_pages;
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
deleted file mode 100644
index 8edda9078d5d..000000000000
--- a/tools/perf/scripts/perl/bin/workqueue-stats-record
+++ /dev/null
@@ -1,2 +0,0 @@
1#!/bin/bash
2perf record -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion $@
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-report b/tools/perf/scripts/perl/bin/workqueue-stats-report
deleted file mode 100644
index 6d91411d248c..000000000000
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ /dev/null
@@ -1,3 +0,0 @@
1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy)
3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
diff --git a/tools/perf/scripts/perl/rwtop.pl b/tools/perf/scripts/perl/rwtop.pl
index 4bb3ecd33472..8b20787021c1 100644
--- a/tools/perf/scripts/perl/rwtop.pl
+++ b/tools/perf/scripts/perl/rwtop.pl
@@ -17,6 +17,7 @@ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib"; 17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core; 18use Perf::Trace::Core;
19use Perf::Trace::Util; 19use Perf::Trace::Util;
20use POSIX qw/SIGALRM SA_RESTART/;
20 21
21my $default_interval = 3; 22my $default_interval = 3;
22my $nlines = 20; 23my $nlines = 20;
@@ -90,7 +91,10 @@ sub syscalls::sys_enter_write
90 91
91sub trace_begin 92sub trace_begin
92{ 93{
93 $SIG{ALRM} = \&set_print_pending; 94 my $sa = POSIX::SigAction->new(\&set_print_pending);
95 $sa->flags(SA_RESTART);
96 $sa->safe(1);
97 POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n";
94 alarm 1; 98 alarm 1;
95} 99}
96 100
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
deleted file mode 100644
index a8eaff5119e0..000000000000
--- a/tools/perf/scripts/perl/workqueue-stats.pl
+++ /dev/null
@@ -1,129 +0,0 @@
1#!/usr/bin/perl -w
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# Displays workqueue stats
6#
7# Usage:
8#
9# perf record -c 1 -f -a -R -e workqueue:workqueue_creation -e
10# workqueue:workqueue_destruction -e workqueue:workqueue_execution
11# -e workqueue:workqueue_insertion
12#
13# perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl
14
15use 5.010000;
16use strict;
17use warnings;
18
19use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
20use lib "./Perf-Trace-Util/lib";
21use Perf::Trace::Core;
22use Perf::Trace::Util;
23
24my @cpus;
25
26sub workqueue::workqueue_destruction
27{
28 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
29 $common_pid, $common_comm,
30 $thread_comm, $thread_pid) = @_;
31
32 $cpus[$common_cpu]{$thread_pid}{destroyed}++;
33 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
34}
35
36sub workqueue::workqueue_creation
37{
38 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
39 $common_pid, $common_comm,
40 $thread_comm, $thread_pid, $cpu) = @_;
41
42 $cpus[$common_cpu]{$thread_pid}{created}++;
43 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
44}
45
46sub workqueue::workqueue_execution
47{
48 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
49 $common_pid, $common_comm,
50 $thread_comm, $thread_pid, $func) = @_;
51
52 $cpus[$common_cpu]{$thread_pid}{executed}++;
53 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
54}
55
56sub workqueue::workqueue_insertion
57{
58 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
59 $common_pid, $common_comm,
60 $thread_comm, $thread_pid, $func) = @_;
61
62 $cpus[$common_cpu]{$thread_pid}{inserted}++;
63 $cpus[$common_cpu]{$thread_pid}{comm} = $thread_comm;
64}
65
66sub trace_end
67{
68 print "workqueue work stats:\n\n";
69 my $cpu = 0;
70 printf("%3s %6s %6s\t%-20s\n", "cpu", "ins", "exec", "name");
71 printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
72 foreach my $pidhash (@cpus) {
73 while ((my $pid, my $wqhash) = each %$pidhash) {
74 my $ins = $$wqhash{'inserted'} || 0;
75 my $exe = $$wqhash{'executed'} || 0;
76 my $comm = $$wqhash{'comm'} || "";
77 if ($ins || $exe) {
78 printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
79 }
80 }
81 $cpu++;
82 }
83
84 $cpu = 0;
85 print "\nworkqueue lifecycle stats:\n\n";
86 printf("%3s %6s %6s\t%-20s\n", "cpu", "created", "destroyed", "name");
87 printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
88 foreach my $pidhash (@cpus) {
89 while ((my $pid, my $wqhash) = each %$pidhash) {
90 my $created = $$wqhash{'created'} || 0;
91 my $destroyed = $$wqhash{'destroyed'} || 0;
92 my $comm = $$wqhash{'comm'} || "";
93 if ($created || $destroyed) {
94 printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
95 $comm);
96 }
97 }
98 $cpu++;
99 }
100
101 print_unhandled();
102}
103
104my %unhandled;
105
106sub print_unhandled
107{
108 if ((scalar keys %unhandled) == 0) {
109 return;
110 }
111
112 print "\nunhandled events:\n\n";
113
114 printf("%-40s %10s\n", "event", "count");
115 printf("%-40s %10s\n", "----------------------------------------",
116 "-----------");
117
118 foreach my $event_name (keys %unhandled) {
119 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
120 }
121}
122
123sub trace_unhandled
124{
125 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
126 $common_pid, $common_comm) = @_;
127
128 $unhandled{$event_name}++;
129}
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
new file mode 100644
index 000000000000..bdcceb886f77
--- /dev/null
+++ b/tools/perf/tests/attr.c
@@ -0,0 +1,178 @@
1
2/*
3 * The struct perf_event_attr test support.
4 *
5 * This test is embedded inside into perf directly and is governed
6 * by the PERF_TEST_ATTR environment variable and hook inside
7 * sys_perf_event_open function.
8 *
9 * The general idea is to store 'struct perf_event_attr' details for
10 * each event created within single perf command. Each event details
11 * are stored into separate text file. Once perf command is finished
12 * these files can be checked for values we expect for command.
13 *
14 * Besides 'struct perf_event_attr' values we also store 'fd' and
15 * 'group_fd' values to allow checking for groups created.
16 *
17 * This all is triggered by setting PERF_TEST_ATTR environment variable.
18 * It must contain name of existing directory with access and write
19 * permissions. All the event text files are stored there.
20 */
21
22/*
23 * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
24 * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
25 */
26#define __SANE_USERSPACE_TYPES__
27#include <stdlib.h>
28#include <stdio.h>
29#include <inttypes.h>
30#include <linux/types.h>
31#include <linux/kernel.h>
32#include "../perf.h"
33#include "util.h"
34#include "exec_cmd.h"
35#include "tests.h"
36
37#define ENV "PERF_TEST_ATTR"
38
39extern int verbose;
40
41static char *dir;
42
43void test_attr__init(void)
44{
45 dir = getenv(ENV);
46 test_attr__enabled = (dir != NULL);
47}
48
49#define BUFSIZE 1024
50
51#define __WRITE_ASS(str, fmt, data) \
52do { \
53 char buf[BUFSIZE]; \
54 size_t size; \
55 \
56 size = snprintf(buf, BUFSIZE, #str "=%"fmt "\n", data); \
57 if (1 != fwrite(buf, size, 1, file)) { \
58 perror("test attr - failed to write event file"); \
59 fclose(file); \
60 return -1; \
61 } \
62 \
63} while (0)
64
65#define WRITE_ASS(field, fmt) __WRITE_ASS(field, fmt, attr->field)
66
67static int store_event(struct perf_event_attr *attr, pid_t pid, int cpu,
68 int fd, int group_fd, unsigned long flags)
69{
70 FILE *file;
71 char path[PATH_MAX];
72
73 snprintf(path, PATH_MAX, "%s/event-%d-%llu-%d", dir,
74 attr->type, attr->config, fd);
75
76 file = fopen(path, "w+");
77 if (!file) {
78 perror("test attr - failed to open event file");
79 return -1;
80 }
81
82 if (fprintf(file, "[event-%d-%llu-%d]\n",
83 attr->type, attr->config, fd) < 0) {
84 perror("test attr - failed to write event file");
85 fclose(file);
86 return -1;
87 }
88
89 /* syscall arguments */
90 __WRITE_ASS(fd, "d", fd);
91 __WRITE_ASS(group_fd, "d", group_fd);
92 __WRITE_ASS(cpu, "d", cpu);
93 __WRITE_ASS(pid, "d", pid);
94 __WRITE_ASS(flags, "lu", flags);
95
96 /* struct perf_event_attr */
97 WRITE_ASS(type, PRIu32);
98 WRITE_ASS(size, PRIu32);
99 WRITE_ASS(config, "llu");
100 WRITE_ASS(sample_period, "llu");
101 WRITE_ASS(sample_type, "llu");
102 WRITE_ASS(read_format, "llu");
103 WRITE_ASS(disabled, "d");
104 WRITE_ASS(inherit, "d");
105 WRITE_ASS(pinned, "d");
106 WRITE_ASS(exclusive, "d");
107 WRITE_ASS(exclude_user, "d");
108 WRITE_ASS(exclude_kernel, "d");
109 WRITE_ASS(exclude_hv, "d");
110 WRITE_ASS(exclude_idle, "d");
111 WRITE_ASS(mmap, "d");
112 WRITE_ASS(comm, "d");
113 WRITE_ASS(freq, "d");
114 WRITE_ASS(inherit_stat, "d");
115 WRITE_ASS(enable_on_exec, "d");
116 WRITE_ASS(task, "d");
117 WRITE_ASS(watermark, "d");
118 WRITE_ASS(precise_ip, "d");
119 WRITE_ASS(mmap_data, "d");
120 WRITE_ASS(sample_id_all, "d");
121 WRITE_ASS(exclude_host, "d");
122 WRITE_ASS(exclude_guest, "d");
123 WRITE_ASS(exclude_callchain_kernel, "d");
124 WRITE_ASS(exclude_callchain_user, "d");
125 WRITE_ASS(wakeup_events, PRIu32);
126 WRITE_ASS(bp_type, PRIu32);
127 WRITE_ASS(config1, "llu");
128 WRITE_ASS(config2, "llu");
129 WRITE_ASS(branch_sample_type, "llu");
130 WRITE_ASS(sample_regs_user, "llu");
131 WRITE_ASS(sample_stack_user, PRIu32);
132
133 fclose(file);
134 return 0;
135}
136
137void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
138 int fd, int group_fd, unsigned long flags)
139{
140 int errno_saved = errno;
141
142 if (store_event(attr, pid, cpu, fd, group_fd, flags))
143 die("test attr FAILED");
144
145 errno = errno_saved;
146}
147
148static int run_dir(const char *d, const char *perf)
149{
150 char cmd[3*PATH_MAX];
151
152 snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s",
153 d, d, perf, verbose ? "-v" : "");
154
155 return system(cmd);
156}
157
158int test__attr(void)
159{
160 struct stat st;
161 char path_perf[PATH_MAX];
162 char path_dir[PATH_MAX];
163
164 /* First try developement tree tests. */
165 if (!lstat("./tests", &st))
166 return run_dir("./tests", "./perf");
167
168 /* Then installed path. */
169 snprintf(path_dir, PATH_MAX, "%s/tests", perf_exec_path());
170 snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
171
172 if (!lstat(path_dir, &st) &&
173 !lstat(path_perf, &st))
174 return run_dir(path_dir, path_perf);
175
176 fprintf(stderr, " (ommitted)");
177 return 0;
178}
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py
new file mode 100644
index 000000000000..2f629ca485bc
--- /dev/null
+++ b/tools/perf/tests/attr.py
@@ -0,0 +1,331 @@
1#! /usr/bin/python
2
3import os
4import sys
5import glob
6import optparse
7import tempfile
8import logging
9import shutil
10import ConfigParser
11
12class Fail(Exception):
13 def __init__(self, test, msg):
14 self.msg = msg
15 self.test = test
16 def getMsg(self):
17 return '\'%s\' - %s' % (self.test.path, self.msg)
18
19class Unsup(Exception):
20 def __init__(self, test):
21 self.test = test
22 def getMsg(self):
23 return '\'%s\'' % self.test.path
24
25class Event(dict):
26 terms = [
27 'flags',
28 'type',
29 'size',
30 'config',
31 'sample_period',
32 'sample_type',
33 'read_format',
34 'disabled',
35 'inherit',
36 'pinned',
37 'exclusive',
38 'exclude_user',
39 'exclude_kernel',
40 'exclude_hv',
41 'exclude_idle',
42 'mmap',
43 'comm',
44 'freq',
45 'inherit_stat',
46 'enable_on_exec',
47 'task',
48 'watermark',
49 'precise_ip',
50 'mmap_data',
51 'sample_id_all',
52 'exclude_host',
53 'exclude_guest',
54 'exclude_callchain_kernel',
55 'exclude_callchain_user',
56 'wakeup_events',
57 'bp_type',
58 'config1',
59 'config2',
60 'branch_sample_type',
61 'sample_regs_user',
62 'sample_stack_user',
63 ]
64
65 def add(self, data):
66 for key, val in data:
67 log.debug(" %s = %s" % (key, val))
68 self[key] = val
69
70 def __init__(self, name, data, base):
71 log.debug(" Event %s" % name);
72 self.name = name;
73 self.group = ''
74 self.add(base)
75 self.add(data)
76
77 def compare_data(self, a, b):
78 # Allow multiple values in assignment separated by '|'
79 a_list = a.split('|')
80 b_list = b.split('|')
81
82 for a_item in a_list:
83 for b_item in b_list:
84 if (a_item == b_item):
85 return True
86 elif (a_item == '*') or (b_item == '*'):
87 return True
88
89 return False
90
91 def equal(self, other):
92 for t in Event.terms:
93 log.debug(" [%s] %s %s" % (t, self[t], other[t]));
94 if not self.has_key(t) or not other.has_key(t):
95 return False
96 if not self.compare_data(self[t], other[t]):
97 return False
98 return True
99
100 def diff(self, other):
101 for t in Event.terms:
102 if not self.has_key(t) or not other.has_key(t):
103 continue
104 if not self.compare_data(self[t], other[t]):
105 log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
106
107
108# Test file description needs to have following sections:
109# [config]
110# - just single instance in file
111# - needs to specify:
112# 'command' - perf command name
113# 'args' - special command arguments
114# 'ret' - expected command return value (0 by default)
115#
116# [eventX:base]
117# - one or multiple instances in file
118# - expected values assignments
119class Test(object):
120 def __init__(self, path, options):
121 parser = ConfigParser.SafeConfigParser()
122 parser.read(path)
123
124 log.debug("running '%s'" % path)
125
126 self.path = path
127 self.test_dir = options.test_dir
128 self.perf = options.perf
129 self.command = parser.get('config', 'command')
130 self.args = parser.get('config', 'args')
131
132 try:
133 self.ret = parser.get('config', 'ret')
134 except:
135 self.ret = 0
136
137 self.expect = {}
138 self.result = {}
139 log.debug(" loading expected events");
140 self.load_events(path, self.expect)
141
142 def is_event(self, name):
143 if name.find("event") == -1:
144 return False
145 else:
146 return True
147
148 def load_events(self, path, events):
149 parser_event = ConfigParser.SafeConfigParser()
150 parser_event.read(path)
151
152 # The event record section header contains 'event' word,
153 # optionaly followed by ':' allowing to load 'parent
154 # event' first as a base
155 for section in filter(self.is_event, parser_event.sections()):
156
157 parser_items = parser_event.items(section);
158 base_items = {}
159
160 # Read parent event if there's any
161 if (':' in section):
162 base = section[section.index(':') + 1:]
163 parser_base = ConfigParser.SafeConfigParser()
164 parser_base.read(self.test_dir + '/' + base)
165 base_items = parser_base.items('event')
166
167 e = Event(section, parser_items, base_items)
168 events[section] = e
169
170 def run_cmd(self, tempdir):
171 cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir,
172 self.perf, self.command, tempdir, self.args)
173 ret = os.WEXITSTATUS(os.system(cmd))
174
175 log.warning(" running '%s' ret %d " % (cmd, ret))
176
177 if ret != int(self.ret):
178 raise Unsup(self)
179
180 def compare(self, expect, result):
181 match = {}
182
183 log.debug(" compare");
184
185 # For each expected event find all matching
186 # events in result. Fail if there's not any.
187 for exp_name, exp_event in expect.items():
188 exp_list = []
189 log.debug(" matching [%s]" % exp_name)
190 for res_name, res_event in result.items():
191 log.debug(" to [%s]" % res_name)
192 if (exp_event.equal(res_event)):
193 exp_list.append(res_name)
194 log.debug(" ->OK")
195 else:
196 log.debug(" ->FAIL");
197
198 log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list)))
199
200 # we did not any matching event - fail
201 if (not exp_list):
202 exp_event.diff(res_event)
203 raise Fail(self, 'match failure');
204
205 match[exp_name] = exp_list
206
207 # For each defined group in the expected events
208 # check we match the same group in the result.
209 for exp_name, exp_event in expect.items():
210 group = exp_event.group
211
212 if (group == ''):
213 continue
214
215 for res_name in match[exp_name]:
216 res_group = result[res_name].group
217 if res_group not in match[group]:
218 raise Fail(self, 'group failure')
219
220 log.debug(" group: [%s] matches group leader %s" %
221 (exp_name, str(match[group])))
222
223 log.debug(" matched")
224
225 def resolve_groups(self, events):
226 for name, event in events.items():
227 group_fd = event['group_fd'];
228 if group_fd == '-1':
229 continue;
230
231 for iname, ievent in events.items():
232 if (ievent['fd'] == group_fd):
233 event.group = iname
234 log.debug('[%s] has group leader [%s]' % (name, iname))
235 break;
236
237 def run(self):
238 tempdir = tempfile.mkdtemp();
239
240 try:
241 # run the test script
242 self.run_cmd(tempdir);
243
244 # load events expectation for the test
245 log.debug(" loading result events");
246 for f in glob.glob(tempdir + '/event*'):
247 self.load_events(f, self.result);
248
249 # resolve group_fd to event names
250 self.resolve_groups(self.expect);
251 self.resolve_groups(self.result);
252
253 # do the expectation - results matching - both ways
254 self.compare(self.expect, self.result)
255 self.compare(self.result, self.expect)
256
257 finally:
258 # cleanup
259 shutil.rmtree(tempdir)
260
261
262def run_tests(options):
263 for f in glob.glob(options.test_dir + '/' + options.test):
264 try:
265 Test(f, options).run()
266 except Unsup, obj:
267 log.warning("unsupp %s" % obj.getMsg())
268
269def setup_log(verbose):
270 global log
271 level = logging.CRITICAL
272
273 if verbose == 1:
274 level = logging.WARNING
275 if verbose == 2:
276 level = logging.INFO
277 if verbose >= 3:
278 level = logging.DEBUG
279
280 log = logging.getLogger('test')
281 log.setLevel(level)
282 ch = logging.StreamHandler()
283 ch.setLevel(level)
284 formatter = logging.Formatter('%(message)s')
285 ch.setFormatter(formatter)
286 log.addHandler(ch)
287
288USAGE = '''%s [OPTIONS]
289 -d dir # tests dir
290 -p path # perf binary
291 -t test # single test
292 -v # verbose level
293''' % sys.argv[0]
294
295def main():
296 parser = optparse.OptionParser(usage=USAGE)
297
298 parser.add_option("-t", "--test",
299 action="store", type="string", dest="test")
300 parser.add_option("-d", "--test-dir",
301 action="store", type="string", dest="test_dir")
302 parser.add_option("-p", "--perf",
303 action="store", type="string", dest="perf")
304 parser.add_option("-v", "--verbose",
305 action="count", dest="verbose")
306
307 options, args = parser.parse_args()
308 if args:
309 parser.error('FAILED wrong arguments %s' % ' '.join(args))
310 return -1
311
312 setup_log(options.verbose)
313
314 if not options.test_dir:
315 print 'FAILED no -d option specified'
316 sys.exit(-1)
317
318 if not options.test:
319 options.test = 'test*'
320
321 try:
322 run_tests(options)
323
324 except Fail, obj:
325 print "FAILED %s" % obj.getMsg();
326 sys.exit(-1)
327
328 sys.exit(0)
329
330if __name__ == '__main__':
331 main()
diff --git a/tools/perf/tests/attr/README b/tools/perf/tests/attr/README
new file mode 100644
index 000000000000..d102957cd59a
--- /dev/null
+++ b/tools/perf/tests/attr/README
@@ -0,0 +1,64 @@
1The struct perf_event_attr test (attr tests) support
2====================================================
3This testing support is embedded into perf directly and is governed
4by the PERF_TEST_ATTR environment variable and hook inside the
5sys_perf_event_open function.
6
7The general idea is to store 'struct perf_event_attr' details for
8each event created within single perf command. Each event details
9are stored into separate text file. Once perf command is finished
10these files are checked for values we expect for command.
11
12The attr tests consist of following parts:
13
14tests/attr.c
15------------
16This is the sys_perf_event_open hook implementation. The hook
17is triggered when the PERF_TEST_ATTR environment variable is
18defined. It must contain name of existing directory with access
19and write permissions.
20
21For each sys_perf_event_open call event details are stored in
22separate file. Besides 'struct perf_event_attr' values we also
23store 'fd' and 'group_fd' values to allow checking for groups.
24
25tests/attr.py
26-------------
27This is the python script that does all the hard work. It reads
28the test definition, executes it and checks results.
29
30tests/attr/
31-----------
32Directory containing all attr test definitions.
33Following tests are defined (with perf commands):
34
35 perf record kill (test-record-basic)
36 perf record -b kill (test-record-branch-any)
37 perf record -j any kill (test-record-branch-filter-any)
38 perf record -j any_call kill (test-record-branch-filter-any_call)
39 perf record -j any_ret kill (test-record-branch-filter-any_ret)
40 perf record -j hv kill (test-record-branch-filter-hv)
41 perf record -j ind_call kill (test-record-branch-filter-ind_call)
42 perf record -j k kill (test-record-branch-filter-k)
43 perf record -j u kill (test-record-branch-filter-u)
44 perf record -c 123 kill (test-record-count)
45 perf record -d kill (test-record-data)
46 perf record -F 100 kill (test-record-freq)
47 perf record -g -- kill (test-record-graph-default)
48 perf record -g dwarf -- kill (test-record-graph-dwarf)
49 perf record -g fp kill (test-record-graph-fp)
50 perf record --group -e cycles,instructions kill (test-record-group)
51 perf record -e '{cycles,instructions}' kill (test-record-group1)
52 perf record -D kill (test-record-no-delay)
53 perf record -i kill (test-record-no-inherit)
54 perf record -n kill (test-record-no-samples)
55 perf record -c 100 -P kill (test-record-period)
56 perf record -R kill (test-record-raw)
57 perf stat -e cycles kill (test-stat-basic)
58 perf stat kill (test-stat-default)
59 perf stat -d kill (test-stat-detailed-1)
60 perf stat -dd kill (test-stat-detailed-2)
61 perf stat -ddd kill (test-stat-detailed-3)
62 perf stat --group -e cycles,instructions kill (test-stat-group)
63 perf stat -e '{cycles,instructions}' kill (test-stat-group1)
64 perf stat -i -e cycles kill (test-stat-no-inherit)
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record
new file mode 100644
index 000000000000..5bc3880f7be5
--- /dev/null
+++ b/tools/perf/tests/attr/base-record
@@ -0,0 +1,39 @@
1[event]
2fd=1
3group_fd=-1
4flags=0
5type=0|1
6size=96
7config=0
8sample_period=4000
9sample_type=263
10read_format=0
11disabled=1
12inherit=1
13pinned=0
14exclusive=0
15exclude_user=0
16exclude_kernel=0
17exclude_hv=0
18exclude_idle=0
19mmap=1
20comm=1
21freq=1
22inherit_stat=0
23enable_on_exec=1
24task=0
25watermark=0
26precise_ip=0
27mmap_data=0
28sample_id_all=1
29exclude_host=0
30exclude_guest=1
31exclude_callchain_kernel=0
32exclude_callchain_user=0
33wakeup_events=0
34bp_type=0
35config1=0
36config2=0
37branch_sample_type=0
38sample_regs_user=0
39sample_stack_user=0
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat
new file mode 100644
index 000000000000..4bd79a82784f
--- /dev/null
+++ b/tools/perf/tests/attr/base-stat
@@ -0,0 +1,39 @@
1[event]
2fd=1
3group_fd=-1
4flags=0
5type=0
6size=96
7config=0
8sample_period=0
9sample_type=0
10read_format=3
11disabled=1
12inherit=1
13pinned=0
14exclusive=0
15exclude_user=0
16exclude_kernel=0
17exclude_hv=0
18exclude_idle=0
19mmap=0
20comm=0
21freq=0
22inherit_stat=0
23enable_on_exec=1
24task=0
25watermark=0
26precise_ip=0
27mmap_data=0
28sample_id_all=0
29exclude_host=0
30exclude_guest=1
31exclude_callchain_kernel=0
32exclude_callchain_user=0
33wakeup_events=0
34bp_type=0
35config1=0
36config2=0
37branch_sample_type=0
38sample_regs_user=0
39sample_stack_user=0
diff --git a/tools/perf/tests/attr/test-record-basic b/tools/perf/tests/attr/test-record-basic
new file mode 100644
index 000000000000..55c0428370ca
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-basic
@@ -0,0 +1,5 @@
1[config]
2command = record
3args = kill >/dev/null 2>&1
4
5[event:base-record]
diff --git a/tools/perf/tests/attr/test-record-branch-any b/tools/perf/tests/attr/test-record-branch-any
new file mode 100644
index 000000000000..1421960ed4e9
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-any
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -b kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any b/tools/perf/tests/attr/test-record-branch-filter-any
new file mode 100644
index 000000000000..915c4df0e0c2
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-any
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j any kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_call b/tools/perf/tests/attr/test-record-branch-filter-any_call
new file mode 100644
index 000000000000..8708dbd4f373
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-any_call
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j any_call kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=16
diff --git a/tools/perf/tests/attr/test-record-branch-filter-any_ret b/tools/perf/tests/attr/test-record-branch-filter-any_ret
new file mode 100644
index 000000000000..0d3607a6dcbe
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-any_ret
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j any_ret kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=32
diff --git a/tools/perf/tests/attr/test-record-branch-filter-hv b/tools/perf/tests/attr/test-record-branch-filter-hv
new file mode 100644
index 000000000000..f25526740cec
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-hv
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j hv kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-ind_call b/tools/perf/tests/attr/test-record-branch-filter-ind_call
new file mode 100644
index 000000000000..e862dd179128
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-ind_call
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j ind_call kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=64
diff --git a/tools/perf/tests/attr/test-record-branch-filter-k b/tools/perf/tests/attr/test-record-branch-filter-k
new file mode 100644
index 000000000000..182971e898f5
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-k
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j k kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-branch-filter-u b/tools/perf/tests/attr/test-record-branch-filter-u
new file mode 100644
index 000000000000..83449ef9e687
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-branch-filter-u
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -j u kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=2311
8branch_sample_type=8
diff --git a/tools/perf/tests/attr/test-record-count b/tools/perf/tests/attr/test-record-count
new file mode 100644
index 000000000000..2f841de56f6b
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-count
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -c 123 kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=123
7sample_type=7
8freq=0
diff --git a/tools/perf/tests/attr/test-record-data b/tools/perf/tests/attr/test-record-data
new file mode 100644
index 000000000000..6627c3e7534a
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-data
@@ -0,0 +1,8 @@
1[config]
2command = record
3args = -d kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=271
8mmap_data=1
diff --git a/tools/perf/tests/attr/test-record-freq b/tools/perf/tests/attr/test-record-freq
new file mode 100644
index 000000000000..600d0f8f2583
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-freq
@@ -0,0 +1,6 @@
1[config]
2command = record
3args = -F 100 kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=100
diff --git a/tools/perf/tests/attr/test-record-graph-default b/tools/perf/tests/attr/test-record-graph-default
new file mode 100644
index 000000000000..833d1849d767
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-graph-default
@@ -0,0 +1,6 @@
1[config]
2command = record
3args = -g -- kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=295
diff --git a/tools/perf/tests/attr/test-record-graph-dwarf b/tools/perf/tests/attr/test-record-graph-dwarf
new file mode 100644
index 000000000000..e93e082f5208
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-graph-dwarf
@@ -0,0 +1,10 @@
1[config]
2command = record
3args = -g dwarf -- kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=12583
7exclude_callchain_user=1
8sample_stack_user=8192
9# TODO different for each arch, no support for that now
10sample_regs_user=*
diff --git a/tools/perf/tests/attr/test-record-graph-fp b/tools/perf/tests/attr/test-record-graph-fp
new file mode 100644
index 000000000000..7cef3743f03f
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-graph-fp
@@ -0,0 +1,6 @@
1[config]
2command = record
3args = -g fp kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=295
diff --git a/tools/perf/tests/attr/test-record-group b/tools/perf/tests/attr/test-record-group
new file mode 100644
index 000000000000..57739cacdb2a
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-group
@@ -0,0 +1,20 @@
1[config]
2command = record
3args = --group -e cycles,instructions kill >/dev/null 2>&1
4
5[event-1:base-record]
6fd=1
7group_fd=-1
8sample_type=327
9read_format=4
10
11[event-2:base-record]
12fd=2
13group_fd=1
14config=1
15sample_type=327
16read_format=4
17mmap=0
18comm=0
19enable_on_exec=0
20disabled=0
diff --git a/tools/perf/tests/attr/test-record-group1 b/tools/perf/tests/attr/test-record-group1
new file mode 100644
index 000000000000..c5548d054aff
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-group1
@@ -0,0 +1,21 @@
1[config]
2command = record
3args = -e '{cycles,instructions}' kill >/dev/null 2>&1
4
5[event-1:base-record]
6fd=1
7group_fd=-1
8sample_type=327
9read_format=4
10
11[event-2:base-record]
12fd=2
13group_fd=1
14type=0
15config=1
16sample_type=327
17read_format=4
18mmap=0
19comm=0
20enable_on_exec=0
21disabled=0
diff --git a/tools/perf/tests/attr/test-record-no-delay b/tools/perf/tests/attr/test-record-no-delay
new file mode 100644
index 000000000000..f253b78cdbf2
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-no-delay
@@ -0,0 +1,9 @@
1[config]
2command = record
3args = -D kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=263
8watermark=0
9wakeup_events=1
diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/attr/test-record-no-inherit
new file mode 100644
index 000000000000..9079a25cd643
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-no-inherit
@@ -0,0 +1,7 @@
1[config]
2command = record
3args = -i kill >/dev/null 2>&1
4
5[event:base-record]
6sample_type=259
7inherit=0
diff --git a/tools/perf/tests/attr/test-record-no-samples b/tools/perf/tests/attr/test-record-no-samples
new file mode 100644
index 000000000000..d0141b2418b5
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-no-samples
@@ -0,0 +1,6 @@
1[config]
2command = record
3args = -n kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=0
diff --git a/tools/perf/tests/attr/test-record-period b/tools/perf/tests/attr/test-record-period
new file mode 100644
index 000000000000..8abc5314fc52
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-period
@@ -0,0 +1,7 @@
1[config]
2command = record
3args = -c 100 -P kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=100
7freq=0
diff --git a/tools/perf/tests/attr/test-record-raw b/tools/perf/tests/attr/test-record-raw
new file mode 100644
index 000000000000..4a8ef25b5f49
--- /dev/null
+++ b/tools/perf/tests/attr/test-record-raw
@@ -0,0 +1,7 @@
1[config]
2command = record
3args = -R kill >/dev/null 2>&1
4
5[event:base-record]
6sample_period=4000
7sample_type=1415
diff --git a/tools/perf/tests/attr/test-stat-basic b/tools/perf/tests/attr/test-stat-basic
new file mode 100644
index 000000000000..74e17881f2ba
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-basic
@@ -0,0 +1,6 @@
1[config]
2command = stat
3args = -e cycles kill >/dev/null 2>&1
4ret = 1
5
6[event:base-stat]
diff --git a/tools/perf/tests/attr/test-stat-default b/tools/perf/tests/attr/test-stat-default
new file mode 100644
index 000000000000..19270f54c96e
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-default
@@ -0,0 +1,64 @@
1[config]
2command = stat
3args = kill >/dev/null 2>&1
4ret = 1
5
6# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
7[event1:base-stat]
8fd=1
9type=1
10config=1
11
12# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
13[event2:base-stat]
14fd=2
15type=1
16config=3
17
18# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
19[event3:base-stat]
20fd=3
21type=1
22config=4
23
24# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
25[event4:base-stat]
26fd=4
27type=1
28config=2
29
30# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
31[event5:base-stat]
32fd=5
33type=0
34config=0
35
36# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
37[event6:base-stat]
38fd=6
39type=0
40config=7
41
42# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
43[event7:base-stat]
44fd=7
45type=0
46config=8
47
48# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
49[event8:base-stat]
50fd=8
51type=0
52config=1
53
54# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
55[event9:base-stat]
56fd=9
57type=0
58config=4
59
60# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
61[event10:base-stat]
62fd=10
63type=0
64config=5
diff --git a/tools/perf/tests/attr/test-stat-detailed-1 b/tools/perf/tests/attr/test-stat-detailed-1
new file mode 100644
index 000000000000..51426b87153b
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-detailed-1
@@ -0,0 +1,101 @@
1[config]
2command = stat
3args = -d kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
diff --git a/tools/perf/tests/attr/test-stat-detailed-2 b/tools/perf/tests/attr/test-stat-detailed-2
new file mode 100644
index 000000000000..8de5acc31c27
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-detailed-2
@@ -0,0 +1,155 @@
1[config]
2command = stat
3args = -dd kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
102
103# PERF_TYPE_HW_CACHE,
104# PERF_COUNT_HW_CACHE_L1I << 0 |
105# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
106# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
107[event15:base-stat]
108fd=15
109type=3
110config=1
111
112# PERF_TYPE_HW_CACHE,
113# PERF_COUNT_HW_CACHE_L1I << 0 |
114# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
115# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
116[event16:base-stat]
117fd=16
118type=3
119config=65537
120
121# PERF_TYPE_HW_CACHE,
122# PERF_COUNT_HW_CACHE_DTLB << 0 |
123# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
124# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
125[event17:base-stat]
126fd=17
127type=3
128config=3
129
130# PERF_TYPE_HW_CACHE,
131# PERF_COUNT_HW_CACHE_DTLB << 0 |
132# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
133# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
134[event18:base-stat]
135fd=18
136type=3
137config=65539
138
139# PERF_TYPE_HW_CACHE,
140# PERF_COUNT_HW_CACHE_ITLB << 0 |
141# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
142# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
143[event19:base-stat]
144fd=19
145type=3
146config=4
147
148# PERF_TYPE_HW_CACHE,
149# PERF_COUNT_HW_CACHE_ITLB << 0 |
150# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
151# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
152[event20:base-stat]
153fd=20
154type=3
155config=65540
diff --git a/tools/perf/tests/attr/test-stat-detailed-3 b/tools/perf/tests/attr/test-stat-detailed-3
new file mode 100644
index 000000000000..0a1f45bf7d79
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-detailed-3
@@ -0,0 +1,173 @@
1[config]
2command = stat
3args = -ddd kill >/dev/null 2>&1
4ret = 1
5
6
7# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
8[event1:base-stat]
9fd=1
10type=1
11config=1
12
13# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
14[event2:base-stat]
15fd=2
16type=1
17config=3
18
19# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
20[event3:base-stat]
21fd=3
22type=1
23config=4
24
25# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
26[event4:base-stat]
27fd=4
28type=1
29config=2
30
31# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
32[event5:base-stat]
33fd=5
34type=0
35config=0
36
37# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
38[event6:base-stat]
39fd=6
40type=0
41config=7
42
43# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
44[event7:base-stat]
45fd=7
46type=0
47config=8
48
49# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
50[event8:base-stat]
51fd=8
52type=0
53config=1
54
55# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
56[event9:base-stat]
57fd=9
58type=0
59config=4
60
61# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
62[event10:base-stat]
63fd=10
64type=0
65config=5
66
67# PERF_TYPE_HW_CACHE /
68# PERF_COUNT_HW_CACHE_L1D << 0 |
69# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
70# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
71[event11:base-stat]
72fd=11
73type=3
74config=0
75
76# PERF_TYPE_HW_CACHE /
77# PERF_COUNT_HW_CACHE_L1D << 0 |
78# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
79# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
80[event12:base-stat]
81fd=12
82type=3
83config=65536
84
85# PERF_TYPE_HW_CACHE /
86# PERF_COUNT_HW_CACHE_LL << 0 |
87# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
88# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
89[event13:base-stat]
90fd=13
91type=3
92config=2
93
94# PERF_TYPE_HW_CACHE,
95# PERF_COUNT_HW_CACHE_LL << 0 |
96# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
97# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
98[event14:base-stat]
99fd=14
100type=3
101config=65538
102
103# PERF_TYPE_HW_CACHE,
104# PERF_COUNT_HW_CACHE_L1I << 0 |
105# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
106# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
107[event15:base-stat]
108fd=15
109type=3
110config=1
111
112# PERF_TYPE_HW_CACHE,
113# PERF_COUNT_HW_CACHE_L1I << 0 |
114# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
115# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
116[event16:base-stat]
117fd=16
118type=3
119config=65537
120
121# PERF_TYPE_HW_CACHE,
122# PERF_COUNT_HW_CACHE_DTLB << 0 |
123# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
124# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
125[event17:base-stat]
126fd=17
127type=3
128config=3
129
130# PERF_TYPE_HW_CACHE,
131# PERF_COUNT_HW_CACHE_DTLB << 0 |
132# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
133# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
134[event18:base-stat]
135fd=18
136type=3
137config=65539
138
139# PERF_TYPE_HW_CACHE,
140# PERF_COUNT_HW_CACHE_ITLB << 0 |
141# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
142# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
143[event19:base-stat]
144fd=19
145type=3
146config=4
147
148# PERF_TYPE_HW_CACHE,
149# PERF_COUNT_HW_CACHE_ITLB << 0 |
150# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
151# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
152[event20:base-stat]
153fd=20
154type=3
155config=65540
156
157# PERF_TYPE_HW_CACHE,
158# PERF_COUNT_HW_CACHE_L1D << 0 |
159# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
160# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
161[event21:base-stat]
162fd=21
163type=3
164config=512
165
166# PERF_TYPE_HW_CACHE,
167# PERF_COUNT_HW_CACHE_L1D << 0 |
168# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
169# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
170[event22:base-stat]
171fd=22
172type=3
173config=66048
diff --git a/tools/perf/tests/attr/test-stat-group b/tools/perf/tests/attr/test-stat-group
new file mode 100644
index 000000000000..fdc1596a8862
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-group
@@ -0,0 +1,15 @@
1[config]
2command = stat
3args = --group -e cycles,instructions kill >/dev/null 2>&1
4ret = 1
5
6[event-1:base-stat]
7fd=1
8group_fd=-1
9
10[event-2:base-stat]
11fd=2
12group_fd=1
13config=1
14disabled=0
15enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-stat-group1 b/tools/perf/tests/attr/test-stat-group1
new file mode 100644
index 000000000000..2a1f86e4a904
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-group1
@@ -0,0 +1,15 @@
1[config]
2command = stat
3args = -e '{cycles,instructions}' kill >/dev/null 2>&1
4ret = 1
5
6[event-1:base-stat]
7fd=1
8group_fd=-1
9
10[event-2:base-stat]
11fd=2
12group_fd=1
13config=1
14disabled=0
15enable_on_exec=0
diff --git a/tools/perf/tests/attr/test-stat-no-inherit b/tools/perf/tests/attr/test-stat-no-inherit
new file mode 100644
index 000000000000..d54b2a1e3e28
--- /dev/null
+++ b/tools/perf/tests/attr/test-stat-no-inherit
@@ -0,0 +1,7 @@
1[config]
2command = stat
3args = -i -e cycles kill >/dev/null 2>&1
4ret = 1
5
6[event:base-stat]
7inherit=0
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
new file mode 100644
index 000000000000..acb98e0e39f2
--- /dev/null
+++ b/tools/perf/tests/builtin-test.c
@@ -0,0 +1,203 @@
1/*
2 * builtin-test.c
3 *
4 * Builtin regression testing command: ever growing number of sanity tests
5 */
6#include "builtin.h"
7#include "intlist.h"
8#include "tests.h"
9#include "debug.h"
10#include "color.h"
11#include "parse-options.h"
12#include "symbol.h"
13
14static struct test {
15 const char *desc;
16 int (*func)(void);
17} tests[] = {
18 {
19 .desc = "vmlinux symtab matches kallsyms",
20 .func = test__vmlinux_matches_kallsyms,
21 },
22 {
23 .desc = "detect open syscall event",
24 .func = test__open_syscall_event,
25 },
26 {
27 .desc = "detect open syscall event on all cpus",
28 .func = test__open_syscall_event_on_all_cpus,
29 },
30 {
31 .desc = "read samples using the mmap interface",
32 .func = test__basic_mmap,
33 },
34 {
35 .desc = "parse events tests",
36 .func = test__parse_events,
37 },
38#if defined(__x86_64__) || defined(__i386__)
39 {
40 .desc = "x86 rdpmc test",
41 .func = test__rdpmc,
42 },
43#endif
44 {
45 .desc = "Validate PERF_RECORD_* events & perf_sample fields",
46 .func = test__PERF_RECORD,
47 },
48 {
49 .desc = "Test perf pmu format parsing",
50 .func = test__pmu,
51 },
52 {
53 .desc = "Test dso data interface",
54 .func = test__dso_data,
55 },
56 {
57 .desc = "roundtrip evsel->name check",
58 .func = test__perf_evsel__roundtrip_name_test,
59 },
60 {
61 .desc = "Check parsing of sched tracepoints fields",
62 .func = test__perf_evsel__tp_sched_test,
63 },
64 {
65 .desc = "Generate and check syscalls:sys_enter_open event fields",
66 .func = test__syscall_open_tp_fields,
67 },
68 {
69 .desc = "struct perf_event_attr setup",
70 .func = test__attr,
71 },
72 {
73 .desc = "Test matching and linking mutliple hists",
74 .func = test__hists_link,
75 },
76 {
77 .desc = "Try 'use perf' in python, checking link problems",
78 .func = test__python_use,
79 },
80 {
81 .func = NULL,
82 },
83};
84
85static bool perf_test__matches(int curr, int argc, const char *argv[])
86{
87 int i;
88
89 if (argc == 0)
90 return true;
91
92 for (i = 0; i < argc; ++i) {
93 char *end;
94 long nr = strtoul(argv[i], &end, 10);
95
96 if (*end == '\0') {
97 if (nr == curr + 1)
98 return true;
99 continue;
100 }
101
102 if (strstr(tests[curr].desc, argv[i]))
103 return true;
104 }
105
106 return false;
107}
108
109static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
110{
111 int i = 0;
112 int width = 0;
113
114 while (tests[i].func) {
115 int len = strlen(tests[i].desc);
116
117 if (width < len)
118 width = len;
119 ++i;
120 }
121
122 i = 0;
123 while (tests[i].func) {
124 int curr = i++, err;
125
126 if (!perf_test__matches(curr, argc, argv))
127 continue;
128
129 pr_info("%2d: %-*s:", i, width, tests[curr].desc);
130
131 if (intlist__find(skiplist, i)) {
132 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
133 continue;
134 }
135
136 pr_debug("\n--- start ---\n");
137 err = tests[curr].func();
138 pr_debug("---- end ----\n%s:", tests[curr].desc);
139
140 switch (err) {
141 case TEST_OK:
142 pr_info(" Ok\n");
143 break;
144 case TEST_SKIP:
145 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
146 break;
147 case TEST_FAIL:
148 default:
149 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
150 break;
151 }
152 }
153
154 return 0;
155}
156
157static int perf_test__list(int argc, const char **argv)
158{
159 int i = 0;
160
161 while (tests[i].func) {
162 int curr = i++;
163
164 if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
165 continue;
166
167 pr_info("%2d: %s\n", i, tests[curr].desc);
168 }
169
170 return 0;
171}
172
173int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
174{
175 const char * const test_usage[] = {
176 "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
177 NULL,
178 };
179 const char *skip = NULL;
180 const struct option test_options[] = {
181 OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
182 OPT_INCR('v', "verbose", &verbose,
183 "be more verbose (show symbol address, etc)"),
184 OPT_END()
185 };
186 struct intlist *skiplist = NULL;
187
188 argc = parse_options(argc, argv, test_options, test_usage, 0);
189 if (argc >= 1 && !strcmp(argv[0], "list"))
190 return perf_test__list(argc, argv);
191
192 symbol_conf.priv_size = sizeof(int);
193 symbol_conf.sort_by_name = true;
194 symbol_conf.try_vmlinux_path = true;
195
196 if (symbol__init() < 0)
197 return -1;
198
199 if (skip != NULL)
200 skiplist = intlist__new(skip);
201
202 return __cmd_test(argc, argv, skiplist);
203}
diff --git a/tools/perf/util/dso-test-data.c b/tools/perf/tests/dso-data.c
index c6caedeb1d6b..5eaffa2de9c5 100644
--- a/tools/perf/util/dso-test-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -6,7 +6,9 @@
6#include <fcntl.h> 6#include <fcntl.h>
7#include <string.h> 7#include <string.h>
8 8
9#include "machine.h"
9#include "symbol.h" 10#include "symbol.h"
11#include "tests.h"
10 12
11#define TEST_ASSERT_VAL(text, cond) \ 13#define TEST_ASSERT_VAL(text, cond) \
12do { \ 14do { \
@@ -24,6 +26,10 @@ static char *test_file(int size)
24 unsigned char *buf; 26 unsigned char *buf;
25 27
26 fd = mkstemp(templ); 28 fd = mkstemp(templ);
29 if (fd < 0) {
30 perror("mkstemp failed");
31 return NULL;
32 }
27 33
28 buf = malloc(size); 34 buf = malloc(size);
29 if (!buf) { 35 if (!buf) {
@@ -94,7 +100,7 @@ struct test_data_offset offsets[] = {
94 }, 100 },
95}; 101};
96 102
97int dso__test_data(void) 103int test__dso_data(void)
98{ 104{
99 struct machine machine; 105 struct machine machine;
100 struct dso *dso; 106 struct dso *dso;
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
new file mode 100644
index 000000000000..0fd99a9adb91
--- /dev/null
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -0,0 +1,114 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "parse-events.h"
4#include "tests.h"
5
6static int perf_evsel__roundtrip_cache_name_test(void)
7{
8 char name[128];
9 int type, op, err = 0, ret = 0, i, idx;
10 struct perf_evsel *evsel;
11 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
12
13 if (evlist == NULL)
14 return -ENOMEM;
15
16 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
17 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
18 /* skip invalid cache type */
19 if (!perf_evsel__is_cache_op_valid(type, op))
20 continue;
21
22 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
23 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
24 name, sizeof(name));
25 err = parse_events(evlist, name);
26 if (err)
27 ret = err;
28 }
29 }
30 }
31
32 idx = 0;
33 evsel = perf_evlist__first(evlist);
34
35 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
36 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
37 /* skip invalid cache type */
38 if (!perf_evsel__is_cache_op_valid(type, op))
39 continue;
40
41 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
42 __perf_evsel__hw_cache_type_op_res_name(type, op, i,
43 name, sizeof(name));
44 if (evsel->idx != idx)
45 continue;
46
47 ++idx;
48
49 if (strcmp(perf_evsel__name(evsel), name)) {
50 pr_debug("%s != %s\n", perf_evsel__name(evsel), name);
51 ret = -1;
52 }
53
54 evsel = perf_evsel__next(evsel);
55 }
56 }
57 }
58
59 perf_evlist__delete(evlist);
60 return ret;
61}
62
63static int __perf_evsel__name_array_test(const char *names[], int nr_names)
64{
65 int i, err;
66 struct perf_evsel *evsel;
67 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
68
69 if (evlist == NULL)
70 return -ENOMEM;
71
72 for (i = 0; i < nr_names; ++i) {
73 err = parse_events(evlist, names[i]);
74 if (err) {
75 pr_debug("failed to parse event '%s', err %d\n",
76 names[i], err);
77 goto out_delete_evlist;
78 }
79 }
80
81 err = 0;
82 list_for_each_entry(evsel, &evlist->entries, node) {
83 if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) {
84 --err;
85 pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]);
86 }
87 }
88
89out_delete_evlist:
90 perf_evlist__delete(evlist);
91 return err;
92}
93
94#define perf_evsel__name_array_test(names) \
95 __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
96
97int test__perf_evsel__roundtrip_name_test(void)
98{
99 int err = 0, ret = 0;
100
101 err = perf_evsel__name_array_test(perf_evsel__hw_names);
102 if (err)
103 ret = err;
104
105 err = perf_evsel__name_array_test(perf_evsel__sw_names);
106 if (err)
107 ret = err;
108
109 err = perf_evsel__roundtrip_cache_name_test();
110 if (err)
111 ret = err;
112
113 return ret;
114}
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
new file mode 100644
index 000000000000..a5d2fcc5ae35
--- /dev/null
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -0,0 +1,84 @@
1#include "evsel.h"
2#include "tests.h"
3#include "event-parse.h"
4
5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
6 int size, bool should_be_signed)
7{
8 struct format_field *field = perf_evsel__field(evsel, name);
9 int is_signed;
10 int ret = 0;
11
12 if (field == NULL) {
13 pr_debug("%s: \"%s\" field not found!\n", evsel->name, name);
14 return -1;
15 }
16
17 is_signed = !!(field->flags | FIELD_IS_SIGNED);
18 if (should_be_signed && !is_signed) {
19 pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
20 evsel->name, name, is_signed, should_be_signed);
21 ret = -1;
22 }
23
24 if (field->size != size) {
25 pr_debug("%s: \"%s\" size (%d) should be %d!\n",
26 evsel->name, name, field->size, size);
27 ret = -1;
28 }
29
30 return ret;
31}
32
33int test__perf_evsel__tp_sched_test(void)
34{
35 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0);
36 int ret = 0;
37
38 if (evsel == NULL) {
39 pr_debug("perf_evsel__new\n");
40 return -1;
41 }
42
43 if (perf_evsel__test_field(evsel, "prev_comm", 16, true))
44 ret = -1;
45
46 if (perf_evsel__test_field(evsel, "prev_pid", 4, true))
47 ret = -1;
48
49 if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
50 ret = -1;
51
52 if (perf_evsel__test_field(evsel, "prev_state", 8, true))
53 ret = -1;
54
55 if (perf_evsel__test_field(evsel, "next_comm", 16, true))
56 ret = -1;
57
58 if (perf_evsel__test_field(evsel, "next_pid", 4, true))
59 ret = -1;
60
61 if (perf_evsel__test_field(evsel, "next_prio", 4, true))
62 ret = -1;
63
64 perf_evsel__delete(evsel);
65
66 evsel = perf_evsel__newtp("sched", "sched_wakeup", 0);
67
68 if (perf_evsel__test_field(evsel, "comm", 16, true))
69 ret = -1;
70
71 if (perf_evsel__test_field(evsel, "pid", 4, true))
72 ret = -1;
73
74 if (perf_evsel__test_field(evsel, "prio", 4, true))
75 ret = -1;
76
77 if (perf_evsel__test_field(evsel, "success", 4, true))
78 ret = -1;
79
80 if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
81 ret = -1;
82
83 return ret;
84}
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
new file mode 100644
index 000000000000..1be64a6c5daf
--- /dev/null
+++ b/tools/perf/tests/hists_link.c
@@ -0,0 +1,500 @@
1#include "perf.h"
2#include "tests.h"
3#include "debug.h"
4#include "symbol.h"
5#include "sort.h"
6#include "evsel.h"
7#include "evlist.h"
8#include "machine.h"
9#include "thread.h"
10#include "parse-events.h"
11
12static struct {
13 u32 pid;
14 const char *comm;
15} fake_threads[] = {
16 { 100, "perf" },
17 { 200, "perf" },
18 { 300, "bash" },
19};
20
21static struct {
22 u32 pid;
23 u64 start;
24 const char *filename;
25} fake_mmap_info[] = {
26 { 100, 0x40000, "perf" },
27 { 100, 0x50000, "libc" },
28 { 100, 0xf0000, "[kernel]" },
29 { 200, 0x40000, "perf" },
30 { 200, 0x50000, "libc" },
31 { 200, 0xf0000, "[kernel]" },
32 { 300, 0x40000, "bash" },
33 { 300, 0x50000, "libc" },
34 { 300, 0xf0000, "[kernel]" },
35};
36
37struct fake_sym {
38 u64 start;
39 u64 length;
40 const char *name;
41};
42
43static struct fake_sym perf_syms[] = {
44 { 700, 100, "main" },
45 { 800, 100, "run_command" },
46 { 900, 100, "cmd_record" },
47};
48
49static struct fake_sym bash_syms[] = {
50 { 700, 100, "main" },
51 { 800, 100, "xmalloc" },
52 { 900, 100, "xfree" },
53};
54
55static struct fake_sym libc_syms[] = {
56 { 700, 100, "malloc" },
57 { 800, 100, "free" },
58 { 900, 100, "realloc" },
59};
60
61static struct fake_sym kernel_syms[] = {
62 { 700, 100, "schedule" },
63 { 800, 100, "page_fault" },
64 { 900, 100, "sys_perf_event_open" },
65};
66
67static struct {
68 const char *dso_name;
69 struct fake_sym *syms;
70 size_t nr_syms;
71} fake_symbols[] = {
72 { "perf", perf_syms, ARRAY_SIZE(perf_syms) },
73 { "bash", bash_syms, ARRAY_SIZE(bash_syms) },
74 { "libc", libc_syms, ARRAY_SIZE(libc_syms) },
75 { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) },
76};
77
78static struct machine *setup_fake_machine(struct machines *machines)
79{
80 struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
81 size_t i;
82
83 if (machine == NULL) {
84 pr_debug("Not enough memory for machine setup\n");
85 return NULL;
86 }
87
88 for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
89 struct thread *thread;
90
91 thread = machine__findnew_thread(machine, fake_threads[i].pid);
92 if (thread == NULL)
93 goto out;
94
95 thread__set_comm(thread, fake_threads[i].comm);
96 }
97
98 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
99 union perf_event fake_mmap_event = {
100 .mmap = {
101 .header = { .misc = PERF_RECORD_MISC_USER, },
102 .pid = fake_mmap_info[i].pid,
103 .start = fake_mmap_info[i].start,
104 .len = 0x1000ULL,
105 .pgoff = 0ULL,
106 },
107 };
108
109 strcpy(fake_mmap_event.mmap.filename,
110 fake_mmap_info[i].filename);
111
112 machine__process_mmap_event(machine, &fake_mmap_event);
113 }
114
115 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
116 size_t k;
117 struct dso *dso;
118
119 dso = __dsos__findnew(&machine->user_dsos,
120 fake_symbols[i].dso_name);
121 if (dso == NULL)
122 goto out;
123
124 /* emulate dso__load() */
125 dso__set_loaded(dso, MAP__FUNCTION);
126
127 for (k = 0; k < fake_symbols[i].nr_syms; k++) {
128 struct symbol *sym;
129 struct fake_sym *fsym = &fake_symbols[i].syms[k];
130
131 sym = symbol__new(fsym->start, fsym->length,
132 STB_GLOBAL, fsym->name);
133 if (sym == NULL)
134 goto out;
135
136 symbols__insert(&dso->symbols[MAP__FUNCTION], sym);
137 }
138 }
139
140 return machine;
141
142out:
143 pr_debug("Not enough memory for machine setup\n");
144 machine__delete_threads(machine);
145 machine__delete(machine);
146 return NULL;
147}
148
149struct sample {
150 u32 pid;
151 u64 ip;
152 struct thread *thread;
153 struct map *map;
154 struct symbol *sym;
155};
156
157static struct sample fake_common_samples[] = {
158 /* perf [kernel] schedule() */
159 { .pid = 100, .ip = 0xf0000 + 700, },
160 /* perf [perf] main() */
161 { .pid = 200, .ip = 0x40000 + 700, },
162 /* perf [perf] cmd_record() */
163 { .pid = 200, .ip = 0x40000 + 900, },
164 /* bash [bash] xmalloc() */
165 { .pid = 300, .ip = 0x40000 + 800, },
166 /* bash [libc] malloc() */
167 { .pid = 300, .ip = 0x50000 + 700, },
168};
169
170static struct sample fake_samples[][5] = {
171 {
172 /* perf [perf] run_command() */
173 { .pid = 100, .ip = 0x40000 + 800, },
174 /* perf [libc] malloc() */
175 { .pid = 100, .ip = 0x50000 + 700, },
176 /* perf [kernel] page_fault() */
177 { .pid = 100, .ip = 0xf0000 + 800, },
178 /* perf [kernel] sys_perf_event_open() */
179 { .pid = 200, .ip = 0xf0000 + 900, },
180 /* bash [libc] free() */
181 { .pid = 300, .ip = 0x50000 + 800, },
182 },
183 {
184 /* perf [libc] free() */
185 { .pid = 200, .ip = 0x50000 + 800, },
186 /* bash [libc] malloc() */
187 { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */
188 /* bash [bash] xfee() */
189 { .pid = 300, .ip = 0x40000 + 900, },
190 /* bash [libc] realloc() */
191 { .pid = 300, .ip = 0x50000 + 900, },
192 /* bash [kernel] page_fault() */
193 { .pid = 300, .ip = 0xf0000 + 800, },
194 },
195};
196
197static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
198{
199 struct perf_evsel *evsel;
200 struct addr_location al;
201 struct hist_entry *he;
202 struct perf_sample sample = { .cpu = 0, };
203 size_t i = 0, k;
204
205 /*
206 * each evsel will have 10 samples - 5 common and 5 distinct.
207 * However the second evsel also has a collapsed entry for
208 * "bash [libc] malloc" so total 9 entries will be in the tree.
209 */
210 list_for_each_entry(evsel, &evlist->entries, node) {
211 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
212 const union perf_event event = {
213 .ip = {
214 .header = {
215 .misc = PERF_RECORD_MISC_USER,
216 },
217 .pid = fake_common_samples[k].pid,
218 .ip = fake_common_samples[k].ip,
219 },
220 };
221
222 if (perf_event__preprocess_sample(&event, machine, &al,
223 &sample, 0) < 0)
224 goto out;
225
226 he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
227 if (he == NULL)
228 goto out;
229
230 fake_common_samples[k].thread = al.thread;
231 fake_common_samples[k].map = al.map;
232 fake_common_samples[k].sym = al.sym;
233 }
234
235 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
236 const union perf_event event = {
237 .ip = {
238 .header = {
239 .misc = PERF_RECORD_MISC_USER,
240 },
241 .pid = fake_samples[i][k].pid,
242 .ip = fake_samples[i][k].ip,
243 },
244 };
245
246 if (perf_event__preprocess_sample(&event, machine, &al,
247 &sample, 0) < 0)
248 goto out;
249
250 he = __hists__add_entry(&evsel->hists, &al, NULL, 1);
251 if (he == NULL)
252 goto out;
253
254 fake_samples[i][k].thread = al.thread;
255 fake_samples[i][k].map = al.map;
256 fake_samples[i][k].sym = al.sym;
257 }
258 i++;
259 }
260
261 return 0;
262
263out:
264 pr_debug("Not enough memory for adding a hist entry\n");
265 return -1;
266}
267
268static int find_sample(struct sample *samples, size_t nr_samples,
269 struct thread *t, struct map *m, struct symbol *s)
270{
271 while (nr_samples--) {
272 if (samples->thread == t && samples->map == m &&
273 samples->sym == s)
274 return 1;
275 samples++;
276 }
277 return 0;
278}
279
280static int __validate_match(struct hists *hists)
281{
282 size_t count = 0;
283 struct rb_root *root;
284 struct rb_node *node;
285
286 /*
287 * Only entries from fake_common_samples should have a pair.
288 */
289 if (sort__need_collapse)
290 root = &hists->entries_collapsed;
291 else
292 root = hists->entries_in;
293
294 node = rb_first(root);
295 while (node) {
296 struct hist_entry *he;
297
298 he = rb_entry(node, struct hist_entry, rb_node_in);
299
300 if (hist_entry__has_pairs(he)) {
301 if (find_sample(fake_common_samples,
302 ARRAY_SIZE(fake_common_samples),
303 he->thread, he->ms.map, he->ms.sym)) {
304 count++;
305 } else {
306 pr_debug("Can't find the matched entry\n");
307 return -1;
308 }
309 }
310
311 node = rb_next(node);
312 }
313
314 if (count != ARRAY_SIZE(fake_common_samples)) {
315 pr_debug("Invalid count for matched entries: %zd of %zd\n",
316 count, ARRAY_SIZE(fake_common_samples));
317 return -1;
318 }
319
320 return 0;
321}
322
323static int validate_match(struct hists *leader, struct hists *other)
324{
325 return __validate_match(leader) || __validate_match(other);
326}
327
328static int __validate_link(struct hists *hists, int idx)
329{
330 size_t count = 0;
331 size_t count_pair = 0;
332 size_t count_dummy = 0;
333 struct rb_root *root;
334 struct rb_node *node;
335
336 /*
337 * Leader hists (idx = 0) will have dummy entries from other,
338 * and some entries will have no pair. However every entry
339 * in other hists should have (dummy) pair.
340 */
341 if (sort__need_collapse)
342 root = &hists->entries_collapsed;
343 else
344 root = hists->entries_in;
345
346 node = rb_first(root);
347 while (node) {
348 struct hist_entry *he;
349
350 he = rb_entry(node, struct hist_entry, rb_node_in);
351
352 if (hist_entry__has_pairs(he)) {
353 if (!find_sample(fake_common_samples,
354 ARRAY_SIZE(fake_common_samples),
355 he->thread, he->ms.map, he->ms.sym) &&
356 !find_sample(fake_samples[idx],
357 ARRAY_SIZE(fake_samples[idx]),
358 he->thread, he->ms.map, he->ms.sym)) {
359 count_dummy++;
360 }
361 count_pair++;
362 } else if (idx) {
363 pr_debug("A entry from the other hists should have pair\n");
364 return -1;
365 }
366
367 count++;
368 node = rb_next(node);
369 }
370
371 /*
372 * Note that we have a entry collapsed in the other (idx = 1) hists.
373 */
374 if (idx == 0) {
375 if (count_dummy != ARRAY_SIZE(fake_samples[1]) - 1) {
376 pr_debug("Invalid count of dummy entries: %zd of %zd\n",
377 count_dummy, ARRAY_SIZE(fake_samples[1]) - 1);
378 return -1;
379 }
380 if (count != count_pair + ARRAY_SIZE(fake_samples[0])) {
381 pr_debug("Invalid count of total leader entries: %zd of %zd\n",
382 count, count_pair + ARRAY_SIZE(fake_samples[0]));
383 return -1;
384 }
385 } else {
386 if (count != count_pair) {
387 pr_debug("Invalid count of total other entries: %zd of %zd\n",
388 count, count_pair);
389 return -1;
390 }
391 if (count_dummy > 0) {
392 pr_debug("Other hists should not have dummy entries: %zd\n",
393 count_dummy);
394 return -1;
395 }
396 }
397
398 return 0;
399}
400
401static int validate_link(struct hists *leader, struct hists *other)
402{
403 return __validate_link(leader, 0) || __validate_link(other, 1);
404}
405
406static void print_hists(struct hists *hists)
407{
408 int i = 0;
409 struct rb_root *root;
410 struct rb_node *node;
411
412 if (sort__need_collapse)
413 root = &hists->entries_collapsed;
414 else
415 root = hists->entries_in;
416
417 pr_info("----- %s --------\n", __func__);
418 node = rb_first(root);
419 while (node) {
420 struct hist_entry *he;
421
422 he = rb_entry(node, struct hist_entry, rb_node_in);
423
424 pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
425 i, he->thread->comm, he->ms.map->dso->short_name,
426 he->ms.sym->name, he->stat.period);
427
428 i++;
429 node = rb_next(node);
430 }
431}
432
433int test__hists_link(void)
434{
435 int err = -1;
436 struct machines machines;
437 struct machine *machine = NULL;
438 struct perf_evsel *evsel, *first;
439 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
440
441 if (evlist == NULL)
442 return -ENOMEM;
443
444 err = parse_events(evlist, "cpu-clock");
445 if (err)
446 goto out;
447 err = parse_events(evlist, "task-clock");
448 if (err)
449 goto out;
450
451 /* default sort order (comm,dso,sym) will be used */
452 if (setup_sorting() < 0)
453 goto out;
454
455 machines__init(&machines);
456
457 /* setup threads/dso/map/symbols also */
458 machine = setup_fake_machine(&machines);
459 if (!machine)
460 goto out;
461
462 if (verbose > 1)
463 machine__fprintf(machine, stderr);
464
465 /* process sample events */
466 err = add_hist_entries(evlist, machine);
467 if (err < 0)
468 goto out;
469
470 list_for_each_entry(evsel, &evlist->entries, node) {
471 hists__collapse_resort(&evsel->hists);
472
473 if (verbose > 2)
474 print_hists(&evsel->hists);
475 }
476
477 first = perf_evlist__first(evlist);
478 evsel = perf_evlist__last(evlist);
479
480 /* match common entries */
481 hists__match(&first->hists, &evsel->hists);
482 err = validate_match(&first->hists, &evsel->hists);
483 if (err)
484 goto out;
485
486 /* link common and/or dummy entries */
487 hists__link(&first->hists, &evsel->hists);
488 err = validate_link(&first->hists, &evsel->hists);
489 if (err)
490 goto out;
491
492 err = 0;
493
494out:
495 /* tear down everything */
496 perf_evlist__delete(evlist);
497 machines__exit(&machines);
498
499 return err;
500}
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
new file mode 100644
index 000000000000..cdd50755af51
--- /dev/null
+++ b/tools/perf/tests/mmap-basic.c
@@ -0,0 +1,148 @@
1#include "evlist.h"
2#include "evsel.h"
3#include "thread_map.h"
4#include "cpumap.h"
5#include "tests.h"
6
7/*
8 * This test will generate random numbers of calls to some getpid syscalls,
9 * then establish an mmap for a group of events that are created to monitor
10 * the syscalls.
11 *
12 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
13 * sample.id field to map back to its respective perf_evsel instance.
14 *
15 * Then it checks if the number of syscalls reported as perf events by
16 * the kernel corresponds to the number of syscalls made.
17 */
18int test__basic_mmap(void)
19{
20 int err = -1;
21 union perf_event *event;
22 struct thread_map *threads;
23 struct cpu_map *cpus;
24 struct perf_evlist *evlist;
25 cpu_set_t cpu_set;
26 const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
27 "getpgid", };
28 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
29 (void*)getpgid };
30#define nsyscalls ARRAY_SIZE(syscall_names)
31 unsigned int nr_events[nsyscalls],
32 expected_nr_events[nsyscalls], i, j;
33 struct perf_evsel *evsels[nsyscalls], *evsel;
34
35 threads = thread_map__new(-1, getpid(), UINT_MAX);
36 if (threads == NULL) {
37 pr_debug("thread_map__new\n");
38 return -1;
39 }
40
41 cpus = cpu_map__new(NULL);
42 if (cpus == NULL) {
43 pr_debug("cpu_map__new\n");
44 goto out_free_threads;
45 }
46
47 CPU_ZERO(&cpu_set);
48 CPU_SET(cpus->map[0], &cpu_set);
49 sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
50 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
51 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
52 cpus->map[0], strerror(errno));
53 goto out_free_cpus;
54 }
55
56 evlist = perf_evlist__new(cpus, threads);
57 if (evlist == NULL) {
58 pr_debug("perf_evlist__new\n");
59 goto out_free_cpus;
60 }
61
62 for (i = 0; i < nsyscalls; ++i) {
63 char name[64];
64
65 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
66 evsels[i] = perf_evsel__newtp("syscalls", name, i);
67 if (evsels[i] == NULL) {
68 pr_debug("perf_evsel__new\n");
69 goto out_free_evlist;
70 }
71
72 evsels[i]->attr.wakeup_events = 1;
73 perf_evsel__set_sample_id(evsels[i]);
74
75 perf_evlist__add(evlist, evsels[i]);
76
77 if (perf_evsel__open(evsels[i], cpus, threads) < 0) {
78 pr_debug("failed to open counter: %s, "
79 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
80 strerror(errno));
81 goto out_close_fd;
82 }
83
84 nr_events[i] = 0;
85 expected_nr_events[i] = 1 + rand() % 127;
86 }
87
88 if (perf_evlist__mmap(evlist, 128, true) < 0) {
89 pr_debug("failed to mmap events: %d (%s)\n", errno,
90 strerror(errno));
91 goto out_close_fd;
92 }
93
94 for (i = 0; i < nsyscalls; ++i)
95 for (j = 0; j < expected_nr_events[i]; ++j) {
96 int foo = syscalls[i]();
97 ++foo;
98 }
99
100 while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
101 struct perf_sample sample;
102
103 if (event->header.type != PERF_RECORD_SAMPLE) {
104 pr_debug("unexpected %s event\n",
105 perf_event__name(event->header.type));
106 goto out_munmap;
107 }
108
109 err = perf_evlist__parse_sample(evlist, event, &sample);
110 if (err) {
111 pr_err("Can't parse sample, err = %d\n", err);
112 goto out_munmap;
113 }
114
115 err = -1;
116 evsel = perf_evlist__id2evsel(evlist, sample.id);
117 if (evsel == NULL) {
118 pr_debug("event with id %" PRIu64
119 " doesn't map to an evsel\n", sample.id);
120 goto out_munmap;
121 }
122 nr_events[evsel->idx]++;
123 }
124
125 err = 0;
126 list_for_each_entry(evsel, &evlist->entries, node) {
127 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
128 pr_debug("expected %d %s events, got %d\n",
129 expected_nr_events[evsel->idx],
130 perf_evsel__name(evsel), nr_events[evsel->idx]);
131 err = -1;
132 goto out_munmap;
133 }
134 }
135
136out_munmap:
137 perf_evlist__munmap(evlist);
138out_close_fd:
139 for (i = 0; i < nsyscalls; ++i)
140 perf_evsel__close_fd(evsels[i], 1, threads->nr);
141out_free_evlist:
142 perf_evlist__delete(evlist);
143out_free_cpus:
144 cpu_map__delete(cpus);
145out_free_threads:
146 thread_map__delete(threads);
147 return err;
148}
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c
new file mode 100644
index 000000000000..b0657a9ccda6
--- /dev/null
+++ b/tools/perf/tests/open-syscall-all-cpus.c
@@ -0,0 +1,109 @@
1#include "evsel.h"
2#include "tests.h"
3#include "thread_map.h"
4#include "cpumap.h"
5#include "debug.h"
6
7int test__open_syscall_event_on_all_cpus(void)
8{
9 int err = -1, fd, cpu;
10 struct cpu_map *cpus;
11 struct perf_evsel *evsel;
12 unsigned int nr_open_calls = 111, i;
13 cpu_set_t cpu_set;
14 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
15
16 if (threads == NULL) {
17 pr_debug("thread_map__new\n");
18 return -1;
19 }
20
21 cpus = cpu_map__new(NULL);
22 if (cpus == NULL) {
23 pr_debug("cpu_map__new\n");
24 goto out_thread_map_delete;
25 }
26
27 CPU_ZERO(&cpu_set);
28
29 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
30 if (evsel == NULL) {
31 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
32 goto out_thread_map_delete;
33 }
34
35 if (perf_evsel__open(evsel, cpus, threads) < 0) {
36 pr_debug("failed to open counter: %s, "
37 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
38 strerror(errno));
39 goto out_evsel_delete;
40 }
41
42 for (cpu = 0; cpu < cpus->nr; ++cpu) {
43 unsigned int ncalls = nr_open_calls + cpu;
44 /*
45 * XXX eventually lift this restriction in a way that
46 * keeps perf building on older glibc installations
47 * without CPU_ALLOC. 1024 cpus in 2010 still seems
48 * a reasonable upper limit tho :-)
49 */
50 if (cpus->map[cpu] >= CPU_SETSIZE) {
51 pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
52 continue;
53 }
54
55 CPU_SET(cpus->map[cpu], &cpu_set);
56 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
57 pr_debug("sched_setaffinity() failed on CPU %d: %s ",
58 cpus->map[cpu],
59 strerror(errno));
60 goto out_close_fd;
61 }
62 for (i = 0; i < ncalls; ++i) {
63 fd = open("/etc/passwd", O_RDONLY);
64 close(fd);
65 }
66 CPU_CLR(cpus->map[cpu], &cpu_set);
67 }
68
69 /*
70 * Here we need to explicitely preallocate the counts, as if
71 * we use the auto allocation it will allocate just for 1 cpu,
72 * as we start by cpu 0.
73 */
74 if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
75 pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
76 goto out_close_fd;
77 }
78
79 err = 0;
80
81 for (cpu = 0; cpu < cpus->nr; ++cpu) {
82 unsigned int expected;
83
84 if (cpus->map[cpu] >= CPU_SETSIZE)
85 continue;
86
87 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
88 pr_debug("perf_evsel__read_on_cpu\n");
89 err = -1;
90 break;
91 }
92
93 expected = nr_open_calls + cpu;
94 if (evsel->counts->cpu[cpu].val != expected) {
95 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
96 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
97 err = -1;
98 }
99 }
100
101 perf_evsel__free_counts(evsel);
102out_close_fd:
103 perf_evsel__close_fd(evsel, 1, threads->nr);
104out_evsel_delete:
105 perf_evsel__delete(evsel);
106out_thread_map_delete:
107 thread_map__delete(threads);
108 return err;
109}
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c
new file mode 100644
index 000000000000..1c52fdc1164e
--- /dev/null
+++ b/tools/perf/tests/open-syscall-tp-fields.c
@@ -0,0 +1,117 @@
1#include "perf.h"
2#include "evlist.h"
3#include "evsel.h"
4#include "thread_map.h"
5#include "tests.h"
6
7int test__syscall_open_tp_fields(void)
8{
9 struct perf_record_opts opts = {
10 .target = {
11 .uid = UINT_MAX,
12 .uses_mmap = true,
13 },
14 .no_delay = true,
15 .freq = 1,
16 .mmap_pages = 256,
17 .raw_samples = true,
18 };
19 const char *filename = "/etc/passwd";
20 int flags = O_RDONLY | O_DIRECTORY;
21 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
22 struct perf_evsel *evsel;
23 int err = -1, i, nr_events = 0, nr_polls = 0;
24
25 if (evlist == NULL) {
26 pr_debug("%s: perf_evlist__new\n", __func__);
27 goto out;
28 }
29
30 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
31 if (evsel == NULL) {
32 pr_debug("%s: perf_evsel__newtp\n", __func__);
33 goto out_delete_evlist;
34 }
35
36 perf_evlist__add(evlist, evsel);
37
38 err = perf_evlist__create_maps(evlist, &opts.target);
39 if (err < 0) {
40 pr_debug("%s: perf_evlist__create_maps\n", __func__);
41 goto out_delete_evlist;
42 }
43
44 perf_evsel__config(evsel, &opts);
45
46 evlist->threads->map[0] = getpid();
47
48 err = perf_evlist__open(evlist);
49 if (err < 0) {
50 pr_debug("perf_evlist__open: %s\n", strerror(errno));
51 goto out_delete_evlist;
52 }
53
54 err = perf_evlist__mmap(evlist, UINT_MAX, false);
55 if (err < 0) {
56 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
57 goto out_delete_evlist;
58 }
59
60 perf_evlist__enable(evlist);
61
62 /*
63 * Generate the event:
64 */
65 open(filename, flags);
66
67 while (1) {
68 int before = nr_events;
69
70 for (i = 0; i < evlist->nr_mmaps; i++) {
71 union perf_event *event;
72
73 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
74 const u32 type = event->header.type;
75 int tp_flags;
76 struct perf_sample sample;
77
78 ++nr_events;
79
80 if (type != PERF_RECORD_SAMPLE)
81 continue;
82
83 err = perf_evsel__parse_sample(evsel, event, &sample);
84 if (err) {
85 pr_err("Can't parse sample, err = %d\n", err);
86 goto out_munmap;
87 }
88
89 tp_flags = perf_evsel__intval(evsel, &sample, "flags");
90
91 if (flags != tp_flags) {
92 pr_debug("%s: Expected flags=%#x, got %#x\n",
93 __func__, flags, tp_flags);
94 goto out_munmap;
95 }
96
97 goto out_ok;
98 }
99 }
100
101 if (nr_events == before)
102 poll(evlist->pollfd, evlist->nr_fds, 10);
103
104 if (++nr_polls > 5) {
105 pr_debug("%s: no events!\n", __func__);
106 goto out_munmap;
107 }
108 }
109out_ok:
110 err = 0;
111out_munmap:
112 perf_evlist__munmap(evlist);
113out_delete_evlist:
114 perf_evlist__delete(evlist);
115out:
116 return err;
117}
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c
new file mode 100644
index 000000000000..befc0671f95d
--- /dev/null
+++ b/tools/perf/tests/open-syscall.c
@@ -0,0 +1,55 @@
1#include "thread_map.h"
2#include "evsel.h"
3#include "debug.h"
4#include "tests.h"
5
6int test__open_syscall_event(void)
7{
8 int err = -1, fd;
9 struct perf_evsel *evsel;
10 unsigned int nr_open_calls = 111, i;
11 struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
12
13 if (threads == NULL) {
14 pr_debug("thread_map__new\n");
15 return -1;
16 }
17
18 evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
19 if (evsel == NULL) {
20 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
21 goto out_thread_map_delete;
22 }
23
24 if (perf_evsel__open_per_thread(evsel, threads) < 0) {
25 pr_debug("failed to open counter: %s, "
26 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
27 strerror(errno));
28 goto out_evsel_delete;
29 }
30
31 for (i = 0; i < nr_open_calls; ++i) {
32 fd = open("/etc/passwd", O_RDONLY);
33 close(fd);
34 }
35
36 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
37 pr_debug("perf_evsel__read_on_cpu\n");
38 goto out_close_fd;
39 }
40
41 if (evsel->counts->cpu[0].val != nr_open_calls) {
42 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
43 nr_open_calls, evsel->counts->cpu[0].val);
44 goto out_close_fd;
45 }
46
47 err = 0;
48out_close_fd:
49 perf_evsel__close_fd(evsel, 1, threads->nr);
50out_evsel_delete:
51 perf_evsel__delete(evsel);
52out_thread_map_delete:
53 thread_map__delete(threads);
54 return err;
55}
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/tests/parse-events.c
index 516ecd9ddd6e..c5636f36fe31 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/tests/parse-events.c
@@ -3,7 +3,9 @@
3#include "evsel.h" 3#include "evsel.h"
4#include "evlist.h" 4#include "evlist.h"
5#include "sysfs.h" 5#include "sysfs.h"
6#include "../../../include/linux/hw_breakpoint.h" 6#include "debugfs.h"
7#include "tests.h"
8#include <linux/hw_breakpoint.h>
7 9
8#define TEST_ASSERT_VAL(text, cond) \ 10#define TEST_ASSERT_VAL(text, cond) \
9do { \ 11do { \
@@ -21,6 +23,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist)
21 struct perf_evsel *evsel = perf_evlist__first(evlist); 23 struct perf_evsel *evsel = perf_evlist__first(evlist);
22 24
23 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries); 25 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
26 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
24 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type); 27 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
25 TEST_ASSERT_VAL("wrong sample_type", 28 TEST_ASSERT_VAL("wrong sample_type",
26 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type); 29 PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
@@ -33,6 +36,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
33 struct perf_evsel *evsel; 36 struct perf_evsel *evsel;
34 37
35 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); 38 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
39 TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups);
36 40
37 list_for_each_entry(evsel, &evlist->entries, node) { 41 list_for_each_entry(evsel, &evlist->entries, node) {
38 TEST_ASSERT_VAL("wrong type", 42 TEST_ASSERT_VAL("wrong type",
@@ -443,12 +447,29 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
443 return 0; 447 return 0;
444} 448}
445 449
450static int test__checkevent_pmu_events(struct perf_evlist *evlist)
451{
452 struct perf_evsel *evsel;
453
454 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
455 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
456 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
457 TEST_ASSERT_VAL("wrong exclude_user",
458 !evsel->attr.exclude_user);
459 TEST_ASSERT_VAL("wrong exclude_kernel",
460 evsel->attr.exclude_kernel);
461 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
462 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
463
464 return 0;
465}
466
446static int test__checkterms_simple(struct list_head *terms) 467static int test__checkterms_simple(struct list_head *terms)
447{ 468{
448 struct parse_events__term *term; 469 struct parse_events_term *term;
449 470
450 /* config=10 */ 471 /* config=10 */
451 term = list_entry(terms->next, struct parse_events__term, list); 472 term = list_entry(terms->next, struct parse_events_term, list);
452 TEST_ASSERT_VAL("wrong type term", 473 TEST_ASSERT_VAL("wrong type term",
453 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG); 474 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG);
454 TEST_ASSERT_VAL("wrong type val", 475 TEST_ASSERT_VAL("wrong type val",
@@ -457,7 +478,7 @@ static int test__checkterms_simple(struct list_head *terms)
457 TEST_ASSERT_VAL("wrong config", !term->config); 478 TEST_ASSERT_VAL("wrong config", !term->config);
458 479
459 /* config1 */ 480 /* config1 */
460 term = list_entry(term->list.next, struct parse_events__term, list); 481 term = list_entry(term->list.next, struct parse_events_term, list);
461 TEST_ASSERT_VAL("wrong type term", 482 TEST_ASSERT_VAL("wrong type term",
462 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1); 483 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG1);
463 TEST_ASSERT_VAL("wrong type val", 484 TEST_ASSERT_VAL("wrong type val",
@@ -466,7 +487,7 @@ static int test__checkterms_simple(struct list_head *terms)
466 TEST_ASSERT_VAL("wrong config", !term->config); 487 TEST_ASSERT_VAL("wrong config", !term->config);
467 488
468 /* config2=3 */ 489 /* config2=3 */
469 term = list_entry(term->list.next, struct parse_events__term, list); 490 term = list_entry(term->list.next, struct parse_events_term, list);
470 TEST_ASSERT_VAL("wrong type term", 491 TEST_ASSERT_VAL("wrong type term",
471 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2); 492 term->type_term == PARSE_EVENTS__TERM_TYPE_CONFIG2);
472 TEST_ASSERT_VAL("wrong type val", 493 TEST_ASSERT_VAL("wrong type val",
@@ -475,7 +496,7 @@ static int test__checkterms_simple(struct list_head *terms)
475 TEST_ASSERT_VAL("wrong config", !term->config); 496 TEST_ASSERT_VAL("wrong config", !term->config);
476 497
477 /* umask=1*/ 498 /* umask=1*/
478 term = list_entry(term->list.next, struct parse_events__term, list); 499 term = list_entry(term->list.next, struct parse_events_term, list);
479 TEST_ASSERT_VAL("wrong type term", 500 TEST_ASSERT_VAL("wrong type term",
480 term->type_term == PARSE_EVENTS__TERM_TYPE_USER); 501 term->type_term == PARSE_EVENTS__TERM_TYPE_USER);
481 TEST_ASSERT_VAL("wrong type val", 502 TEST_ASSERT_VAL("wrong type val",
@@ -491,6 +512,7 @@ static int test__group1(struct perf_evlist *evlist)
491 struct perf_evsel *evsel, *leader; 512 struct perf_evsel *evsel, *leader;
492 513
493 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); 514 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
515 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
494 516
495 /* instructions:k */ 517 /* instructions:k */
496 evsel = leader = perf_evlist__first(evlist); 518 evsel = leader = perf_evlist__first(evlist);
@@ -503,7 +525,9 @@ static int test__group1(struct perf_evlist *evlist)
503 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 525 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
504 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 526 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
505 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 527 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
506 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 528 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
529 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
530 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
507 531
508 /* cycles:upp */ 532 /* cycles:upp */
509 evsel = perf_evsel__next(evsel); 533 evsel = perf_evsel__next(evsel);
@@ -518,6 +542,7 @@ static int test__group1(struct perf_evlist *evlist)
518 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 542 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
519 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 543 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
520 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 544 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
545 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
521 546
522 return 0; 547 return 0;
523} 548}
@@ -527,6 +552,7 @@ static int test__group2(struct perf_evlist *evlist)
527 struct perf_evsel *evsel, *leader; 552 struct perf_evsel *evsel, *leader;
528 553
529 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); 554 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
555 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
530 556
531 /* faults + :ku modifier */ 557 /* faults + :ku modifier */
532 evsel = leader = perf_evlist__first(evlist); 558 evsel = leader = perf_evlist__first(evlist);
@@ -539,7 +565,9 @@ static int test__group2(struct perf_evlist *evlist)
539 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 565 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
540 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 566 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
541 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 567 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
542 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 568 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
569 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
570 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
543 571
544 /* cache-references + :u modifier */ 572 /* cache-references + :u modifier */
545 evsel = perf_evsel__next(evsel); 573 evsel = perf_evsel__next(evsel);
@@ -549,10 +577,11 @@ static int test__group2(struct perf_evlist *evlist)
549 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); 577 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
550 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); 578 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
551 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); 579 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
552 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 580 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
553 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 581 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
554 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 582 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
555 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 583 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
584 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
556 585
557 /* cycles:k */ 586 /* cycles:k */
558 evsel = perf_evsel__next(evsel); 587 evsel = perf_evsel__next(evsel);
@@ -565,7 +594,7 @@ static int test__group2(struct perf_evlist *evlist)
565 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 594 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
566 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 595 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
567 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 596 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
568 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 597 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
569 598
570 return 0; 599 return 0;
571} 600}
@@ -575,6 +604,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
575 struct perf_evsel *evsel, *leader; 604 struct perf_evsel *evsel, *leader;
576 605
577 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); 606 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
607 TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups);
578 608
579 /* group1 syscalls:sys_enter_open:H */ 609 /* group1 syscalls:sys_enter_open:H */
580 evsel = leader = perf_evlist__first(evlist); 610 evsel = leader = perf_evlist__first(evlist);
@@ -588,9 +618,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
588 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); 618 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
589 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 619 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
590 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 620 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
591 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 621 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
592 TEST_ASSERT_VAL("wrong group name", 622 TEST_ASSERT_VAL("wrong group name",
593 !strcmp(leader->group_name, "group1")); 623 !strcmp(leader->group_name, "group1"));
624 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
625 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
594 626
595 /* group1 cycles:kppp */ 627 /* group1 cycles:kppp */
596 evsel = perf_evsel__next(evsel); 628 evsel = perf_evsel__next(evsel);
@@ -606,6 +638,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
606 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3); 638 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 3);
607 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 639 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
608 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 640 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
641 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
609 642
610 /* group2 cycles + G modifier */ 643 /* group2 cycles + G modifier */
611 evsel = leader = perf_evsel__next(evsel); 644 evsel = leader = perf_evsel__next(evsel);
@@ -618,9 +651,11 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
618 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 651 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
619 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 652 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
620 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 653 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
621 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 654 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
622 TEST_ASSERT_VAL("wrong group name", 655 TEST_ASSERT_VAL("wrong group name",
623 !strcmp(leader->group_name, "group2")); 656 !strcmp(leader->group_name, "group2"));
657 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
658 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
624 659
625 /* group2 1:3 + G modifier */ 660 /* group2 1:3 + G modifier */
626 evsel = perf_evsel__next(evsel); 661 evsel = perf_evsel__next(evsel);
@@ -633,6 +668,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
633 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 668 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
634 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 669 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
635 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 670 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
671 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
636 672
637 /* instructions:u */ 673 /* instructions:u */
638 evsel = perf_evsel__next(evsel); 674 evsel = perf_evsel__next(evsel);
@@ -645,7 +681,7 @@ static int test__group3(struct perf_evlist *evlist __maybe_unused)
645 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); 681 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
646 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 682 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
647 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 683 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
648 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 684 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
649 685
650 return 0; 686 return 0;
651} 687}
@@ -655,6 +691,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
655 struct perf_evsel *evsel, *leader; 691 struct perf_evsel *evsel, *leader;
656 692
657 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); 693 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
694 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
658 695
659 /* cycles:u + p */ 696 /* cycles:u + p */
660 evsel = leader = perf_evlist__first(evlist); 697 evsel = leader = perf_evlist__first(evlist);
@@ -669,7 +706,9 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
669 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 706 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
670 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1); 707 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 1);
671 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 708 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
672 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 709 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
710 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
711 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
673 712
674 /* instructions:kp + p */ 713 /* instructions:kp + p */
675 evsel = perf_evsel__next(evsel); 714 evsel = perf_evsel__next(evsel);
@@ -684,6 +723,7 @@ static int test__group4(struct perf_evlist *evlist __maybe_unused)
684 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 723 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
685 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2); 724 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip == 2);
686 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 725 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
726 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
687 727
688 return 0; 728 return 0;
689} 729}
@@ -693,6 +733,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
693 struct perf_evsel *evsel, *leader; 733 struct perf_evsel *evsel, *leader;
694 734
695 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries); 735 TEST_ASSERT_VAL("wrong number of entries", 5 == evlist->nr_entries);
736 TEST_ASSERT_VAL("wrong number of groups", 2 == evlist->nr_groups);
696 737
697 /* cycles + G */ 738 /* cycles + G */
698 evsel = leader = perf_evlist__first(evlist); 739 evsel = leader = perf_evlist__first(evlist);
@@ -706,7 +747,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
706 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 747 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
707 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 748 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
708 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 749 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
709 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 750 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
751 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
752 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
710 753
711 /* instructions + G */ 754 /* instructions + G */
712 evsel = perf_evsel__next(evsel); 755 evsel = perf_evsel__next(evsel);
@@ -720,6 +763,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
720 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 763 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
721 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 764 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
722 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 765 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
766 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
723 767
724 /* cycles:G */ 768 /* cycles:G */
725 evsel = leader = perf_evsel__next(evsel); 769 evsel = leader = perf_evsel__next(evsel);
@@ -733,7 +777,9 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
733 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 777 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
734 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 778 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
735 TEST_ASSERT_VAL("wrong group name", !evsel->group_name); 779 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
736 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 780 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
781 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
782 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
737 783
738 /* instructions:G */ 784 /* instructions:G */
739 evsel = perf_evsel__next(evsel); 785 evsel = perf_evsel__next(evsel);
@@ -747,6 +793,7 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
747 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); 793 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
748 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 794 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
749 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); 795 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
796 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
750 797
751 /* cycles */ 798 /* cycles */
752 evsel = perf_evsel__next(evsel); 799 evsel = perf_evsel__next(evsel);
@@ -759,18 +806,235 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
759 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); 806 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
760 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); 807 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
761 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); 808 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
762 TEST_ASSERT_VAL("wrong leader", evsel->leader == NULL); 809 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
810
811 return 0;
812}
813
814static int test__group_gh1(struct perf_evlist *evlist)
815{
816 struct perf_evsel *evsel, *leader;
817
818 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
819 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
820
821 /* cycles + :H group modifier */
822 evsel = leader = perf_evlist__first(evlist);
823 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
824 TEST_ASSERT_VAL("wrong config",
825 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
826 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
827 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
828 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
829 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
830 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
831 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
832 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
833 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
834 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
835 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
836
837 /* cache-misses:G + :H group modifier */
838 evsel = perf_evsel__next(evsel);
839 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
840 TEST_ASSERT_VAL("wrong config",
841 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
842 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
843 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
844 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
845 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
846 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
847 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
848 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
849 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
850
851 return 0;
852}
853
854static int test__group_gh2(struct perf_evlist *evlist)
855{
856 struct perf_evsel *evsel, *leader;
857
858 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
859 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
860
861 /* cycles + :G group modifier */
862 evsel = leader = perf_evlist__first(evlist);
863 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
864 TEST_ASSERT_VAL("wrong config",
865 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
866 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
867 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
868 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
869 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
870 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
871 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
872 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
873 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
874 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
875 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
876
877 /* cache-misses:H + :G group modifier */
878 evsel = perf_evsel__next(evsel);
879 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
880 TEST_ASSERT_VAL("wrong config",
881 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
882 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
883 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
884 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
885 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
886 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
887 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
888 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
889 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
763 890
764 return 0; 891 return 0;
765} 892}
766 893
767struct test__event_st { 894static int test__group_gh3(struct perf_evlist *evlist)
895{
896 struct perf_evsel *evsel, *leader;
897
898 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
899 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
900
901 /* cycles:G + :u group modifier */
902 evsel = leader = perf_evlist__first(evlist);
903 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
904 TEST_ASSERT_VAL("wrong config",
905 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
906 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
907 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
908 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
909 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
910 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
911 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
912 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
913 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
914 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
915 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
916
917 /* cache-misses:H + :u group modifier */
918 evsel = perf_evsel__next(evsel);
919 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
920 TEST_ASSERT_VAL("wrong config",
921 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
922 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
923 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
924 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
925 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
926 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
927 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
928 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
929 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
930
931 return 0;
932}
933
934static int test__group_gh4(struct perf_evlist *evlist)
935{
936 struct perf_evsel *evsel, *leader;
937
938 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
939 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
940
941 /* cycles:G + :uG group modifier */
942 evsel = leader = perf_evlist__first(evlist);
943 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
944 TEST_ASSERT_VAL("wrong config",
945 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
946 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
947 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
948 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
949 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
950 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
951 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
952 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
953 TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
954 TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
955 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
956
957 /* cache-misses:H + :uG group modifier */
958 evsel = perf_evsel__next(evsel);
959 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
960 TEST_ASSERT_VAL("wrong config",
961 PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
962 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
963 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
964 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
965 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
966 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
967 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
968 TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
969 TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
970
971 return 0;
972}
973
974static int count_tracepoints(void)
975{
976 char events_path[PATH_MAX];
977 struct dirent *events_ent;
978 DIR *events_dir;
979 int cnt = 0;
980
981 scnprintf(events_path, PATH_MAX, "%s/tracing/events",
982 debugfs_find_mountpoint());
983
984 events_dir = opendir(events_path);
985
986 TEST_ASSERT_VAL("Can't open events dir", events_dir);
987
988 while ((events_ent = readdir(events_dir))) {
989 char sys_path[PATH_MAX];
990 struct dirent *sys_ent;
991 DIR *sys_dir;
992
993 if (!strcmp(events_ent->d_name, ".")
994 || !strcmp(events_ent->d_name, "..")
995 || !strcmp(events_ent->d_name, "enable")
996 || !strcmp(events_ent->d_name, "header_event")
997 || !strcmp(events_ent->d_name, "header_page"))
998 continue;
999
1000 scnprintf(sys_path, PATH_MAX, "%s/%s",
1001 events_path, events_ent->d_name);
1002
1003 sys_dir = opendir(sys_path);
1004 TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
1005
1006 while ((sys_ent = readdir(sys_dir))) {
1007 if (!strcmp(sys_ent->d_name, ".")
1008 || !strcmp(sys_ent->d_name, "..")
1009 || !strcmp(sys_ent->d_name, "enable")
1010 || !strcmp(sys_ent->d_name, "filter"))
1011 continue;
1012
1013 cnt++;
1014 }
1015
1016 closedir(sys_dir);
1017 }
1018
1019 closedir(events_dir);
1020 return cnt;
1021}
1022
1023static int test__all_tracepoints(struct perf_evlist *evlist)
1024{
1025 TEST_ASSERT_VAL("wrong events count",
1026 count_tracepoints() == evlist->nr_entries);
1027
1028 return test__checkevent_tracepoint_multi(evlist);
1029}
1030
1031struct evlist_test {
768 const char *name; 1032 const char *name;
769 __u32 type; 1033 __u32 type;
770 int (*check)(struct perf_evlist *evlist); 1034 int (*check)(struct perf_evlist *evlist);
771}; 1035};
772 1036
773static struct test__event_st test__events[] = { 1037static struct evlist_test test__events[] = {
774 [0] = { 1038 [0] = {
775 .name = "syscalls:sys_enter_open", 1039 .name = "syscalls:sys_enter_open",
776 .check = test__checkevent_tracepoint, 1040 .check = test__checkevent_tracepoint,
@@ -903,9 +1167,29 @@ static struct test__event_st test__events[] = {
903 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles", 1167 .name = "{cycles,instructions}:G,{cycles:G,instructions:G},cycles",
904 .check = test__group5, 1168 .check = test__group5,
905 }, 1169 },
1170 [33] = {
1171 .name = "*:*",
1172 .check = test__all_tracepoints,
1173 },
1174 [34] = {
1175 .name = "{cycles,cache-misses:G}:H",
1176 .check = test__group_gh1,
1177 },
1178 [35] = {
1179 .name = "{cycles,cache-misses:H}:G",
1180 .check = test__group_gh2,
1181 },
1182 [36] = {
1183 .name = "{cycles:G,cache-misses:H}:u",
1184 .check = test__group_gh3,
1185 },
1186 [37] = {
1187 .name = "{cycles:G,cache-misses:H}:uG",
1188 .check = test__group_gh4,
1189 },
906}; 1190};
907 1191
908static struct test__event_st test__events_pmu[] = { 1192static struct evlist_test test__events_pmu[] = {
909 [0] = { 1193 [0] = {
910 .name = "cpu/config=10,config1,config2=3,period=1000/u", 1194 .name = "cpu/config=10,config1,config2=3,period=1000/u",
911 .check = test__checkevent_pmu, 1195 .check = test__checkevent_pmu,
@@ -916,20 +1200,20 @@ static struct test__event_st test__events_pmu[] = {
916 }, 1200 },
917}; 1201};
918 1202
919struct test__term { 1203struct terms_test {
920 const char *str; 1204 const char *str;
921 __u32 type; 1205 __u32 type;
922 int (*check)(struct list_head *terms); 1206 int (*check)(struct list_head *terms);
923}; 1207};
924 1208
925static struct test__term test__terms[] = { 1209static struct terms_test test__terms[] = {
926 [0] = { 1210 [0] = {
927 .str = "config=10,config1,config2=3,umask=1", 1211 .str = "config=10,config1,config2=3,umask=1",
928 .check = test__checkterms_simple, 1212 .check = test__checkterms_simple,
929 }, 1213 },
930}; 1214};
931 1215
932static int test_event(struct test__event_st *e) 1216static int test_event(struct evlist_test *e)
933{ 1217{
934 struct perf_evlist *evlist; 1218 struct perf_evlist *evlist;
935 int ret; 1219 int ret;
@@ -938,7 +1222,7 @@ static int test_event(struct test__event_st *e)
938 if (evlist == NULL) 1222 if (evlist == NULL)
939 return -ENOMEM; 1223 return -ENOMEM;
940 1224
941 ret = parse_events(evlist, e->name, 0); 1225 ret = parse_events(evlist, e->name);
942 if (ret) { 1226 if (ret) {
943 pr_debug("failed to parse event '%s', err %d\n", 1227 pr_debug("failed to parse event '%s', err %d\n",
944 e->name, ret); 1228 e->name, ret);
@@ -951,13 +1235,13 @@ static int test_event(struct test__event_st *e)
951 return ret; 1235 return ret;
952} 1236}
953 1237
954static int test_events(struct test__event_st *events, unsigned cnt) 1238static int test_events(struct evlist_test *events, unsigned cnt)
955{ 1239{
956 int ret1, ret2 = 0; 1240 int ret1, ret2 = 0;
957 unsigned i; 1241 unsigned i;
958 1242
959 for (i = 0; i < cnt; i++) { 1243 for (i = 0; i < cnt; i++) {
960 struct test__event_st *e = &events[i]; 1244 struct evlist_test *e = &events[i];
961 1245
962 pr_debug("running test %d '%s'\n", i, e->name); 1246 pr_debug("running test %d '%s'\n", i, e->name);
963 ret1 = test_event(e); 1247 ret1 = test_event(e);
@@ -968,7 +1252,7 @@ static int test_events(struct test__event_st *events, unsigned cnt)
968 return ret2; 1252 return ret2;
969} 1253}
970 1254
971static int test_term(struct test__term *t) 1255static int test_term(struct terms_test *t)
972{ 1256{
973 struct list_head *terms; 1257 struct list_head *terms;
974 int ret; 1258 int ret;
@@ -992,13 +1276,13 @@ static int test_term(struct test__term *t)
992 return ret; 1276 return ret;
993} 1277}
994 1278
995static int test_terms(struct test__term *terms, unsigned cnt) 1279static int test_terms(struct terms_test *terms, unsigned cnt)
996{ 1280{
997 int ret = 0; 1281 int ret = 0;
998 unsigned i; 1282 unsigned i;
999 1283
1000 for (i = 0; i < cnt; i++) { 1284 for (i = 0; i < cnt; i++) {
1001 struct test__term *t = &terms[i]; 1285 struct terms_test *t = &terms[i];
1002 1286
1003 pr_debug("running test %d '%s'\n", i, t->str); 1287 pr_debug("running test %d '%s'\n", i, t->str);
1004 ret = test_term(t); 1288 ret = test_term(t);
@@ -1024,7 +1308,52 @@ static int test_pmu(void)
1024 return !ret; 1308 return !ret;
1025} 1309}
1026 1310
1027int parse_events__test(void) 1311static int test_pmu_events(void)
1312{
1313 struct stat st;
1314 char path[PATH_MAX];
1315 struct dirent *ent;
1316 DIR *dir;
1317 int ret;
1318
1319 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/events/",
1320 sysfs_find_mountpoint());
1321
1322 ret = stat(path, &st);
1323 if (ret) {
1324 pr_debug("ommiting PMU cpu events tests\n");
1325 return 0;
1326 }
1327
1328 dir = opendir(path);
1329 if (!dir) {
1330 pr_debug("can't open pmu event dir");
1331 return -1;
1332 }
1333
1334 while (!ret && (ent = readdir(dir))) {
1335#define MAX_NAME 100
1336 struct evlist_test e;
1337 char name[MAX_NAME];
1338
1339 if (!strcmp(ent->d_name, ".") ||
1340 !strcmp(ent->d_name, ".."))
1341 continue;
1342
1343 snprintf(name, MAX_NAME, "cpu/event=%s/u", ent->d_name);
1344
1345 e.name = name;
1346 e.check = test__checkevent_pmu_events;
1347
1348 ret = test_event(&e);
1349#undef MAX_NAME
1350 }
1351
1352 closedir(dir);
1353 return ret;
1354}
1355
1356int test__parse_events(void)
1028{ 1357{
1029 int ret1, ret2 = 0; 1358 int ret1, ret2 = 0;
1030 1359
@@ -1040,6 +1369,12 @@ do { \
1040 if (test_pmu()) 1369 if (test_pmu())
1041 TEST_EVENTS(test__events_pmu); 1370 TEST_EVENTS(test__events_pmu);
1042 1371
1372 if (test_pmu()) {
1373 int ret = test_pmu_events();
1374 if (ret)
1375 return ret;
1376 }
1377
1043 ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms)); 1378 ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms));
1044 if (!ret2) 1379 if (!ret2)
1045 ret2 = ret1; 1380 ret2 = ret1;
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
new file mode 100644
index 000000000000..1e8e5128d0da
--- /dev/null
+++ b/tools/perf/tests/perf-record.c
@@ -0,0 +1,314 @@
1#include <sched.h>
2#include "evlist.h"
3#include "evsel.h"
4#include "perf.h"
5#include "debug.h"
6#include "tests.h"
7
8static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp)
9{
10 int i, cpu = -1, nrcpus = 1024;
11realloc:
12 CPU_ZERO(maskp);
13
14 if (sched_getaffinity(pid, sizeof(*maskp), maskp) == -1) {
15 if (errno == EINVAL && nrcpus < (1024 << 8)) {
16 nrcpus = nrcpus << 2;
17 goto realloc;
18 }
19 perror("sched_getaffinity");
20 return -1;
21 }
22
23 for (i = 0; i < nrcpus; i++) {
24 if (CPU_ISSET(i, maskp)) {
25 if (cpu == -1)
26 cpu = i;
27 else
28 CPU_CLR(i, maskp);
29 }
30 }
31
32 return cpu;
33}
34
35int test__PERF_RECORD(void)
36{
37 struct perf_record_opts opts = {
38 .target = {
39 .uid = UINT_MAX,
40 .uses_mmap = true,
41 },
42 .no_delay = true,
43 .freq = 10,
44 .mmap_pages = 256,
45 };
46 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask);
48 struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
49 struct perf_evsel *evsel;
50 struct perf_sample sample;
51 const char *cmd = "sleep";
52 const char *argv[] = { cmd, "1", NULL, };
53 char *bname;
54 u64 prev_time = 0;
55 bool found_cmd_mmap = false,
56 found_libc_mmap = false,
57 found_vdso_mmap = false,
58 found_ld_mmap = false;
59 int err = -1, errs = 0, i, wakeups = 0;
60 u32 cpu;
61 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
62
63 if (evlist == NULL || argv == NULL) {
64 pr_debug("Not enough memory to create evlist\n");
65 goto out;
66 }
67
68 /*
69 * We need at least one evsel in the evlist, use the default
70 * one: "cycles".
71 */
72 err = perf_evlist__add_default(evlist);
73 if (err < 0) {
74 pr_debug("Not enough memory to create evsel\n");
75 goto out_delete_evlist;
76 }
77
78 /*
79 * Create maps of threads and cpus to monitor. In this case
80 * we start with all threads and cpus (-1, -1) but then in
81 * perf_evlist__prepare_workload we'll fill in the only thread
82 * we're monitoring, the one forked there.
83 */
84 err = perf_evlist__create_maps(evlist, &opts.target);
85 if (err < 0) {
86 pr_debug("Not enough memory to create thread/cpu maps\n");
87 goto out_delete_evlist;
88 }
89
90 /*
91 * Prepare the workload in argv[] to run, it'll fork it, and then wait
92 * for perf_evlist__start_workload() to exec it. This is done this way
93 * so that we have time to open the evlist (calling sys_perf_event_open
94 * on all the fds) and then mmap them.
95 */
96 err = perf_evlist__prepare_workload(evlist, &opts, argv);
97 if (err < 0) {
98 pr_debug("Couldn't run the workload!\n");
99 goto out_delete_maps;
100 }
101
102 /*
103 * Config the evsels, setting attr->comm on the first one, etc.
104 */
105 evsel = perf_evlist__first(evlist);
106 perf_evsel__set_sample_bit(evsel, CPU);
107 perf_evsel__set_sample_bit(evsel, TID);
108 perf_evsel__set_sample_bit(evsel, TIME);
109 perf_evlist__config(evlist, &opts);
110
111 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
112 if (err < 0) {
113 pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno));
114 goto out_delete_maps;
115 }
116
117 cpu = err;
118
119 /*
120 * So that we can check perf_sample.cpu on all the samples.
121 */
122 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
123 pr_debug("sched_setaffinity: %s\n", strerror(errno));
124 goto out_delete_maps;
125 }
126
127 /*
128 * Call sys_perf_event_open on all the fds on all the evsels,
129 * grouping them if asked to.
130 */
131 err = perf_evlist__open(evlist);
132 if (err < 0) {
133 pr_debug("perf_evlist__open: %s\n", strerror(errno));
134 goto out_delete_maps;
135 }
136
137 /*
138 * mmap the first fd on a given CPU and ask for events for the other
139 * fds in the same CPU to be injected in the same mmap ring buffer
140 * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)).
141 */
142 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
143 if (err < 0) {
144 pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
145 goto out_delete_maps;
146 }
147
148 /*
149 * Now that all is properly set up, enable the events, they will
150 * count just on workload.pid, which will start...
151 */
152 perf_evlist__enable(evlist);
153
154 /*
155 * Now!
156 */
157 perf_evlist__start_workload(evlist);
158
159 while (1) {
160 int before = total_events;
161
162 for (i = 0; i < evlist->nr_mmaps; i++) {
163 union perf_event *event;
164
165 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
166 const u32 type = event->header.type;
167 const char *name = perf_event__name(type);
168
169 ++total_events;
170 if (type < PERF_RECORD_MAX)
171 nr_events[type]++;
172
173 err = perf_evlist__parse_sample(evlist, event, &sample);
174 if (err < 0) {
175 if (verbose)
176 perf_event__fprintf(event, stderr);
177 pr_debug("Couldn't parse sample\n");
178 goto out_err;
179 }
180
181 if (verbose) {
182 pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
183 perf_event__fprintf(event, stderr);
184 }
185
186 if (prev_time > sample.time) {
187 pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
188 name, prev_time, sample.time);
189 ++errs;
190 }
191
192 prev_time = sample.time;
193
194 if (sample.cpu != cpu) {
195 pr_debug("%s with unexpected cpu, expected %d, got %d\n",
196 name, cpu, sample.cpu);
197 ++errs;
198 }
199
200 if ((pid_t)sample.pid != evlist->workload.pid) {
201 pr_debug("%s with unexpected pid, expected %d, got %d\n",
202 name, evlist->workload.pid, sample.pid);
203 ++errs;
204 }
205
206 if ((pid_t)sample.tid != evlist->workload.pid) {
207 pr_debug("%s with unexpected tid, expected %d, got %d\n",
208 name, evlist->workload.pid, sample.tid);
209 ++errs;
210 }
211
212 if ((type == PERF_RECORD_COMM ||
213 type == PERF_RECORD_MMAP ||
214 type == PERF_RECORD_FORK ||
215 type == PERF_RECORD_EXIT) &&
216 (pid_t)event->comm.pid != evlist->workload.pid) {
217 pr_debug("%s with unexpected pid/tid\n", name);
218 ++errs;
219 }
220
221 if ((type == PERF_RECORD_COMM ||
222 type == PERF_RECORD_MMAP) &&
223 event->comm.pid != event->comm.tid) {
224 pr_debug("%s with different pid/tid!\n", name);
225 ++errs;
226 }
227
228 switch (type) {
229 case PERF_RECORD_COMM:
230 if (strcmp(event->comm.comm, cmd)) {
231 pr_debug("%s with unexpected comm!\n", name);
232 ++errs;
233 }
234 break;
235 case PERF_RECORD_EXIT:
236 goto found_exit;
237 case PERF_RECORD_MMAP:
238 bname = strrchr(event->mmap.filename, '/');
239 if (bname != NULL) {
240 if (!found_cmd_mmap)
241 found_cmd_mmap = !strcmp(bname + 1, cmd);
242 if (!found_libc_mmap)
243 found_libc_mmap = !strncmp(bname + 1, "libc", 4);
244 if (!found_ld_mmap)
245 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
246 } else if (!found_vdso_mmap)
247 found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
248 break;
249
250 case PERF_RECORD_SAMPLE:
251 /* Just ignore samples for now */
252 break;
253 default:
254 pr_debug("Unexpected perf_event->header.type %d!\n",
255 type);
256 ++errs;
257 }
258 }
259 }
260
261 /*
262 * We don't use poll here because at least at 3.1 times the
263 * PERF_RECORD_{!SAMPLE} events don't honour
264 * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does.
265 */
266 if (total_events == before && false)
267 poll(evlist->pollfd, evlist->nr_fds, -1);
268
269 sleep(1);
270 if (++wakeups > 5) {
271 pr_debug("No PERF_RECORD_EXIT event!\n");
272 break;
273 }
274 }
275
276found_exit:
277 if (nr_events[PERF_RECORD_COMM] > 1) {
278 pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
279 ++errs;
280 }
281
282 if (nr_events[PERF_RECORD_COMM] == 0) {
283 pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
284 ++errs;
285 }
286
287 if (!found_cmd_mmap) {
288 pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
289 ++errs;
290 }
291
292 if (!found_libc_mmap) {
293 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
294 ++errs;
295 }
296
297 if (!found_ld_mmap) {
298 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
299 ++errs;
300 }
301
302 if (!found_vdso_mmap) {
303 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
304 ++errs;
305 }
306out_err:
307 perf_evlist__munmap(evlist);
308out_delete_maps:
309 perf_evlist__delete_maps(evlist);
310out_delete_evlist:
311 perf_evlist__delete(evlist);
312out:
313 return (err < 0 || errs > 0) ? -1 : 0;
314}
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
new file mode 100644
index 000000000000..12b322fa3475
--- /dev/null
+++ b/tools/perf/tests/pmu.c
@@ -0,0 +1,173 @@
1#include "parse-events.h"
2#include "pmu.h"
3#include "util.h"
4#include "tests.h"
5
6/* Simulated format definitions. */
7static struct test_format {
8 const char *name;
9 const char *value;
10} test_formats[] = {
11 { "krava01", "config:0-1,62-63\n", },
12 { "krava02", "config:10-17\n", },
13 { "krava03", "config:5\n", },
14 { "krava11", "config1:0,2,4,6,8,20-28\n", },
15 { "krava12", "config1:63\n", },
16 { "krava13", "config1:45-47\n", },
17 { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
18 { "krava22", "config2:8,18,48,58\n", },
19 { "krava23", "config2:28-29,38\n", },
20};
21
22/* Simulated users input. */
23static struct parse_events_term test_terms[] = {
24 {
25 .config = (char *) "krava01",
26 .val.num = 15,
27 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
28 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
29 },
30 {
31 .config = (char *) "krava02",
32 .val.num = 170,
33 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
34 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
35 },
36 {
37 .config = (char *) "krava03",
38 .val.num = 1,
39 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
40 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
41 },
42 {
43 .config = (char *) "krava11",
44 .val.num = 27,
45 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
46 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
47 },
48 {
49 .config = (char *) "krava12",
50 .val.num = 1,
51 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
52 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
53 },
54 {
55 .config = (char *) "krava13",
56 .val.num = 2,
57 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
58 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
59 },
60 {
61 .config = (char *) "krava21",
62 .val.num = 119,
63 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
64 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
65 },
66 {
67 .config = (char *) "krava22",
68 .val.num = 11,
69 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
70 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
71 },
72 {
73 .config = (char *) "krava23",
74 .val.num = 2,
75 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
76 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
77 },
78};
79
80/*
81 * Prepare format directory data, exported by kernel
82 * at /sys/bus/event_source/devices/<dev>/format.
83 */
84static char *test_format_dir_get(void)
85{
86 static char dir[PATH_MAX];
87 unsigned int i;
88
89 snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
90 if (!mkdtemp(dir))
91 return NULL;
92
93 for (i = 0; i < ARRAY_SIZE(test_formats); i++) {
94 static char name[PATH_MAX];
95 struct test_format *format = &test_formats[i];
96 FILE *file;
97
98 snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
99
100 file = fopen(name, "w");
101 if (!file)
102 return NULL;
103
104 if (1 != fwrite(format->value, strlen(format->value), 1, file))
105 break;
106
107 fclose(file);
108 }
109
110 return dir;
111}
112
113/* Cleanup format directory. */
114static int test_format_dir_put(char *dir)
115{
116 char buf[PATH_MAX];
117 snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
118 if (system(buf))
119 return -1;
120
121 snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
122 return system(buf);
123}
124
125static struct list_head *test_terms_list(void)
126{
127 static LIST_HEAD(terms);
128 unsigned int i;
129
130 for (i = 0; i < ARRAY_SIZE(test_terms); i++)
131 list_add_tail(&test_terms[i].list, &terms);
132
133 return &terms;
134}
135
136int test__pmu(void)
137{
138 char *format = test_format_dir_get();
139 LIST_HEAD(formats);
140 struct list_head *terms = test_terms_list();
141 int ret;
142
143 if (!format)
144 return -EINVAL;
145
146 do {
147 struct perf_event_attr attr;
148
149 memset(&attr, 0, sizeof(attr));
150
151 ret = perf_pmu__format_parse(format, &formats);
152 if (ret)
153 break;
154
155 ret = perf_pmu__config_terms(&formats, &attr, terms);
156 if (ret)
157 break;
158
159 ret = -EINVAL;
160
161 if (attr.config != 0xc00000000002a823)
162 break;
163 if (attr.config1 != 0x8000400000000145)
164 break;
165 if (attr.config2 != 0x0400000020041d07)
166 break;
167
168 ret = 0;
169 } while (0);
170
171 test_format_dir_put(format);
172 return ret;
173}
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c
new file mode 100644
index 000000000000..7760277c6def
--- /dev/null
+++ b/tools/perf/tests/python-use.c
@@ -0,0 +1,23 @@
1/*
2 * Just test if we can load the python binding.
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include "tests.h"
8
9extern int verbose;
10
11int test__python_use(void)
12{
13 char *cmd;
14 int ret;
15
16 if (asprintf(&cmd, "echo \"import sys ; sys.path.append('%s'); import perf\" | %s %s",
17 PYTHONPATH, PYTHON, verbose ? "" : "2> /dev/null") < 0)
18 return -1;
19
20 ret = system(cmd) ? -1 : 0;
21 free(cmd);
22 return ret;
23}
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c
new file mode 100644
index 000000000000..ff94886aad99
--- /dev/null
+++ b/tools/perf/tests/rdpmc.c
@@ -0,0 +1,175 @@
1#include <unistd.h>
2#include <stdlib.h>
3#include <signal.h>
4#include <sys/mman.h>
5#include "types.h"
6#include "perf.h"
7#include "debug.h"
8#include "tests.h"
9
10#if defined(__x86_64__) || defined(__i386__)
11
12#define barrier() asm volatile("" ::: "memory")
13
14static u64 rdpmc(unsigned int counter)
15{
16 unsigned int low, high;
17
18 asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
19
20 return low | ((u64)high) << 32;
21}
22
23static u64 rdtsc(void)
24{
25 unsigned int low, high;
26
27 asm volatile("rdtsc" : "=a" (low), "=d" (high));
28
29 return low | ((u64)high) << 32;
30}
31
32static u64 mmap_read_self(void *addr)
33{
34 struct perf_event_mmap_page *pc = addr;
35 u32 seq, idx, time_mult = 0, time_shift = 0;
36 u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
37
38 do {
39 seq = pc->lock;
40 barrier();
41
42 enabled = pc->time_enabled;
43 running = pc->time_running;
44
45 if (enabled != running) {
46 cyc = rdtsc();
47 time_mult = pc->time_mult;
48 time_shift = pc->time_shift;
49 time_offset = pc->time_offset;
50 }
51
52 idx = pc->index;
53 count = pc->offset;
54 if (idx)
55 count += rdpmc(idx - 1);
56
57 barrier();
58 } while (pc->lock != seq);
59
60 if (enabled != running) {
61 u64 quot, rem;
62
63 quot = (cyc >> time_shift);
64 rem = cyc & ((1 << time_shift) - 1);
65 delta = time_offset + quot * time_mult +
66 ((rem * time_mult) >> time_shift);
67
68 enabled += delta;
69 if (idx)
70 running += delta;
71
72 quot = count / running;
73 rem = count % running;
74 count = quot * enabled + (rem * enabled) / running;
75 }
76
77 return count;
78}
79
80/*
81 * If the RDPMC instruction faults then signal this back to the test parent task:
82 */
83static void segfault_handler(int sig __maybe_unused,
84 siginfo_t *info __maybe_unused,
85 void *uc __maybe_unused)
86{
87 exit(-1);
88}
89
90static int __test__rdpmc(void)
91{
92 volatile int tmp = 0;
93 u64 i, loops = 1000;
94 int n;
95 int fd;
96 void *addr;
97 struct perf_event_attr attr = {
98 .type = PERF_TYPE_HARDWARE,
99 .config = PERF_COUNT_HW_INSTRUCTIONS,
100 .exclude_kernel = 1,
101 };
102 u64 delta_sum = 0;
103 struct sigaction sa;
104
105 sigfillset(&sa.sa_mask);
106 sa.sa_sigaction = segfault_handler;
107 sigaction(SIGSEGV, &sa, NULL);
108
109 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
110 if (fd < 0) {
111 pr_err("Error: sys_perf_event_open() syscall returned "
112 "with %d (%s)\n", fd, strerror(errno));
113 return -1;
114 }
115
116 addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
117 if (addr == (void *)(-1)) {
118 pr_err("Error: mmap() syscall returned with (%s)\n",
119 strerror(errno));
120 goto out_close;
121 }
122
123 for (n = 0; n < 6; n++) {
124 u64 stamp, now, delta;
125
126 stamp = mmap_read_self(addr);
127
128 for (i = 0; i < loops; i++)
129 tmp++;
130
131 now = mmap_read_self(addr);
132 loops *= 10;
133
134 delta = now - stamp;
135 pr_debug("%14d: %14Lu\n", n, (long long)delta);
136
137 delta_sum += delta;
138 }
139
140 munmap(addr, page_size);
141 pr_debug(" ");
142out_close:
143 close(fd);
144
145 if (!delta_sum)
146 return -1;
147
148 return 0;
149}
150
151int test__rdpmc(void)
152{
153 int status = 0;
154 int wret = 0;
155 int ret;
156 int pid;
157
158 pid = fork();
159 if (pid < 0)
160 return -1;
161
162 if (!pid) {
163 ret = __test__rdpmc();
164
165 exit(ret);
166 }
167
168 wret = waitpid(pid, &status, 0);
169 if (wret < 0 || status)
170 return -1;
171
172 return 0;
173}
174
175#endif
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
new file mode 100644
index 000000000000..5de0be1ff4b6
--- /dev/null
+++ b/tools/perf/tests/tests.h
@@ -0,0 +1,27 @@
1#ifndef TESTS_H
2#define TESTS_H
3
4enum {
5 TEST_OK = 0,
6 TEST_FAIL = -1,
7 TEST_SKIP = -2,
8};
9
10/* Tests */
11int test__vmlinux_matches_kallsyms(void);
12int test__open_syscall_event(void);
13int test__open_syscall_event_on_all_cpus(void);
14int test__basic_mmap(void);
15int test__PERF_RECORD(void);
16int test__rdpmc(void);
17int test__perf_evsel__roundtrip_name_test(void);
18int test__perf_evsel__tp_sched_test(void);
19int test__syscall_open_tp_fields(void);
20int test__pmu(void);
21int test__attr(void);
22int test__dso_data(void);
23int test__parse_events(void);
24int test__hists_link(void);
25int test__python_use(void);
26
27#endif /* TESTS_H */
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
new file mode 100644
index 000000000000..7b4c4d26d1ba
--- /dev/null
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -0,0 +1,233 @@
1#include <linux/compiler.h>
2#include <linux/rbtree.h>
3#include <string.h>
4#include "map.h"
5#include "symbol.h"
6#include "util.h"
7#include "tests.h"
8#include "debug.h"
9#include "machine.h"
10
11static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
12 struct symbol *sym)
13{
14 bool *visited = symbol__priv(sym);
15 *visited = true;
16 return 0;
17}
18
19int test__vmlinux_matches_kallsyms(void)
20{
21 int err = -1;
22 struct rb_node *nd;
23 struct symbol *sym;
24 struct map *kallsyms_map, *vmlinux_map;
25 struct machine kallsyms, vmlinux;
26 enum map_type type = MAP__FUNCTION;
27 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
28
29 /*
30 * Step 1:
31 *
32 * Init the machines that will hold kernel, modules obtained from
33 * both vmlinux + .ko files and from /proc/kallsyms split by modules.
34 */
35 machine__init(&kallsyms, "", HOST_KERNEL_ID);
36 machine__init(&vmlinux, "", HOST_KERNEL_ID);
37
38 /*
39 * Step 2:
40 *
41 * Create the kernel maps for kallsyms and the DSO where we will then
42 * load /proc/kallsyms. Also create the modules maps from /proc/modules
43 * and find the .ko files that match them in /lib/modules/`uname -r`/.
44 */
45 if (machine__create_kernel_maps(&kallsyms) < 0) {
46 pr_debug("machine__create_kernel_maps ");
47 goto out;
48 }
49
50 /*
51 * Step 3:
52 *
53 * Load and split /proc/kallsyms into multiple maps, one per module.
54 */
55 if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) {
56 pr_debug("dso__load_kallsyms ");
57 goto out;
58 }
59
60 /*
61 * Step 4:
62 *
63 * kallsyms will be internally on demand sorted by name so that we can
64 * find the reference relocation * symbol, i.e. the symbol we will use
65 * to see if the running kernel was relocated by checking if it has the
66 * same value in the vmlinux file we load.
67 */
68 kallsyms_map = machine__kernel_map(&kallsyms, type);
69
70 sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL);
71 if (sym == NULL) {
72 pr_debug("dso__find_symbol_by_name ");
73 goto out;
74 }
75
76 ref_reloc_sym.addr = sym->start;
77
78 /*
79 * Step 5:
80 *
81 * Now repeat step 2, this time for the vmlinux file we'll auto-locate.
82 */
83 if (machine__create_kernel_maps(&vmlinux) < 0) {
84 pr_debug("machine__create_kernel_maps ");
85 goto out;
86 }
87
88 vmlinux_map = machine__kernel_map(&vmlinux, type);
89 map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym;
90
91 /*
92 * Step 6:
93 *
94 * Locate a vmlinux file in the vmlinux path that has a buildid that
95 * matches the one of the running kernel.
96 *
97 * While doing that look if we find the ref reloc symbol, if we find it
98 * we'll have its ref_reloc_symbol.unrelocated_addr and then
99 * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
100 * to fixup the symbols.
101 */
102 if (machine__load_vmlinux_path(&vmlinux, type,
103 vmlinux_matches_kallsyms_filter) <= 0) {
104 pr_debug("Couldn't find a vmlinux that matches the kernel running on this machine, skipping test\n");
105 err = TEST_SKIP;
106 goto out;
107 }
108
109 err = 0;
110 /*
111 * Step 7:
112 *
113 * Now look at the symbols in the vmlinux DSO and check if we find all of them
114 * in the kallsyms dso. For the ones that are in both, check its names and
115 * end addresses too.
116 */
117 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
118 struct symbol *pair, *first_pair;
119 bool backwards = true;
120
121 sym = rb_entry(nd, struct symbol, rb_node);
122
123 if (sym->start == sym->end)
124 continue;
125
126 first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
127 pair = first_pair;
128
129 if (pair && pair->start == sym->start) {
130next_pair:
131 if (strcmp(sym->name, pair->name) == 0) {
132 /*
133 * kallsyms don't have the symbol end, so we
134 * set that by using the next symbol start - 1,
135 * in some cases we get this up to a page
136 * wrong, trace_kmalloc when I was developing
137 * this code was one such example, 2106 bytes
138 * off the real size. More than that and we
139 * _really_ have a problem.
140 */
141 s64 skew = sym->end - pair->end;
142 if (llabs(skew) < page_size)
143 continue;
144
145 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
146 sym->start, sym->name, sym->end, pair->end);
147 } else {
148 struct rb_node *nnd;
149detour:
150 nnd = backwards ? rb_prev(&pair->rb_node) :
151 rb_next(&pair->rb_node);
152 if (nnd) {
153 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
154
155 if (next->start == sym->start) {
156 pair = next;
157 goto next_pair;
158 }
159 }
160
161 if (backwards) {
162 backwards = false;
163 pair = first_pair;
164 goto detour;
165 }
166
167 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
168 sym->start, sym->name, pair->name);
169 }
170 } else
171 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
172
173 err = -1;
174 }
175
176 if (!verbose)
177 goto out;
178
179 pr_info("Maps only in vmlinux:\n");
180
181 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
182 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
183 /*
184 * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
185 * the kernel will have the path for the vmlinux file being used,
186 * so use the short name, less descriptive but the same ("[kernel]" in
187 * both cases.
188 */
189 pair = map_groups__find_by_name(&kallsyms.kmaps, type,
190 (pos->dso->kernel ?
191 pos->dso->short_name :
192 pos->dso->name));
193 if (pair)
194 pair->priv = 1;
195 else
196 map__fprintf(pos, stderr);
197 }
198
199 pr_info("Maps in vmlinux with a different name in kallsyms:\n");
200
201 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
202 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
203
204 pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
205 if (pair == NULL || pair->priv)
206 continue;
207
208 if (pair->start == pos->start) {
209 pair->priv = 1;
210 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
211 pos->start, pos->end, pos->pgoff, pos->dso->name);
212 if (pos->pgoff != pair->pgoff || pos->end != pair->end)
213 pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
214 pair->start, pair->end, pair->pgoff);
215 pr_info(" %s\n", pair->dso->name);
216 pair->priv = 1;
217 }
218 }
219
220 pr_info("Maps only in kallsyms:\n");
221
222 for (nd = rb_first(&kallsyms.kmaps.maps[type]);
223 nd; nd = rb_next(nd)) {
224 struct map *pos = rb_entry(nd, struct map, rb_node);
225
226 if (!pos->priv)
227 map__fprintf(pos, stderr);
228 }
229out:
230 machine__exit(&kallsyms);
231 machine__exit(&vmlinux);
232 return err;
233}
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index 4aeb7d5df939..809ea4632a34 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -273,6 +273,8 @@ void ui_browser__hide(struct ui_browser *browser __maybe_unused)
273{ 273{
274 pthread_mutex_lock(&ui__lock); 274 pthread_mutex_lock(&ui__lock);
275 ui_helpline__pop(); 275 ui_helpline__pop();
276 free(browser->helpline);
277 browser->helpline = NULL;
276 pthread_mutex_unlock(&ui__lock); 278 pthread_mutex_unlock(&ui__lock);
277} 279}
278 280
@@ -471,7 +473,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
471 return row; 473 return row;
472} 474}
473 475
474static struct ui_browser__colorset { 476static struct ui_browser_colorset {
475 const char *name, *fg, *bg; 477 const char *name, *fg, *bg;
476 int colorset; 478 int colorset;
477} ui_browser__colorsets[] = { 479} ui_browser__colorsets[] = {
@@ -706,7 +708,7 @@ void ui_browser__init(void)
706 perf_config(ui_browser__color_config, NULL); 708 perf_config(ui_browser__color_config, NULL);
707 709
708 while (ui_browser__colorsets[i].name) { 710 while (ui_browser__colorsets[i].name) {
709 struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; 711 struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
710 sltt_set_color(c->colorset, c->name, c->fg, c->bg); 712 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
711 } 713 }
712 714
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 8f8cd2d73b3b..7dca1555c610 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -182,15 +182,30 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
182 ab->selection = dl; 182 ab->selection = dl;
183} 183}
184 184
185static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
186{
187 if (!dl || !dl->ins || !ins__is_jump(dl->ins)
188 || !disasm_line__has_offset(dl)
189 || dl->ops.target.offset >= symbol__size(sym))
190 return false;
191
192 return true;
193}
194
185static void annotate_browser__draw_current_jump(struct ui_browser *browser) 195static void annotate_browser__draw_current_jump(struct ui_browser *browser)
186{ 196{
187 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 197 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
188 struct disasm_line *cursor = ab->selection, *target; 198 struct disasm_line *cursor = ab->selection, *target;
189 struct browser_disasm_line *btarget, *bcursor; 199 struct browser_disasm_line *btarget, *bcursor;
190 unsigned int from, to; 200 unsigned int from, to;
201 struct map_symbol *ms = ab->b.priv;
202 struct symbol *sym = ms->sym;
191 203
192 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) || 204 /* PLT symbols contain external offsets */
193 !disasm_line__has_offset(cursor)) 205 if (strstr(sym->name, "@plt"))
206 return;
207
208 if (!disasm_line__is_valid_jump(cursor, sym))
194 return; 209 return;
195 210
196 target = ab->offsets[cursor->ops.target.offset]; 211 target = ab->offsets[cursor->ops.target.offset];
@@ -386,9 +401,8 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
386 browser->b.nr_entries = browser->nr_asm_entries; 401 browser->b.nr_entries = browser->nr_asm_entries;
387} 402}
388 403
389static bool annotate_browser__callq(struct annotate_browser *browser, 404static bool annotate_browser__callq(struct annotate_browser *browser, int evidx,
390 int evidx, void (*timer)(void *arg), 405 struct hist_browser_timer *hbt)
391 void *arg, int delay_secs)
392{ 406{
393 struct map_symbol *ms = browser->b.priv; 407 struct map_symbol *ms = browser->b.priv;
394 struct disasm_line *dl = browser->selection; 408 struct disasm_line *dl = browser->selection;
@@ -418,7 +432,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
418 } 432 }
419 433
420 pthread_mutex_unlock(&notes->lock); 434 pthread_mutex_unlock(&notes->lock);
421 symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs); 435 symbol__tui_annotate(target, ms->map, evidx, hbt);
422 ui_browser__show_title(&browser->b, sym->name); 436 ui_browser__show_title(&browser->b, sym->name);
423 return true; 437 return true;
424} 438}
@@ -602,13 +616,13 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser
602} 616}
603 617
604static int annotate_browser__run(struct annotate_browser *browser, int evidx, 618static int annotate_browser__run(struct annotate_browser *browser, int evidx,
605 void(*timer)(void *arg), 619 struct hist_browser_timer *hbt)
606 void *arg, int delay_secs)
607{ 620{
608 struct rb_node *nd = NULL; 621 struct rb_node *nd = NULL;
609 struct map_symbol *ms = browser->b.priv; 622 struct map_symbol *ms = browser->b.priv;
610 struct symbol *sym = ms->sym; 623 struct symbol *sym = ms->sym;
611 const char *help = "Press 'h' for help on key bindings"; 624 const char *help = "Press 'h' for help on key bindings";
625 int delay_secs = hbt ? hbt->refresh : 0;
612 int key; 626 int key;
613 627
614 if (ui_browser__show(&browser->b, sym->name, help) < 0) 628 if (ui_browser__show(&browser->b, sym->name, help) < 0)
@@ -639,8 +653,8 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
639 653
640 switch (key) { 654 switch (key) {
641 case K_TIMER: 655 case K_TIMER:
642 if (timer != NULL) 656 if (hbt)
643 timer(arg); 657 hbt->timer(hbt->arg);
644 658
645 if (delay_secs != 0) 659 if (delay_secs != 0)
646 symbol__annotate_decay_histogram(sym, evidx); 660 symbol__annotate_decay_histogram(sym, evidx);
@@ -676,8 +690,14 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx,
676 "o Toggle disassembler output/simplified view\n" 690 "o Toggle disassembler output/simplified view\n"
677 "s Toggle source code view\n" 691 "s Toggle source code view\n"
678 "/ Search string\n" 692 "/ Search string\n"
693 "r Run available scripts\n"
679 "? Search previous string\n"); 694 "? Search previous string\n");
680 continue; 695 continue;
696 case 'r':
697 {
698 script_browse(NULL);
699 continue;
700 }
681 case 'H': 701 case 'H':
682 nd = browser->curr_hot; 702 nd = browser->curr_hot;
683 break; 703 break;
@@ -734,7 +754,7 @@ show_help:
734 goto show_sup_ins; 754 goto show_sup_ins;
735 goto out; 755 goto out;
736 } else if (!(annotate_browser__jump(browser) || 756 } else if (!(annotate_browser__jump(browser) ||
737 annotate_browser__callq(browser, evidx, timer, arg, delay_secs))) { 757 annotate_browser__callq(browser, evidx, hbt))) {
738show_sup_ins: 758show_sup_ins:
739 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); 759 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
740 } 760 }
@@ -757,32 +777,29 @@ out:
757} 777}
758 778
759int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 779int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
760 void(*timer)(void *arg), void *arg, int delay_secs) 780 struct hist_browser_timer *hbt)
761{ 781{
762 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 782 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt);
763 timer, arg, delay_secs);
764} 783}
765 784
766static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, 785static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
767 size_t size) 786 size_t size)
768{ 787{
769 u64 offset; 788 u64 offset;
789 struct map_symbol *ms = browser->b.priv;
790 struct symbol *sym = ms->sym;
791
792 /* PLT symbols contain external offsets */
793 if (strstr(sym->name, "@plt"))
794 return;
770 795
771 for (offset = 0; offset < size; ++offset) { 796 for (offset = 0; offset < size; ++offset) {
772 struct disasm_line *dl = browser->offsets[offset], *dlt; 797 struct disasm_line *dl = browser->offsets[offset], *dlt;
773 struct browser_disasm_line *bdlt; 798 struct browser_disasm_line *bdlt;
774 799
775 if (!dl || !dl->ins || !ins__is_jump(dl->ins) || 800 if (!disasm_line__is_valid_jump(dl, sym))
776 !disasm_line__has_offset(dl))
777 continue; 801 continue;
778 802
779 if (dl->ops.target.offset >= size) {
780 ui__error("jump to after symbol!\n"
781 "size: %zx, jump target: %" PRIx64,
782 size, dl->ops.target.offset);
783 continue;
784 }
785
786 dlt = browser->offsets[dl->ops.target.offset]; 803 dlt = browser->offsets[dl->ops.target.offset];
787 /* 804 /*
788 * FIXME: Oops, no jump target? Buggy disassembler? Or do we 805 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
@@ -810,8 +827,7 @@ static inline int width_jumps(int n)
810} 827}
811 828
812int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 829int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
813 void(*timer)(void *arg), void *arg, 830 struct hist_browser_timer *hbt)
814 int delay_secs)
815{ 831{
816 struct disasm_line *pos, *n; 832 struct disasm_line *pos, *n;
817 struct annotation *notes; 833 struct annotation *notes;
@@ -893,7 +909,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
893 909
894 annotate_browser__update_addr_width(&browser); 910 annotate_browser__update_addr_width(&browser);
895 911
896 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); 912 ret = annotate_browser__run(&browser, evidx, hbt);
897 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 913 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
898 list_del(&pos->node); 914 list_del(&pos->node);
899 disasm_line__free(pos); 915 disasm_line__free(pos);
@@ -906,11 +922,11 @@ out_free_offsets:
906 922
907#define ANNOTATE_CFG(n) \ 923#define ANNOTATE_CFG(n) \
908 { .name = #n, .value = &annotate_browser__opts.n, } 924 { .name = #n, .value = &annotate_browser__opts.n, }
909 925
910/* 926/*
911 * Keep the entries sorted, they are bsearch'ed 927 * Keep the entries sorted, they are bsearch'ed
912 */ 928 */
913static struct annotate__config { 929static struct annotate_config {
914 const char *name; 930 const char *name;
915 bool *value; 931 bool *value;
916} annotate__configs[] = { 932} annotate__configs[] = {
@@ -924,7 +940,7 @@ static struct annotate__config {
924 940
925static int annotate_config__cmp(const void *name, const void *cfgp) 941static int annotate_config__cmp(const void *name, const void *cfgp)
926{ 942{
927 const struct annotate__config *cfg = cfgp; 943 const struct annotate_config *cfg = cfgp;
928 944
929 return strcmp(name, cfg->name); 945 return strcmp(name, cfg->name);
930} 946}
@@ -932,7 +948,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp)
932static int annotate__config(const char *var, const char *value, 948static int annotate__config(const char *var, const char *value,
933 void *data __maybe_unused) 949 void *data __maybe_unused)
934{ 950{
935 struct annotate__config *cfg; 951 struct annotate_config *cfg;
936 const char *name; 952 const char *name;
937 953
938 if (prefixcmp(var, "annotate.") != 0) 954 if (prefixcmp(var, "annotate.") != 0)
@@ -940,7 +956,7 @@ static int annotate__config(const char *var, const char *value,
940 956
941 name = var + 9; 957 name = var + 9;
942 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), 958 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
943 sizeof(struct annotate__config), annotate_config__cmp); 959 sizeof(struct annotate_config), annotate_config__cmp);
944 960
945 if (cfg == NULL) 961 if (cfg == NULL)
946 return -1; 962 return -1;
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index ef2f93ca7496..aa22704047d6 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -11,6 +11,7 @@
11#include "../../util/pstack.h" 11#include "../../util/pstack.h"
12#include "../../util/sort.h" 12#include "../../util/sort.h"
13#include "../../util/util.h" 13#include "../../util/util.h"
14#include "../../arch/common.h"
14 15
15#include "../browser.h" 16#include "../browser.h"
16#include "../helpline.h" 17#include "../helpline.h"
@@ -310,10 +311,11 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser)
310} 311}
311 312
312static int hist_browser__run(struct hist_browser *browser, const char *ev_name, 313static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
313 void(*timer)(void *arg), void *arg, int delay_secs) 314 struct hist_browser_timer *hbt)
314{ 315{
315 int key; 316 int key;
316 char title[160]; 317 char title[160];
318 int delay_secs = hbt ? hbt->refresh : 0;
317 319
318 browser->b.entries = &browser->hists->entries; 320 browser->b.entries = &browser->hists->entries;
319 browser->b.nr_entries = browser->hists->nr_entries; 321 browser->b.nr_entries = browser->hists->nr_entries;
@@ -330,7 +332,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name,
330 332
331 switch (key) { 333 switch (key) {
332 case K_TIMER: 334 case K_TIMER:
333 timer(arg); 335 hbt->timer(hbt->arg);
334 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); 336 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
335 337
336 if (browser->hists->stats.nr_lost_warned != 338 if (browser->hists->stats.nr_lost_warned !=
@@ -565,26 +567,128 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
565 return row - first_row; 567 return row - first_row;
566} 568}
567 569
568#define HPP__COLOR_FN(_name, _field) \ 570struct hpp_arg {
569static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ 571 struct ui_browser *b;
570 struct hist_entry *he) \ 572 char folded_sign;
573 bool current_entry;
574};
575
576static int __hpp__color_callchain(struct hpp_arg *arg)
577{
578 if (!symbol_conf.use_callchain)
579 return 0;
580
581 slsmg_printf("%c ", arg->folded_sign);
582 return 2;
583}
584
585static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
586 u64 (*get_field)(struct hist_entry *),
587 int (*callchain_cb)(struct hpp_arg *))
588{
589 int ret = 0;
590 double percent = 0.0;
591 struct hists *hists = he->hists;
592 struct hpp_arg *arg = hpp->ptr;
593
594 if (hists->stats.total_period)
595 percent = 100.0 * get_field(he) / hists->stats.total_period;
596
597 ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
598
599 if (callchain_cb)
600 ret += callchain_cb(arg);
601
602 ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
603 slsmg_printf("%s", hpp->buf);
604
605 if (symbol_conf.event_group) {
606 int prev_idx, idx_delta;
607 struct perf_evsel *evsel = hists_to_evsel(hists);
608 struct hist_entry *pair;
609 int nr_members = evsel->nr_members;
610
611 if (nr_members <= 1)
612 goto out;
613
614 prev_idx = perf_evsel__group_idx(evsel);
615
616 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
617 u64 period = get_field(pair);
618 u64 total = pair->hists->stats.total_period;
619
620 if (!total)
621 continue;
622
623 evsel = hists_to_evsel(pair->hists);
624 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
625
626 while (idx_delta--) {
627 /*
628 * zero-fill group members in the middle which
629 * have no sample
630 */
631 ui_browser__set_percent_color(arg->b, 0.0,
632 arg->current_entry);
633 ret += scnprintf(hpp->buf, hpp->size,
634 " %6.2f%%", 0.0);
635 slsmg_printf("%s", hpp->buf);
636 }
637
638 percent = 100.0 * period / total;
639 ui_browser__set_percent_color(arg->b, percent,
640 arg->current_entry);
641 ret += scnprintf(hpp->buf, hpp->size,
642 " %6.2f%%", percent);
643 slsmg_printf("%s", hpp->buf);
644
645 prev_idx = perf_evsel__group_idx(evsel);
646 }
647
648 idx_delta = nr_members - prev_idx - 1;
649
650 while (idx_delta--) {
651 /*
652 * zero-fill group members at last which have no sample
653 */
654 ui_browser__set_percent_color(arg->b, 0.0,
655 arg->current_entry);
656 ret += scnprintf(hpp->buf, hpp->size,
657 " %6.2f%%", 0.0);
658 slsmg_printf("%s", hpp->buf);
659 }
660 }
661out:
662 if (!arg->current_entry || !arg->b->navkeypressed)
663 ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
664
665 return ret;
666}
667
668#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \
669static u64 __hpp_get_##_field(struct hist_entry *he) \
571{ \ 670{ \
572 struct hists *hists = he->hists; \ 671 return he->stat._field; \
573 double percent = 100.0 * he->stat._field / hists->stats.total_period; \ 672} \
574 *(double *)hpp->ptr = percent; \ 673 \
575 return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ 674static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \
675 struct hist_entry *he) \
676{ \
677 return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
576} 678}
577 679
578HPP__COLOR_FN(overhead, period) 680__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain)
579HPP__COLOR_FN(overhead_sys, period_sys) 681__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL)
580HPP__COLOR_FN(overhead_us, period_us) 682__HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL)
581HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) 683__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL)
582HPP__COLOR_FN(overhead_guest_us, period_guest_us) 684__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
583 685
584#undef HPP__COLOR_FN 686#undef __HPP_COLOR_PERCENT_FN
585 687
586void hist_browser__init_hpp(void) 688void hist_browser__init_hpp(void)
587{ 689{
690 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
691
588 perf_hpp__init(); 692 perf_hpp__init();
589 693
590 perf_hpp__format[PERF_HPP__OVERHEAD].color = 694 perf_hpp__format[PERF_HPP__OVERHEAD].color =
@@ -604,13 +708,13 @@ static int hist_browser__show_entry(struct hist_browser *browser,
604 unsigned short row) 708 unsigned short row)
605{ 709{
606 char s[256]; 710 char s[256];
607 double percent; 711 int printed = 0;
608 int i, printed = 0;
609 int width = browser->b.width; 712 int width = browser->b.width;
610 char folded_sign = ' '; 713 char folded_sign = ' ';
611 bool current_entry = ui_browser__is_current_entry(&browser->b, row); 714 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
612 off_t row_offset = entry->row_offset; 715 off_t row_offset = entry->row_offset;
613 bool first = true; 716 bool first = true;
717 struct perf_hpp_fmt *fmt;
614 718
615 if (current_entry) { 719 if (current_entry) {
616 browser->he_selection = entry; 720 browser->he_selection = entry;
@@ -623,41 +727,30 @@ static int hist_browser__show_entry(struct hist_browser *browser,
623 } 727 }
624 728
625 if (row_offset == 0) { 729 if (row_offset == 0) {
730 struct hpp_arg arg = {
731 .b = &browser->b,
732 .folded_sign = folded_sign,
733 .current_entry = current_entry,
734 };
626 struct perf_hpp hpp = { 735 struct perf_hpp hpp = {
627 .buf = s, 736 .buf = s,
628 .size = sizeof(s), 737 .size = sizeof(s),
738 .ptr = &arg,
629 }; 739 };
630 740
631 ui_browser__gotorc(&browser->b, row, 0); 741 ui_browser__gotorc(&browser->b, row, 0);
632 742
633 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 743 perf_hpp__for_each_format(fmt) {
634 if (!perf_hpp__format[i].cond)
635 continue;
636
637 if (!first) { 744 if (!first) {
638 slsmg_printf(" "); 745 slsmg_printf(" ");
639 width -= 2; 746 width -= 2;
640 } 747 }
641 first = false; 748 first = false;
642 749
643 if (perf_hpp__format[i].color) { 750 if (fmt->color) {
644 hpp.ptr = &percent; 751 width -= fmt->color(&hpp, entry);
645 /* It will set percent for us. See HPP__COLOR_FN above. */
646 width -= perf_hpp__format[i].color(&hpp, entry);
647
648 ui_browser__set_percent_color(&browser->b, percent, current_entry);
649
650 if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) {
651 slsmg_printf("%c ", folded_sign);
652 width -= 2;
653 }
654
655 slsmg_printf("%s", s);
656
657 if (!current_entry || !browser->b.navkeypressed)
658 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
659 } else { 752 } else {
660 width -= perf_hpp__format[i].entry(&hpp, entry); 753 width -= fmt->entry(&hpp, entry);
661 slsmg_printf("%s", s); 754 slsmg_printf("%s", s);
662 } 755 }
663 } 756 }
@@ -1096,6 +1189,21 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
1096 const struct thread *thread = hists->thread_filter; 1189 const struct thread *thread = hists->thread_filter;
1097 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 1190 unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1098 u64 nr_events = hists->stats.total_period; 1191 u64 nr_events = hists->stats.total_period;
1192 struct perf_evsel *evsel = hists_to_evsel(hists);
1193 char buf[512];
1194 size_t buflen = sizeof(buf);
1195
1196 if (symbol_conf.event_group && evsel->nr_members > 1) {
1197 struct perf_evsel *pos;
1198
1199 perf_evsel__group_desc(evsel, buf, buflen);
1200 ev_name = buf;
1201
1202 for_each_group_member(pos, evsel) {
1203 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1204 nr_events += pos->hists.stats.total_period;
1205 }
1206 }
1099 1207
1100 nr_samples = convert_unit(nr_samples, &unit); 1208 nr_samples = convert_unit(nr_samples, &unit);
1101 printed = scnprintf(bf, size, 1209 printed = scnprintf(bf, size,
@@ -1127,11 +1235,107 @@ static inline void free_popup_options(char **options, int n)
1127 } 1235 }
1128} 1236}
1129 1237
1238/* Check whether the browser is for 'top' or 'report' */
1239static inline bool is_report_browser(void *timer)
1240{
1241 return timer == NULL;
1242}
1243
1244/*
1245 * Only runtime switching of perf data file will make "input_name" point
1246 * to a malloced buffer. So add "is_input_name_malloced" flag to decide
1247 * whether we need to call free() for current "input_name" during the switch.
1248 */
1249static bool is_input_name_malloced = false;
1250
1251static int switch_data_file(void)
1252{
1253 char *pwd, *options[32], *abs_path[32], *tmp;
1254 DIR *pwd_dir;
1255 int nr_options = 0, choice = -1, ret = -1;
1256 struct dirent *dent;
1257
1258 pwd = getenv("PWD");
1259 if (!pwd)
1260 return ret;
1261
1262 pwd_dir = opendir(pwd);
1263 if (!pwd_dir)
1264 return ret;
1265
1266 memset(options, 0, sizeof(options));
1267 memset(options, 0, sizeof(abs_path));
1268
1269 while ((dent = readdir(pwd_dir))) {
1270 char path[PATH_MAX];
1271 u64 magic;
1272 char *name = dent->d_name;
1273 FILE *file;
1274
1275 if (!(dent->d_type == DT_REG))
1276 continue;
1277
1278 snprintf(path, sizeof(path), "%s/%s", pwd, name);
1279
1280 file = fopen(path, "r");
1281 if (!file)
1282 continue;
1283
1284 if (fread(&magic, 1, 8, file) < 8)
1285 goto close_file_and_continue;
1286
1287 if (is_perf_magic(magic)) {
1288 options[nr_options] = strdup(name);
1289 if (!options[nr_options])
1290 goto close_file_and_continue;
1291
1292 abs_path[nr_options] = strdup(path);
1293 if (!abs_path[nr_options]) {
1294 free(options[nr_options]);
1295 ui__warning("Can't search all data files due to memory shortage.\n");
1296 fclose(file);
1297 break;
1298 }
1299
1300 nr_options++;
1301 }
1302
1303close_file_and_continue:
1304 fclose(file);
1305 if (nr_options >= 32) {
1306 ui__warning("Too many perf data files in PWD!\n"
1307 "Only the first 32 files will be listed.\n");
1308 break;
1309 }
1310 }
1311 closedir(pwd_dir);
1312
1313 if (nr_options) {
1314 choice = ui__popup_menu(nr_options, options);
1315 if (choice < nr_options && choice >= 0) {
1316 tmp = strdup(abs_path[choice]);
1317 if (tmp) {
1318 if (is_input_name_malloced)
1319 free((void *)input_name);
1320 input_name = tmp;
1321 is_input_name_malloced = true;
1322 ret = 0;
1323 } else
1324 ui__warning("Data switch failed due to memory shortage!\n");
1325 }
1326 }
1327
1328 free_popup_options(options, nr_options);
1329 free_popup_options(abs_path, nr_options);
1330 return ret;
1331}
1332
1333
1130static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 1334static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1131 const char *helpline, const char *ev_name, 1335 const char *helpline, const char *ev_name,
1132 bool left_exits, 1336 bool left_exits,
1133 void(*timer)(void *arg), void *arg, 1337 struct hist_browser_timer *hbt,
1134 int delay_secs) 1338 struct perf_session_env *env)
1135{ 1339{
1136 struct hists *hists = &evsel->hists; 1340 struct hists *hists = &evsel->hists;
1137 struct hist_browser *browser = hist_browser__new(hists); 1341 struct hist_browser *browser = hist_browser__new(hists);
@@ -1141,6 +1345,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1141 int nr_options = 0; 1345 int nr_options = 0;
1142 int key = -1; 1346 int key = -1;
1143 char buf[64]; 1347 char buf[64];
1348 char script_opt[64];
1349 int delay_secs = hbt ? hbt->refresh : 0;
1144 1350
1145 if (browser == NULL) 1351 if (browser == NULL)
1146 return -1; 1352 return -1;
@@ -1159,10 +1365,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1159 int choice = 0, 1365 int choice = 0,
1160 annotate = -2, zoom_dso = -2, zoom_thread = -2, 1366 annotate = -2, zoom_dso = -2, zoom_thread = -2,
1161 annotate_f = -2, annotate_t = -2, browse_map = -2; 1367 annotate_f = -2, annotate_t = -2, browse_map = -2;
1368 int scripts_comm = -2, scripts_symbol = -2,
1369 scripts_all = -2, switch_data = -2;
1162 1370
1163 nr_options = 0; 1371 nr_options = 0;
1164 1372
1165 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs); 1373 key = hist_browser__run(browser, ev_name, hbt);
1166 1374
1167 if (browser->he_selection != NULL) { 1375 if (browser->he_selection != NULL) {
1168 thread = hist_browser__selected_thread(browser); 1376 thread = hist_browser__selected_thread(browser);
@@ -1211,6 +1419,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1211 hist_browser__reset(browser); 1419 hist_browser__reset(browser);
1212 } 1420 }
1213 continue; 1421 continue;
1422 case 'r':
1423 if (is_report_browser(hbt))
1424 goto do_scripts;
1425 continue;
1426 case 's':
1427 if (is_report_browser(hbt))
1428 goto do_data_switch;
1429 continue;
1214 case K_F1: 1430 case K_F1:
1215 case 'h': 1431 case 'h':
1216 case '?': 1432 case '?':
@@ -1229,6 +1445,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1229 "E Expand all callchains\n" 1445 "E Expand all callchains\n"
1230 "d Zoom into current DSO\n" 1446 "d Zoom into current DSO\n"
1231 "t Zoom into current Thread\n" 1447 "t Zoom into current Thread\n"
1448 "r Run available scripts('perf report' only)\n"
1449 "s Switch to another data file in PWD ('perf report' only)\n"
1232 "P Print histograms to perf.hist.N\n" 1450 "P Print histograms to perf.hist.N\n"
1233 "V Verbose (DSO names in callchains, etc)\n" 1451 "V Verbose (DSO names in callchains, etc)\n"
1234 "/ Filter symbol by name"); 1452 "/ Filter symbol by name");
@@ -1317,6 +1535,28 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1317 browser->selection->map != NULL && 1535 browser->selection->map != NULL &&
1318 asprintf(&options[nr_options], "Browse map details") > 0) 1536 asprintf(&options[nr_options], "Browse map details") > 0)
1319 browse_map = nr_options++; 1537 browse_map = nr_options++;
1538
1539 /* perf script support */
1540 if (browser->he_selection) {
1541 struct symbol *sym;
1542
1543 if (asprintf(&options[nr_options], "Run scripts for samples of thread [%s]",
1544 browser->he_selection->thread->comm) > 0)
1545 scripts_comm = nr_options++;
1546
1547 sym = browser->he_selection->ms.sym;
1548 if (sym && sym->namelen &&
1549 asprintf(&options[nr_options], "Run scripts for samples of symbol [%s]",
1550 sym->name) > 0)
1551 scripts_symbol = nr_options++;
1552 }
1553
1554 if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
1555 scripts_all = nr_options++;
1556
1557 if (is_report_browser(hbt) && asprintf(&options[nr_options],
1558 "Switch to another data file in PWD") > 0)
1559 switch_data = nr_options++;
1320add_exit_option: 1560add_exit_option:
1321 options[nr_options++] = (char *)"Exit"; 1561 options[nr_options++] = (char *)"Exit";
1322retry_popup_menu: 1562retry_popup_menu:
@@ -1334,6 +1574,9 @@ retry_popup_menu:
1334 struct hist_entry *he; 1574 struct hist_entry *he;
1335 int err; 1575 int err;
1336do_annotate: 1576do_annotate:
1577 if (!objdump_path && perf_session_env__lookup_objdump(env))
1578 continue;
1579
1337 he = hist_browser__selected_entry(browser); 1580 he = hist_browser__selected_entry(browser);
1338 if (he == NULL) 1581 if (he == NULL)
1339 continue; 1582 continue;
@@ -1356,8 +1599,7 @@ do_annotate:
1356 * Don't let this be freed, say, by hists__decay_entry. 1599 * Don't let this be freed, say, by hists__decay_entry.
1357 */ 1600 */
1358 he->used = true; 1601 he->used = true;
1359 err = hist_entry__tui_annotate(he, evsel->idx, 1602 err = hist_entry__tui_annotate(he, evsel->idx, hbt);
1360 timer, arg, delay_secs);
1361 he->used = false; 1603 he->used = false;
1362 /* 1604 /*
1363 * offer option to annotate the other branch source or target 1605 * offer option to annotate the other branch source or target
@@ -1411,6 +1653,30 @@ zoom_out_thread:
1411 hists__filter_by_thread(hists); 1653 hists__filter_by_thread(hists);
1412 hist_browser__reset(browser); 1654 hist_browser__reset(browser);
1413 } 1655 }
1656 /* perf scripts support */
1657 else if (choice == scripts_all || choice == scripts_comm ||
1658 choice == scripts_symbol) {
1659do_scripts:
1660 memset(script_opt, 0, 64);
1661
1662 if (choice == scripts_comm)
1663 sprintf(script_opt, " -c %s ", browser->he_selection->thread->comm);
1664
1665 if (choice == scripts_symbol)
1666 sprintf(script_opt, " -S %s ", browser->he_selection->ms.sym->name);
1667
1668 script_browse(script_opt);
1669 }
1670 /* Switch to another data file */
1671 else if (choice == switch_data) {
1672do_data_switch:
1673 if (!switch_data_file()) {
1674 key = K_SWITCH_INPUT_DATA;
1675 break;
1676 } else
1677 ui__warning("Won't switch the data files due to\n"
1678 "no valid data file get selected!\n");
1679 }
1414 } 1680 }
1415out_free_stack: 1681out_free_stack:
1416 pstack__delete(fstack); 1682 pstack__delete(fstack);
@@ -1424,6 +1690,7 @@ struct perf_evsel_menu {
1424 struct ui_browser b; 1690 struct ui_browser b;
1425 struct perf_evsel *selection; 1691 struct perf_evsel *selection;
1426 bool lost_events, lost_events_warned; 1692 bool lost_events, lost_events_warned;
1693 struct perf_session_env *env;
1427}; 1694};
1428 1695
1429static void perf_evsel_menu__write(struct ui_browser *browser, 1696static void perf_evsel_menu__write(struct ui_browser *browser,
@@ -1442,6 +1709,16 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1442 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : 1709 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1443 HE_COLORSET_NORMAL); 1710 HE_COLORSET_NORMAL);
1444 1711
1712 if (symbol_conf.event_group && evsel->nr_members > 1) {
1713 struct perf_evsel *pos;
1714
1715 ev_name = perf_evsel__group_name(evsel);
1716
1717 for_each_group_member(pos, evsel) {
1718 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1719 }
1720 }
1721
1445 nr_events = convert_unit(nr_events, &unit); 1722 nr_events = convert_unit(nr_events, &unit);
1446 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, 1723 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1447 unit, unit == ' ' ? "" : " ", ev_name); 1724 unit, unit == ' ' ? "" : " ", ev_name);
@@ -1466,11 +1743,12 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1466 1743
1467static int perf_evsel_menu__run(struct perf_evsel_menu *menu, 1744static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1468 int nr_events, const char *help, 1745 int nr_events, const char *help,
1469 void(*timer)(void *arg), void *arg, int delay_secs) 1746 struct hist_browser_timer *hbt)
1470{ 1747{
1471 struct perf_evlist *evlist = menu->b.priv; 1748 struct perf_evlist *evlist = menu->b.priv;
1472 struct perf_evsel *pos; 1749 struct perf_evsel *pos;
1473 const char *ev_name, *title = "Available samples"; 1750 const char *ev_name, *title = "Available samples";
1751 int delay_secs = hbt ? hbt->refresh : 0;
1474 int key; 1752 int key;
1475 1753
1476 if (ui_browser__show(&menu->b, title, 1754 if (ui_browser__show(&menu->b, title,
@@ -1482,7 +1760,7 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1482 1760
1483 switch (key) { 1761 switch (key) {
1484 case K_TIMER: 1762 case K_TIMER:
1485 timer(arg); 1763 hbt->timer(hbt->arg);
1486 1764
1487 if (!menu->lost_events_warned && menu->lost_events) { 1765 if (!menu->lost_events_warned && menu->lost_events) {
1488 ui_browser__warn_lost_events(&menu->b); 1766 ui_browser__warn_lost_events(&menu->b);
@@ -1500,12 +1778,12 @@ browse_hists:
1500 * Give the calling tool a chance to populate the non 1778 * Give the calling tool a chance to populate the non
1501 * default evsel resorted hists tree. 1779 * default evsel resorted hists tree.
1502 */ 1780 */
1503 if (timer) 1781 if (hbt)
1504 timer(arg); 1782 hbt->timer(hbt->arg);
1505 ev_name = perf_evsel__name(pos); 1783 ev_name = perf_evsel__name(pos);
1506 key = perf_evsel__hists_browse(pos, nr_events, help, 1784 key = perf_evsel__hists_browse(pos, nr_events, help,
1507 ev_name, true, timer, 1785 ev_name, true, hbt,
1508 arg, delay_secs); 1786 menu->env);
1509 ui_browser__show_title(&menu->b, title); 1787 ui_browser__show_title(&menu->b, title);
1510 switch (key) { 1788 switch (key) {
1511 case K_TAB: 1789 case K_TAB:
@@ -1525,6 +1803,7 @@ browse_hists:
1525 "Do you really want to exit?")) 1803 "Do you really want to exit?"))
1526 continue; 1804 continue;
1527 /* Fall thru */ 1805 /* Fall thru */
1806 case K_SWITCH_INPUT_DATA:
1528 case 'q': 1807 case 'q':
1529 case CTRL('c'): 1808 case CTRL('c'):
1530 goto out; 1809 goto out;
@@ -1551,10 +1830,21 @@ out:
1551 return key; 1830 return key;
1552} 1831}
1553 1832
1833static bool filter_group_entries(struct ui_browser *self __maybe_unused,
1834 void *entry)
1835{
1836 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1837
1838 if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
1839 return true;
1840
1841 return false;
1842}
1843
1554static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, 1844static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1555 const char *help, 1845 int nr_entries, const char *help,
1556 void(*timer)(void *arg), void *arg, 1846 struct hist_browser_timer *hbt,
1557 int delay_secs) 1847 struct perf_session_env *env)
1558{ 1848{
1559 struct perf_evsel *pos; 1849 struct perf_evsel *pos;
1560 struct perf_evsel_menu menu = { 1850 struct perf_evsel_menu menu = {
@@ -1563,9 +1853,11 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1563 .refresh = ui_browser__list_head_refresh, 1853 .refresh = ui_browser__list_head_refresh,
1564 .seek = ui_browser__list_head_seek, 1854 .seek = ui_browser__list_head_seek,
1565 .write = perf_evsel_menu__write, 1855 .write = perf_evsel_menu__write,
1566 .nr_entries = evlist->nr_entries, 1856 .filter = filter_group_entries,
1857 .nr_entries = nr_entries,
1567 .priv = evlist, 1858 .priv = evlist,
1568 }, 1859 },
1860 .env = env,
1569 }; 1861 };
1570 1862
1571 ui_helpline__push("Press ESC to exit"); 1863 ui_helpline__push("Press ESC to exit");
@@ -1578,23 +1870,37 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1578 menu.b.width = line_len; 1870 menu.b.width = line_len;
1579 } 1871 }
1580 1872
1581 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer, 1873 return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
1582 arg, delay_secs);
1583} 1874}
1584 1875
1585int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 1876int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1586 void(*timer)(void *arg), void *arg, 1877 struct hist_browser_timer *hbt,
1587 int delay_secs) 1878 struct perf_session_env *env)
1588{ 1879{
1589 if (evlist->nr_entries == 1) { 1880 int nr_entries = evlist->nr_entries;
1881
1882single_entry:
1883 if (nr_entries == 1) {
1590 struct perf_evsel *first = list_entry(evlist->entries.next, 1884 struct perf_evsel *first = list_entry(evlist->entries.next,
1591 struct perf_evsel, node); 1885 struct perf_evsel, node);
1592 const char *ev_name = perf_evsel__name(first); 1886 const char *ev_name = perf_evsel__name(first);
1593 return perf_evsel__hists_browse(first, evlist->nr_entries, help, 1887
1594 ev_name, false, timer, arg, 1888 return perf_evsel__hists_browse(first, nr_entries, help,
1595 delay_secs); 1889 ev_name, false, hbt, env);
1890 }
1891
1892 if (symbol_conf.event_group) {
1893 struct perf_evsel *pos;
1894
1895 nr_entries = 0;
1896 list_for_each_entry(pos, &evlist->entries, node)
1897 if (perf_evsel__is_group_leader(pos))
1898 nr_entries++;
1899
1900 if (nr_entries == 1)
1901 goto single_entry;
1596 } 1902 }
1597 1903
1598 return __perf_evlist__tui_browse_hists(evlist, help, 1904 return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
1599 timer, arg, delay_secs); 1905 hbt, env);
1600} 1906}
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c
new file mode 100644
index 000000000000..cbbd44b0d93e
--- /dev/null
+++ b/tools/perf/ui/browsers/scripts.c
@@ -0,0 +1,189 @@
1#include <elf.h>
2#include <newt.h>
3#include <inttypes.h>
4#include <sys/ttydefaults.h>
5#include <string.h>
6#include "../../util/sort.h"
7#include "../../util/util.h"
8#include "../../util/hist.h"
9#include "../../util/debug.h"
10#include "../../util/symbol.h"
11#include "../browser.h"
12#include "../helpline.h"
13#include "../libslang.h"
14
15/* 2048 lines should be enough for a script output */
16#define MAX_LINES 2048
17
18/* 160 bytes for one output line */
19#define AVERAGE_LINE_LEN 160
20
21struct script_line {
22 struct list_head node;
23 char line[AVERAGE_LINE_LEN];
24};
25
26struct perf_script_browser {
27 struct ui_browser b;
28 struct list_head entries;
29 const char *script_name;
30 int nr_lines;
31};
32
33#define SCRIPT_NAMELEN 128
34#define SCRIPT_MAX_NO 64
35/*
36 * Usually the full path for a script is:
37 * /home/username/libexec/perf-core/scripts/python/xxx.py
38 * /home/username/libexec/perf-core/scripts/perl/xxx.pl
39 * So 256 should be long enough to contain the full path.
40 */
41#define SCRIPT_FULLPATH_LEN 256
42
43/*
44 * When success, will copy the full path of the selected script
45 * into the buffer pointed by script_name, and return 0.
46 * Return -1 on failure.
47 */
48static int list_scripts(char *script_name)
49{
50 char *buf, *names[SCRIPT_MAX_NO], *paths[SCRIPT_MAX_NO];
51 int i, num, choice, ret = -1;
52
53 /* Preset the script name to SCRIPT_NAMELEN */
54 buf = malloc(SCRIPT_MAX_NO * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN));
55 if (!buf)
56 return ret;
57
58 for (i = 0; i < SCRIPT_MAX_NO; i++) {
59 names[i] = buf + i * (SCRIPT_NAMELEN + SCRIPT_FULLPATH_LEN);
60 paths[i] = names[i] + SCRIPT_NAMELEN;
61 }
62
63 num = find_scripts(names, paths);
64 if (num > 0) {
65 choice = ui__popup_menu(num, names);
66 if (choice < num && choice >= 0) {
67 strcpy(script_name, paths[choice]);
68 ret = 0;
69 }
70 }
71
72 free(buf);
73 return ret;
74}
75
76static void script_browser__write(struct ui_browser *browser,
77 void *entry, int row)
78{
79 struct script_line *sline = list_entry(entry, struct script_line, node);
80 bool current_entry = ui_browser__is_current_entry(browser, row);
81
82 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
83 HE_COLORSET_NORMAL);
84
85 slsmg_write_nstring(sline->line, browser->width);
86}
87
88static int script_browser__run(struct perf_script_browser *self)
89{
90 int key;
91
92 if (ui_browser__show(&self->b, self->script_name,
93 "Press <- or ESC to exit") < 0)
94 return -1;
95
96 while (1) {
97 key = ui_browser__run(&self->b, 0);
98
99 /* We can add some special key handling here if needed */
100 break;
101 }
102
103 ui_browser__hide(&self->b);
104 return key;
105}
106
107
108int script_browse(const char *script_opt)
109{
110 char cmd[SCRIPT_FULLPATH_LEN*2], script_name[SCRIPT_FULLPATH_LEN];
111 char *line = NULL;
112 size_t len = 0;
113 ssize_t retlen;
114 int ret = -1, nr_entries = 0;
115 FILE *fp;
116 void *buf;
117 struct script_line *sline;
118
119 struct perf_script_browser script = {
120 .b = {
121 .refresh = ui_browser__list_head_refresh,
122 .seek = ui_browser__list_head_seek,
123 .write = script_browser__write,
124 },
125 .script_name = script_name,
126 };
127
128 INIT_LIST_HEAD(&script.entries);
129
130 /* Save each line of the output in one struct script_line object. */
131 buf = zalloc((sizeof(*sline)) * MAX_LINES);
132 if (!buf)
133 return -1;
134 sline = buf;
135
136 memset(script_name, 0, SCRIPT_FULLPATH_LEN);
137 if (list_scripts(script_name))
138 goto exit;
139
140 sprintf(cmd, "perf script -s %s ", script_name);
141
142 if (script_opt)
143 strcat(cmd, script_opt);
144
145 if (input_name) {
146 strcat(cmd, " -i ");
147 strcat(cmd, input_name);
148 }
149
150 strcat(cmd, " 2>&1");
151
152 fp = popen(cmd, "r");
153 if (!fp)
154 goto exit;
155
156 while ((retlen = getline(&line, &len, fp)) != -1) {
157 strncpy(sline->line, line, AVERAGE_LINE_LEN);
158
159 /* If one output line is very large, just cut it short */
160 if (retlen >= AVERAGE_LINE_LEN) {
161 sline->line[AVERAGE_LINE_LEN - 1] = '\0';
162 sline->line[AVERAGE_LINE_LEN - 2] = '\n';
163 }
164 list_add_tail(&sline->node, &script.entries);
165
166 if (script.b.width < retlen)
167 script.b.width = retlen;
168
169 if (nr_entries++ >= MAX_LINES - 1)
170 break;
171 sline++;
172 }
173
174 if (script.b.width > AVERAGE_LINE_LEN)
175 script.b.width = AVERAGE_LINE_LEN;
176
177 if (line)
178 free(line);
179 pclose(fp);
180
181 script.nr_lines = nr_entries;
182 script.b.nr_entries = nr_entries;
183 script.b.entries = &script.entries;
184
185 ret = script_browser__run(&script);
186exit:
187 free(buf);
188 return ret;
189}
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c
new file mode 100644
index 000000000000..7d8dc581a545
--- /dev/null
+++ b/tools/perf/ui/gtk/annotate.c
@@ -0,0 +1,229 @@
1#include "gtk.h"
2#include "util/debug.h"
3#include "util/annotate.h"
4#include "ui/helpline.h"
5
6
7enum {
8 ANN_COL__PERCENT,
9 ANN_COL__OFFSET,
10 ANN_COL__LINE,
11
12 MAX_ANN_COLS
13};
14
15static const char *const col_names[] = {
16 "Overhead",
17 "Offset",
18 "Line"
19};
20
21static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym,
22 struct disasm_line *dl, int evidx)
23{
24 struct sym_hist *symhist;
25 double percent = 0.0;
26 const char *markup;
27 int ret = 0;
28
29 strcpy(buf, "");
30
31 if (dl->offset == (s64) -1)
32 return 0;
33
34 symhist = annotation__histogram(symbol__annotation(sym), evidx);
35 if (!symhist->addr[dl->offset])
36 return 0;
37
38 percent = 100.0 * symhist->addr[dl->offset] / symhist->sum;
39
40 markup = perf_gtk__get_percent_color(percent);
41 if (markup)
42 ret += scnprintf(buf, size, "%s", markup);
43 ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent);
44 if (markup)
45 ret += scnprintf(buf + ret, size - ret, "</span>");
46
47 return ret;
48}
49
50static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym,
51 struct map *map, struct disasm_line *dl)
52{
53 u64 start = map__rip_2objdump(map, sym->start);
54
55 strcpy(buf, "");
56
57 if (dl->offset == (s64) -1)
58 return 0;
59
60 return scnprintf(buf, size, "%"PRIx64, start + dl->offset);
61}
62
63static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl)
64{
65 int ret = 0;
66 char *line = g_markup_escape_text(dl->line, -1);
67 const char *markup = "<span fgcolor='gray'>";
68
69 strcpy(buf, "");
70
71 if (!line)
72 return 0;
73
74 if (dl->offset != (s64) -1)
75 markup = NULL;
76
77 if (markup)
78 ret += scnprintf(buf, size, "%s", markup);
79 ret += scnprintf(buf + ret, size - ret, "%s", line);
80 if (markup)
81 ret += scnprintf(buf + ret, size - ret, "</span>");
82
83 g_free(line);
84 return ret;
85}
86
87static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym,
88 struct map *map, int evidx,
89 struct hist_browser_timer *hbt __maybe_unused)
90{
91 struct disasm_line *pos, *n;
92 struct annotation *notes;
93 GType col_types[MAX_ANN_COLS];
94 GtkCellRenderer *renderer;
95 GtkListStore *store;
96 GtkWidget *view;
97 int i;
98 char s[512];
99
100 notes = symbol__annotation(sym);
101
102 for (i = 0; i < MAX_ANN_COLS; i++) {
103 col_types[i] = G_TYPE_STRING;
104 }
105 store = gtk_list_store_newv(MAX_ANN_COLS, col_types);
106
107 view = gtk_tree_view_new();
108 renderer = gtk_cell_renderer_text_new();
109
110 for (i = 0; i < MAX_ANN_COLS; i++) {
111 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
112 -1, col_names[i], renderer, "markup",
113 i, NULL);
114 }
115
116 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
117 g_object_unref(GTK_TREE_MODEL(store));
118
119 list_for_each_entry(pos, &notes->src->source, node) {
120 GtkTreeIter iter;
121
122 gtk_list_store_append(store, &iter);
123
124 if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx))
125 gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1);
126 if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos))
127 gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1);
128 if (perf_gtk__get_line(s, sizeof(s), pos))
129 gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1);
130 }
131
132 gtk_container_add(GTK_CONTAINER(window), view);
133
134 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
135 list_del(&pos->node);
136 disasm_line__free(pos);
137 }
138
139 return 0;
140}
141
142int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
143 struct hist_browser_timer *hbt)
144{
145 GtkWidget *window;
146 GtkWidget *notebook;
147 GtkWidget *scrolled_window;
148 GtkWidget *tab_label;
149
150 if (map->dso->annotate_warned)
151 return -1;
152
153 if (symbol__annotate(sym, map, 0) < 0) {
154 ui__error("%s", ui_helpline__current);
155 return -1;
156 }
157
158 if (perf_gtk__is_active_context(pgctx)) {
159 window = pgctx->main_window;
160 notebook = pgctx->notebook;
161 } else {
162 GtkWidget *vbox;
163 GtkWidget *infobar;
164 GtkWidget *statbar;
165
166 signal(SIGSEGV, perf_gtk__signal);
167 signal(SIGFPE, perf_gtk__signal);
168 signal(SIGINT, perf_gtk__signal);
169 signal(SIGQUIT, perf_gtk__signal);
170 signal(SIGTERM, perf_gtk__signal);
171
172 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
173 gtk_window_set_title(GTK_WINDOW(window), "perf annotate");
174
175 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
176
177 pgctx = perf_gtk__activate_context(window);
178 if (!pgctx)
179 return -1;
180
181 vbox = gtk_vbox_new(FALSE, 0);
182 notebook = gtk_notebook_new();
183 pgctx->notebook = notebook;
184
185 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
186
187 infobar = perf_gtk__setup_info_bar();
188 if (infobar) {
189 gtk_box_pack_start(GTK_BOX(vbox), infobar,
190 FALSE, FALSE, 0);
191 }
192
193 statbar = perf_gtk__setup_statusbar();
194 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
195
196 gtk_container_add(GTK_CONTAINER(window), vbox);
197 }
198
199 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
200 tab_label = gtk_label_new(sym->name);
201
202 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
203 GTK_POLICY_AUTOMATIC,
204 GTK_POLICY_AUTOMATIC);
205
206 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window,
207 tab_label);
208
209 perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt);
210 return 0;
211}
212
213void perf_gtk__show_annotations(void)
214{
215 GtkWidget *window;
216
217 if (!perf_gtk__is_active_context(pgctx))
218 return;
219
220 window = pgctx->main_window;
221 gtk_widget_show_all(window);
222
223 perf_gtk__resize_window(window);
224 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
225
226 gtk_main();
227
228 perf_gtk__deactivate_context(&pgctx);
229}
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 4125c6284114..c95012cdb438 100644
--- a/tools/perf/ui/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -8,15 +8,13 @@
8 8
9#include <signal.h> 9#include <signal.h>
10 10
11#define MAX_COLUMNS 32 11void perf_gtk__signal(int sig)
12
13static void perf_gtk__signal(int sig)
14{ 12{
15 perf_gtk__exit(false); 13 perf_gtk__exit(false);
16 psignal(sig, "perf"); 14 psignal(sig, "perf");
17} 15}
18 16
19static void perf_gtk__resize_window(GtkWidget *window) 17void perf_gtk__resize_window(GtkWidget *window)
20{ 18{
21 GdkRectangle rect; 19 GdkRectangle rect;
22 GdkScreen *screen; 20 GdkScreen *screen;
@@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window)
36 gtk_window_resize(GTK_WINDOW(window), width, height); 34 gtk_window_resize(GTK_WINDOW(window), width, height);
37} 35}
38 36
39static const char *perf_gtk__get_percent_color(double percent) 37const char *perf_gtk__get_percent_color(double percent)
40{ 38{
41 if (percent >= MIN_RED) 39 if (percent >= MIN_RED)
42 return "<span fgcolor='red'>"; 40 return "<span fgcolor='red'>";
@@ -45,155 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent)
45 return NULL; 43 return NULL;
46} 44}
47 45
48#define HPP__COLOR_FN(_name, _field) \
49static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
50 struct hist_entry *he) \
51{ \
52 struct hists *hists = he->hists; \
53 double percent = 100.0 * he->stat._field / hists->stats.total_period; \
54 const char *markup; \
55 int ret = 0; \
56 \
57 markup = perf_gtk__get_percent_color(percent); \
58 if (markup) \
59 ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \
60 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \
61 if (markup) \
62 ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \
63 \
64 return ret; \
65}
66
67HPP__COLOR_FN(overhead, period)
68HPP__COLOR_FN(overhead_sys, period_sys)
69HPP__COLOR_FN(overhead_us, period_us)
70HPP__COLOR_FN(overhead_guest_sys, period_guest_sys)
71HPP__COLOR_FN(overhead_guest_us, period_guest_us)
72
73#undef HPP__COLOR_FN
74
75void perf_gtk__init_hpp(void)
76{
77 perf_hpp__init();
78
79 perf_hpp__format[PERF_HPP__OVERHEAD].color =
80 perf_gtk__hpp_color_overhead;
81 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
82 perf_gtk__hpp_color_overhead_sys;
83 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
84 perf_gtk__hpp_color_overhead_us;
85 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
86 perf_gtk__hpp_color_overhead_guest_sys;
87 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
88 perf_gtk__hpp_color_overhead_guest_us;
89}
90
91static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
92{
93 GType col_types[MAX_COLUMNS];
94 GtkCellRenderer *renderer;
95 struct sort_entry *se;
96 GtkListStore *store;
97 struct rb_node *nd;
98 GtkWidget *view;
99 int i, col_idx;
100 int nr_cols;
101 char s[512];
102
103 struct perf_hpp hpp = {
104 .buf = s,
105 .size = sizeof(s),
106 };
107
108 nr_cols = 0;
109
110 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
111 if (!perf_hpp__format[i].cond)
112 continue;
113
114 col_types[nr_cols++] = G_TYPE_STRING;
115 }
116
117 list_for_each_entry(se, &hist_entry__sort_list, list) {
118 if (se->elide)
119 continue;
120
121 col_types[nr_cols++] = G_TYPE_STRING;
122 }
123
124 store = gtk_list_store_newv(nr_cols, col_types);
125
126 view = gtk_tree_view_new();
127
128 renderer = gtk_cell_renderer_text_new();
129
130 col_idx = 0;
131
132 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
133 if (!perf_hpp__format[i].cond)
134 continue;
135
136 perf_hpp__format[i].header(&hpp);
137
138 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
139 -1, s,
140 renderer, "markup",
141 col_idx++, NULL);
142 }
143
144 list_for_each_entry(se, &hist_entry__sort_list, list) {
145 if (se->elide)
146 continue;
147
148 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
149 -1, se->se_header,
150 renderer, "text",
151 col_idx++, NULL);
152 }
153
154 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
155
156 g_object_unref(GTK_TREE_MODEL(store));
157
158 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
159 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
160 GtkTreeIter iter;
161
162 if (h->filtered)
163 continue;
164
165 gtk_list_store_append(store, &iter);
166
167 col_idx = 0;
168
169 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
170 if (!perf_hpp__format[i].cond)
171 continue;
172
173 if (perf_hpp__format[i].color)
174 perf_hpp__format[i].color(&hpp, h);
175 else
176 perf_hpp__format[i].entry(&hpp, h);
177
178 gtk_list_store_set(store, &iter, col_idx++, s, -1);
179 }
180
181 list_for_each_entry(se, &hist_entry__sort_list, list) {
182 if (se->elide)
183 continue;
184
185 se->se_snprintf(h, s, ARRAY_SIZE(s),
186 hists__col_len(hists, se->se_width_idx));
187
188 gtk_list_store_set(store, &iter, col_idx++, s, -1);
189 }
190 }
191
192 gtk_container_add(GTK_CONTAINER(window), view);
193}
194
195#ifdef HAVE_GTK_INFO_BAR 46#ifdef HAVE_GTK_INFO_BAR
196static GtkWidget *perf_gtk__setup_info_bar(void) 47GtkWidget *perf_gtk__setup_info_bar(void)
197{ 48{
198 GtkWidget *info_bar; 49 GtkWidget *info_bar;
199 GtkWidget *label; 50 GtkWidget *label;
@@ -220,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void)
220} 71}
221#endif 72#endif
222 73
223static GtkWidget *perf_gtk__setup_statusbar(void) 74GtkWidget *perf_gtk__setup_statusbar(void)
224{ 75{
225 GtkWidget *stbar; 76 GtkWidget *stbar;
226 unsigned ctxid; 77 unsigned ctxid;
@@ -234,81 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void)
234 85
235 return stbar; 86 return stbar;
236} 87}
237
238int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
239 const char *help,
240 void (*timer) (void *arg)__maybe_unused,
241 void *arg __maybe_unused,
242 int delay_secs __maybe_unused)
243{
244 struct perf_evsel *pos;
245 GtkWidget *vbox;
246 GtkWidget *notebook;
247 GtkWidget *info_bar;
248 GtkWidget *statbar;
249 GtkWidget *window;
250
251 signal(SIGSEGV, perf_gtk__signal);
252 signal(SIGFPE, perf_gtk__signal);
253 signal(SIGINT, perf_gtk__signal);
254 signal(SIGQUIT, perf_gtk__signal);
255 signal(SIGTERM, perf_gtk__signal);
256
257 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
258
259 gtk_window_set_title(GTK_WINDOW(window), "perf report");
260
261 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
262
263 pgctx = perf_gtk__activate_context(window);
264 if (!pgctx)
265 return -1;
266
267 vbox = gtk_vbox_new(FALSE, 0);
268
269 notebook = gtk_notebook_new();
270
271 list_for_each_entry(pos, &evlist->entries, node) {
272 struct hists *hists = &pos->hists;
273 const char *evname = perf_evsel__name(pos);
274 GtkWidget *scrolled_window;
275 GtkWidget *tab_label;
276
277 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
278
279 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
280 GTK_POLICY_AUTOMATIC,
281 GTK_POLICY_AUTOMATIC);
282
283 perf_gtk__show_hists(scrolled_window, hists);
284
285 tab_label = gtk_label_new(evname);
286
287 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
288 }
289
290 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
291
292 info_bar = perf_gtk__setup_info_bar();
293 if (info_bar)
294 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
295
296 statbar = perf_gtk__setup_statusbar();
297 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
298
299 gtk_container_add(GTK_CONTAINER(window), vbox);
300
301 gtk_widget_show_all(window);
302
303 perf_gtk__resize_window(window);
304
305 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
306
307 ui_helpline__push(help);
308
309 gtk_main();
310
311 perf_gtk__deactivate_context(&pgctx);
312
313 return 0;
314}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 687af0bba187..3d96785ef155 100644
--- a/tools/perf/ui/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
@@ -10,6 +10,7 @@
10 10
11struct perf_gtk_context { 11struct perf_gtk_context {
12 GtkWidget *main_window; 12 GtkWidget *main_window;
13 GtkWidget *notebook;
13 14
14#ifdef HAVE_GTK_INFO_BAR 15#ifdef HAVE_GTK_INFO_BAR
15 GtkWidget *info_bar; 16 GtkWidget *info_bar;
@@ -30,9 +31,17 @@ struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
30int perf_gtk__deactivate_context(struct perf_gtk_context **ctx); 31int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
31 32
32void perf_gtk__init_helpline(void); 33void perf_gtk__init_helpline(void);
34void perf_gtk__init_progress(void);
33void perf_gtk__init_hpp(void); 35void perf_gtk__init_hpp(void);
34 36
35#ifndef HAVE_GTK_INFO_BAR 37void perf_gtk__signal(int sig);
38void perf_gtk__resize_window(GtkWidget *window);
39const char *perf_gtk__get_percent_color(double percent);
40GtkWidget *perf_gtk__setup_statusbar(void);
41
42#ifdef HAVE_GTK_INFO_BAR
43GtkWidget *perf_gtk__setup_info_bar(void);
44#else
36static inline GtkWidget *perf_gtk__setup_info_bar(void) 45static inline GtkWidget *perf_gtk__setup_info_bar(void)
37{ 46{
38 return NULL; 47 return NULL;
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c
index 5db4432ff12a..3388cbd12186 100644
--- a/tools/perf/ui/gtk/helpline.c
+++ b/tools/perf/ui/gtk/helpline.c
@@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg)
24 pgctx->statbar_ctx_id, msg); 24 pgctx->statbar_ctx_id, msg);
25} 25}
26 26
27static struct ui_helpline gtk_helpline_fns = { 27static int gtk_helpline_show(const char *fmt, va_list ap)
28 .pop = gtk_helpline_pop,
29 .push = gtk_helpline_push,
30};
31
32void perf_gtk__init_helpline(void)
33{
34 helpline_fns = &gtk_helpline_fns;
35}
36
37int perf_gtk__show_helpline(const char *fmt, va_list ap)
38{ 28{
39 int ret; 29 int ret;
40 char *ptr; 30 char *ptr;
@@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap)
54 44
55 return ret; 45 return ret;
56} 46}
47
48static struct ui_helpline gtk_helpline_fns = {
49 .pop = gtk_helpline_pop,
50 .push = gtk_helpline_push,
51 .show = gtk_helpline_show,
52};
53
54void perf_gtk__init_helpline(void)
55{
56 helpline_fns = &gtk_helpline_fns;
57}
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
new file mode 100644
index 000000000000..1e764a8ad259
--- /dev/null
+++ b/tools/perf/ui/gtk/hists.c
@@ -0,0 +1,312 @@
1#include "../evlist.h"
2#include "../cache.h"
3#include "../evsel.h"
4#include "../sort.h"
5#include "../hist.h"
6#include "../helpline.h"
7#include "gtk.h"
8
9#define MAX_COLUMNS 32
10
11static int __percent_color_snprintf(char *buf, size_t size, double percent)
12{
13 int ret = 0;
14 const char *markup;
15
16 markup = perf_gtk__get_percent_color(percent);
17 if (markup)
18 ret += scnprintf(buf, size, markup);
19
20 ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent);
21
22 if (markup)
23 ret += scnprintf(buf + ret, size - ret, "</span>");
24
25 return ret;
26}
27
28
29static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he,
30 u64 (*get_field)(struct hist_entry *))
31{
32 int ret;
33 double percent = 0.0;
34 struct hists *hists = he->hists;
35
36 if (hists->stats.total_period)
37 percent = 100.0 * get_field(he) / hists->stats.total_period;
38
39 ret = __percent_color_snprintf(hpp->buf, hpp->size, percent);
40
41 if (symbol_conf.event_group) {
42 int prev_idx, idx_delta;
43 struct perf_evsel *evsel = hists_to_evsel(hists);
44 struct hist_entry *pair;
45 int nr_members = evsel->nr_members;
46
47 if (nr_members <= 1)
48 return ret;
49
50 prev_idx = perf_evsel__group_idx(evsel);
51
52 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
53 u64 period = get_field(pair);
54 u64 total = pair->hists->stats.total_period;
55
56 evsel = hists_to_evsel(pair->hists);
57 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
58
59 while (idx_delta--) {
60 /*
61 * zero-fill group members in the middle which
62 * have no sample
63 */
64 ret += __percent_color_snprintf(hpp->buf + ret,
65 hpp->size - ret,
66 0.0);
67 }
68
69 percent = 100.0 * period / total;
70 ret += __percent_color_snprintf(hpp->buf + ret,
71 hpp->size - ret,
72 percent);
73
74 prev_idx = perf_evsel__group_idx(evsel);
75 }
76
77 idx_delta = nr_members - prev_idx - 1;
78
79 while (idx_delta--) {
80 /*
81 * zero-fill group members at last which have no sample
82 */
83 ret += __percent_color_snprintf(hpp->buf + ret,
84 hpp->size - ret,
85 0.0);
86 }
87 }
88 return ret;
89}
90
91#define __HPP_COLOR_PERCENT_FN(_type, _field) \
92static u64 he_get_##_field(struct hist_entry *he) \
93{ \
94 return he->stat._field; \
95} \
96 \
97static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \
98 struct hist_entry *he) \
99{ \
100 return __hpp__color_fmt(hpp, he, he_get_##_field); \
101}
102
103__HPP_COLOR_PERCENT_FN(overhead, period)
104__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
105__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
106__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
107__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
108
109#undef __HPP_COLOR_PERCENT_FN
110
111
112void perf_gtk__init_hpp(void)
113{
114 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
115
116 perf_hpp__init();
117
118 perf_hpp__format[PERF_HPP__OVERHEAD].color =
119 perf_gtk__hpp_color_overhead;
120 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
121 perf_gtk__hpp_color_overhead_sys;
122 perf_hpp__format[PERF_HPP__OVERHEAD_US].color =
123 perf_gtk__hpp_color_overhead_us;
124 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color =
125 perf_gtk__hpp_color_overhead_guest_sys;
126 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
127 perf_gtk__hpp_color_overhead_guest_us;
128}
129
130static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
131{
132 struct perf_hpp_fmt *fmt;
133 GType col_types[MAX_COLUMNS];
134 GtkCellRenderer *renderer;
135 struct sort_entry *se;
136 GtkListStore *store;
137 struct rb_node *nd;
138 GtkWidget *view;
139 int col_idx;
140 int nr_cols;
141 char s[512];
142
143 struct perf_hpp hpp = {
144 .buf = s,
145 .size = sizeof(s),
146 .ptr = hists_to_evsel(hists),
147 };
148
149 nr_cols = 0;
150
151 perf_hpp__for_each_format(fmt)
152 col_types[nr_cols++] = G_TYPE_STRING;
153
154 list_for_each_entry(se, &hist_entry__sort_list, list) {
155 if (se->elide)
156 continue;
157
158 col_types[nr_cols++] = G_TYPE_STRING;
159 }
160
161 store = gtk_list_store_newv(nr_cols, col_types);
162
163 view = gtk_tree_view_new();
164
165 renderer = gtk_cell_renderer_text_new();
166
167 col_idx = 0;
168
169 perf_hpp__for_each_format(fmt) {
170 fmt->header(&hpp);
171
172 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
173 -1, ltrim(s),
174 renderer, "markup",
175 col_idx++, NULL);
176 }
177
178 list_for_each_entry(se, &hist_entry__sort_list, list) {
179 if (se->elide)
180 continue;
181
182 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
183 -1, se->se_header,
184 renderer, "text",
185 col_idx++, NULL);
186 }
187
188 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
189
190 g_object_unref(GTK_TREE_MODEL(store));
191
192 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
193 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
194 GtkTreeIter iter;
195
196 if (h->filtered)
197 continue;
198
199 gtk_list_store_append(store, &iter);
200
201 col_idx = 0;
202
203 perf_hpp__for_each_format(fmt) {
204 if (fmt->color)
205 fmt->color(&hpp, h);
206 else
207 fmt->entry(&hpp, h);
208
209 gtk_list_store_set(store, &iter, col_idx++, s, -1);
210 }
211
212 list_for_each_entry(se, &hist_entry__sort_list, list) {
213 if (se->elide)
214 continue;
215
216 se->se_snprintf(h, s, ARRAY_SIZE(s),
217 hists__col_len(hists, se->se_width_idx));
218
219 gtk_list_store_set(store, &iter, col_idx++, s, -1);
220 }
221 }
222
223 gtk_container_add(GTK_CONTAINER(window), view);
224}
225
226int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
227 const char *help,
228 struct hist_browser_timer *hbt __maybe_unused)
229{
230 struct perf_evsel *pos;
231 GtkWidget *vbox;
232 GtkWidget *notebook;
233 GtkWidget *info_bar;
234 GtkWidget *statbar;
235 GtkWidget *window;
236
237 signal(SIGSEGV, perf_gtk__signal);
238 signal(SIGFPE, perf_gtk__signal);
239 signal(SIGINT, perf_gtk__signal);
240 signal(SIGQUIT, perf_gtk__signal);
241 signal(SIGTERM, perf_gtk__signal);
242
243 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
244
245 gtk_window_set_title(GTK_WINDOW(window), "perf report");
246
247 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
248
249 pgctx = perf_gtk__activate_context(window);
250 if (!pgctx)
251 return -1;
252
253 vbox = gtk_vbox_new(FALSE, 0);
254
255 notebook = gtk_notebook_new();
256
257 gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
258
259 info_bar = perf_gtk__setup_info_bar();
260 if (info_bar)
261 gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0);
262
263 statbar = perf_gtk__setup_statusbar();
264 gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0);
265
266 gtk_container_add(GTK_CONTAINER(window), vbox);
267
268 list_for_each_entry(pos, &evlist->entries, node) {
269 struct hists *hists = &pos->hists;
270 const char *evname = perf_evsel__name(pos);
271 GtkWidget *scrolled_window;
272 GtkWidget *tab_label;
273 char buf[512];
274 size_t size = sizeof(buf);
275
276 if (symbol_conf.event_group) {
277 if (!perf_evsel__is_group_leader(pos))
278 continue;
279
280 if (pos->nr_members > 1) {
281 perf_evsel__group_desc(pos, buf, size);
282 evname = buf;
283 }
284 }
285
286 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
287
288 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
289 GTK_POLICY_AUTOMATIC,
290 GTK_POLICY_AUTOMATIC);
291
292 perf_gtk__show_hists(scrolled_window, hists);
293
294 tab_label = gtk_label_new(evname);
295
296 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
297 }
298
299 gtk_widget_show_all(window);
300
301 perf_gtk__resize_window(window);
302
303 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
304
305 ui_helpline__push(help);
306
307 gtk_main();
308
309 perf_gtk__deactivate_context(&pgctx);
310
311 return 0;
312}
diff --git a/tools/perf/ui/gtk/progress.c b/tools/perf/ui/gtk/progress.c
new file mode 100644
index 000000000000..482bcf3df9b7
--- /dev/null
+++ b/tools/perf/ui/gtk/progress.c
@@ -0,0 +1,59 @@
1#include <inttypes.h>
2
3#include "gtk.h"
4#include "../progress.h"
5#include "util.h"
6
7static GtkWidget *dialog;
8static GtkWidget *progress;
9
10static void gtk_progress_update(u64 curr, u64 total, const char *title)
11{
12 double fraction = total ? 1.0 * curr / total : 0.0;
13 char buf[1024];
14
15 if (dialog == NULL) {
16 GtkWidget *vbox = gtk_vbox_new(TRUE, 5);
17 GtkWidget *label = gtk_label_new(title);
18
19 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
20 progress = gtk_progress_bar_new();
21
22 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, FALSE, 3);
23 gtk_box_pack_start(GTK_BOX(vbox), progress, TRUE, TRUE, 3);
24
25 gtk_container_add(GTK_CONTAINER(dialog), vbox);
26
27 gtk_window_set_title(GTK_WINDOW(dialog), "perf");
28 gtk_window_resize(GTK_WINDOW(dialog), 300, 80);
29 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
30
31 gtk_widget_show_all(dialog);
32 }
33
34 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
35 snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, curr, total);
36 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf);
37
38 /* we didn't call gtk_main yet, so do it manually */
39 while (gtk_events_pending())
40 gtk_main_iteration();
41}
42
43static void gtk_progress_finish(void)
44{
45 /* this will also destroy all of its children */
46 gtk_widget_destroy(dialog);
47
48 dialog = NULL;
49}
50
51static struct ui_progress gtk_progress_fns = {
52 .update = gtk_progress_update,
53 .finish = gtk_progress_finish,
54};
55
56void perf_gtk__init_progress(void)
57{
58 progress_fns = &gtk_progress_fns;
59}
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
index 3c4c6ef78283..6c2dd2e423f3 100644
--- a/tools/perf/ui/gtk/setup.c
+++ b/tools/perf/ui/gtk/setup.c
@@ -8,7 +8,9 @@ int perf_gtk__init(void)
8{ 8{
9 perf_error__register(&perf_gtk_eops); 9 perf_error__register(&perf_gtk_eops);
10 perf_gtk__init_helpline(); 10 perf_gtk__init_helpline();
11 perf_gtk__init_progress();
11 perf_gtk__init_hpp(); 12 perf_gtk__init_hpp();
13
12 return gtk_init_check(NULL, NULL) ? 0 : -1; 14 return gtk_init_check(NULL, NULL) ? 0 : -1;
13} 15}
14 16
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c
index ccb046aac98b..c06942a41c78 100644
--- a/tools/perf/ui/gtk/util.c
+++ b/tools/perf/ui/gtk/util.c
@@ -111,14 +111,3 @@ struct perf_error_ops perf_gtk_eops = {
111 .warning = perf_gtk__warning_statusbar, 111 .warning = perf_gtk__warning_statusbar,
112#endif 112#endif
113}; 113};
114
115/*
116 * FIXME: Functions below should be implemented properly.
117 * For now, just add stubs for NO_NEWT=1 build.
118 */
119#ifndef NEWT_SUPPORT
120void ui_progress__update(u64 curr __maybe_unused, u64 total __maybe_unused,
121 const char *title __maybe_unused)
122{
123}
124#endif
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c
index a49bcf3c190b..700fb3cfa1c7 100644
--- a/tools/perf/ui/helpline.c
+++ b/tools/perf/ui/helpline.c
@@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused)
16{ 16{
17} 17}
18 18
19static int nop_helpline__show(const char *fmt __maybe_unused,
20 va_list ap __maybe_unused)
21{
22 return 0;
23}
24
19static struct ui_helpline default_helpline_fns = { 25static struct ui_helpline default_helpline_fns = {
20 .pop = nop_helpline__pop, 26 .pop = nop_helpline__pop,
21 .push = nop_helpline__push, 27 .push = nop_helpline__push,
28 .show = nop_helpline__show,
22}; 29};
23 30
24struct ui_helpline *helpline_fns = &default_helpline_fns; 31struct ui_helpline *helpline_fns = &default_helpline_fns;
@@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg)
59 ui_helpline__pop(); 66 ui_helpline__pop();
60 ui_helpline__push(msg); 67 ui_helpline__push(msg);
61} 68}
69
70int ui_helpline__vshow(const char *fmt, va_list ap)
71{
72 return helpline_fns->show(fmt, ap);
73}
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h
index baa28a4d16b9..46181f4fc07e 100644
--- a/tools/perf/ui/helpline.h
+++ b/tools/perf/ui/helpline.h
@@ -9,6 +9,7 @@
9struct ui_helpline { 9struct ui_helpline {
10 void (*pop)(void); 10 void (*pop)(void);
11 void (*push)(const char *msg); 11 void (*push)(const char *msg);
12 int (*show)(const char *fmt, va_list ap);
12}; 13};
13 14
14extern struct ui_helpline *helpline_fns; 15extern struct ui_helpline *helpline_fns;
@@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg);
20void ui_helpline__vpush(const char *fmt, va_list ap); 21void ui_helpline__vpush(const char *fmt, va_list ap);
21void ui_helpline__fpush(const char *fmt, ...); 22void ui_helpline__fpush(const char *fmt, ...);
22void ui_helpline__puts(const char *msg); 23void ui_helpline__puts(const char *msg);
24int ui_helpline__vshow(const char *fmt, va_list ap);
23 25
24extern char ui_helpline__current[512]; 26extern char ui_helpline__current[512];
25
26#ifdef NEWT_SUPPORT
27extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
28int ui_helpline__show_help(const char *format, va_list ap);
29#else
30static inline int ui_helpline__show_help(const char *format __maybe_unused,
31 va_list ap __maybe_unused)
32{
33 return 0;
34}
35#endif /* NEWT_SUPPORT */
36
37#ifdef GTK2_SUPPORT
38int perf_gtk__show_helpline(const char *format, va_list ap);
39#else
40static inline int perf_gtk__show_helpline(const char *format __maybe_unused,
41 va_list ap __maybe_unused)
42{
43 return 0;
44}
45#endif /* GTK2_SUPPORT */
46 28
47#endif /* _PERF_UI_HELPLINE_H_ */ 29#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index f5a1e4f65263..d671e63aa351 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -3,151 +3,163 @@
3#include "../util/hist.h" 3#include "../util/hist.h"
4#include "../util/util.h" 4#include "../util/util.h"
5#include "../util/sort.h" 5#include "../util/sort.h"
6 6#include "../util/evsel.h"
7 7
8/* hist period print (hpp) functions */ 8/* hist period print (hpp) functions */
9static int hpp__header_overhead(struct perf_hpp *hpp)
10{
11 return scnprintf(hpp->buf, hpp->size, "Overhead");
12}
13 9
14static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) 10typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
15{
16 return 8;
17}
18 11
19static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) 12static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
13 u64 (*get_field)(struct hist_entry *),
14 const char *fmt, hpp_snprint_fn print_fn,
15 bool fmt_percent)
20{ 16{
17 int ret;
21 struct hists *hists = he->hists; 18 struct hists *hists = he->hists;
22 double percent = 100.0 * he->stat.period / hists->stats.total_period;
23 19
24 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 20 if (fmt_percent) {
25} 21 double percent = 0.0;
26 22
27static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) 23 if (hists->stats.total_period)
28{ 24 percent = 100.0 * get_field(he) /
29 struct hists *hists = he->hists; 25 hists->stats.total_period;
30 double percent = 100.0 * he->stat.period / hists->stats.total_period;
31 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
32 26
33 return scnprintf(hpp->buf, hpp->size, fmt, percent); 27 ret = print_fn(hpp->buf, hpp->size, fmt, percent);
34} 28 } else
29 ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
35 30
36static int hpp__header_overhead_sys(struct perf_hpp *hpp) 31 if (symbol_conf.event_group) {
37{ 32 int prev_idx, idx_delta;
38 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 33 struct perf_evsel *evsel = hists_to_evsel(hists);
34 struct hist_entry *pair;
35 int nr_members = evsel->nr_members;
39 36
40 return scnprintf(hpp->buf, hpp->size, fmt, "sys"); 37 if (nr_members <= 1)
41} 38 return ret;
42 39
43static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) 40 prev_idx = perf_evsel__group_idx(evsel);
44{
45 return 7;
46}
47 41
48static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) 42 list_for_each_entry(pair, &he->pairs.head, pairs.node) {
49{ 43 u64 period = get_field(pair);
50 struct hists *hists = he->hists; 44 u64 total = pair->hists->stats.total_period;
51 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
52 45
53 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); 46 if (!total)
54} 47 continue;
55 48
56static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) 49 evsel = hists_to_evsel(pair->hists);
57{ 50 idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1;
58 struct hists *hists = he->hists;
59 double percent = 100.0 * he->stat.period_sys / hists->stats.total_period;
60 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
61 51
62 return scnprintf(hpp->buf, hpp->size, fmt, percent); 52 while (idx_delta--) {
63} 53 /*
54 * zero-fill group members in the middle which
55 * have no sample
56 */
57 ret += print_fn(hpp->buf + ret, hpp->size - ret,
58 fmt, 0);
59 }
64 60
65static int hpp__header_overhead_us(struct perf_hpp *hpp) 61 if (fmt_percent)
66{ 62 ret += print_fn(hpp->buf + ret, hpp->size - ret,
67 const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; 63 fmt, 100.0 * period / total);
68 64 else
69 return scnprintf(hpp->buf, hpp->size, fmt, "user"); 65 ret += print_fn(hpp->buf + ret, hpp->size - ret,
70} 66 fmt, period);
71 67
72static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) 68 prev_idx = perf_evsel__group_idx(evsel);
73{ 69 }
74 return 7;
75}
76
77static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
78{
79 struct hists *hists = he->hists;
80 double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
81
82 return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
83}
84
85static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
86{
87 struct hists *hists = he->hists;
88 double percent = 100.0 * he->stat.period_us / hists->stats.total_period;
89 const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
90
91 return scnprintf(hpp->buf, hpp->size, fmt, percent);
92}
93
94static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp)
95{
96 return scnprintf(hpp->buf, hpp->size, "guest sys");
97}
98
99static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused)
100{
101 return 9;
102}
103
104static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
105 struct hist_entry *he)
106{
107 struct hists *hists = he->hists;
108 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
109
110 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
111}
112
113static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
114 struct hist_entry *he)
115{
116 struct hists *hists = he->hists;
117 double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period;
118 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
119 70
120 return scnprintf(hpp->buf, hpp->size, fmt, percent); 71 idx_delta = nr_members - prev_idx - 1;
121}
122 72
123static int hpp__header_overhead_guest_us(struct perf_hpp *hpp) 73 while (idx_delta--) {
124{ 74 /*
125 return scnprintf(hpp->buf, hpp->size, "guest usr"); 75 * zero-fill group members at last which have no sample
126} 76 */
127 77 ret += print_fn(hpp->buf + ret, hpp->size - ret,
128static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) 78 fmt, 0);
129{ 79 }
130 return 9; 80 }
81 return ret;
131} 82}
132 83
133static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, 84#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
134 struct hist_entry *he) 85static int hpp__header_##_type(struct perf_hpp *hpp) \
135{ 86{ \
136 struct hists *hists = he->hists; 87 int len = _min_width; \
137 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; 88 \
138 89 if (symbol_conf.event_group) { \
139 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); 90 struct perf_evsel *evsel = hpp->ptr; \
140} 91 \
92 len = max(len, evsel->nr_members * _unit_width); \
93 } \
94 return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \
95}
96
97#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
98static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \
99{ \
100 int len = _min_width; \
101 \
102 if (symbol_conf.event_group) { \
103 struct perf_evsel *evsel = hpp->ptr; \
104 \
105 len = max(len, evsel->nr_members * _unit_width); \
106 } \
107 return len; \
108}
109
110#define __HPP_COLOR_PERCENT_FN(_type, _field) \
111static u64 he_get_##_field(struct hist_entry *he) \
112{ \
113 return he->stat._field; \
114} \
115 \
116static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
117{ \
118 return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
119 (hpp_snprint_fn)percent_color_snprintf, true); \
120}
121
122#define __HPP_ENTRY_PERCENT_FN(_type, _field) \
123static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
124{ \
125 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
126 return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
127 scnprintf, true); \
128}
129
130#define __HPP_ENTRY_RAW_FN(_type, _field) \
131static u64 he_get_raw_##_field(struct hist_entry *he) \
132{ \
133 return he->stat._field; \
134} \
135 \
136static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
137{ \
138 const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
139 return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
140}
141
142#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
143__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
144__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
145__HPP_COLOR_PERCENT_FN(_type, _field) \
146__HPP_ENTRY_PERCENT_FN(_type, _field)
147
148#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
149__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
150__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
151__HPP_ENTRY_RAW_FN(_type, _field)
152
153
154HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
155HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
156HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
157HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
158HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
159
160HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
161HPP_RAW_FNS(period, "Period", period, 12, 12)
141 162
142static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
143 struct hist_entry *he)
144{
145 struct hists *hists = he->hists;
146 double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period;
147 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
148
149 return scnprintf(hpp->buf, hpp->size, fmt, percent);
150}
151 163
152static int hpp__header_baseline(struct perf_hpp *hpp) 164static int hpp__header_baseline(struct perf_hpp *hpp)
153{ 165{
@@ -161,7 +173,7 @@ static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
161 173
162static double baseline_percent(struct hist_entry *he) 174static double baseline_percent(struct hist_entry *he)
163{ 175{
164 struct hist_entry *pair = he->pair; 176 struct hist_entry *pair = hist_entry__next_pair(he);
165 struct hists *pair_hists = pair ? pair->hists : NULL; 177 struct hists *pair_hists = pair ? pair->hists : NULL;
166 double percent = 0.0; 178 double percent = 0.0;
167 179
@@ -179,7 +191,10 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
179{ 191{
180 double percent = baseline_percent(he); 192 double percent = baseline_percent(he);
181 193
182 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); 194 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
195 return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
196 else
197 return scnprintf(hpp->buf, hpp->size, " ");
183} 198}
184 199
185static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) 200static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
@@ -187,45 +202,31 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
187 double percent = baseline_percent(he); 202 double percent = baseline_percent(he);
188 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; 203 const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
189 204
190 return scnprintf(hpp->buf, hpp->size, fmt, percent); 205 if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
191} 206 return scnprintf(hpp->buf, hpp->size, fmt, percent);
192 207 else
193static int hpp__header_samples(struct perf_hpp *hpp) 208 return scnprintf(hpp->buf, hpp->size, " ");
194{
195 const char *fmt = symbol_conf.field_sep ? "%s" : "%11s";
196
197 return scnprintf(hpp->buf, hpp->size, fmt, "Samples");
198}
199
200static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused)
201{
202 return 11;
203} 209}
204 210
205static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he) 211static int hpp__header_period_baseline(struct perf_hpp *hpp)
206{
207 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64;
208
209 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events);
210}
211
212static int hpp__header_period(struct perf_hpp *hpp)
213{ 212{
214 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; 213 const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
215 214
216 return scnprintf(hpp->buf, hpp->size, fmt, "Period"); 215 return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
217} 216}
218 217
219static int hpp__width_period(struct perf_hpp *hpp __maybe_unused) 218static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
220{ 219{
221 return 12; 220 return 12;
222} 221}
223 222
224static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) 223static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
225{ 224{
225 struct hist_entry *pair = hist_entry__next_pair(he);
226 u64 period = pair ? pair->stat.period : 0;
226 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; 227 const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
227 228
228 return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); 229 return scnprintf(hpp->buf, hpp->size, fmt, period);
229} 230}
230 231
231static int hpp__header_delta(struct perf_hpp *hpp) 232static int hpp__header_delta(struct perf_hpp *hpp)
@@ -242,104 +243,188 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
242 243
243static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) 244static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
244{ 245{
245 struct hist_entry *pair = he->pair; 246 struct hist_entry *pair = hist_entry__next_pair(he);
246 struct hists *pair_hists = pair ? pair->hists : NULL;
247 struct hists *hists = he->hists;
248 u64 old_total, new_total;
249 double old_percent = 0, new_percent = 0;
250 double diff;
251 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; 247 const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
252 char buf[32] = " "; 248 char buf[32] = " ";
249 double diff = 0.0;
253 250
254 old_total = pair_hists ? pair_hists->stats.total_period : 0; 251 if (pair) {
255 if (old_total > 0 && pair) 252 if (he->diff.computed)
256 old_percent = 100.0 * pair->stat.period / old_total; 253 diff = he->diff.period_ratio_delta;
257 254 else
258 new_total = hists->stats.total_period; 255 diff = perf_diff__compute_delta(he, pair);
259 if (new_total > 0) 256 } else
260 new_percent = 100.0 * he->stat.period / new_total; 257 diff = perf_diff__period_percent(he, he->stat.period);
261 258
262 diff = new_percent - old_percent;
263 if (fabs(diff) >= 0.01) 259 if (fabs(diff) >= 0.01)
264 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); 260 scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
265 261
266 return scnprintf(hpp->buf, hpp->size, fmt, buf); 262 return scnprintf(hpp->buf, hpp->size, fmt, buf);
267} 263}
268 264
269static int hpp__header_displ(struct perf_hpp *hpp) 265static int hpp__header_ratio(struct perf_hpp *hpp)
266{
267 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
268
269 return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
270}
271
272static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
273{
274 return 14;
275}
276
277static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
278{
279 struct hist_entry *pair = hist_entry__next_pair(he);
280 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
281 char buf[32] = " ";
282 double ratio = 0.0;
283
284 if (pair) {
285 if (he->diff.computed)
286 ratio = he->diff.period_ratio;
287 else
288 ratio = perf_diff__compute_ratio(he, pair);
289 }
290
291 if (ratio > 0.0)
292 scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
293
294 return scnprintf(hpp->buf, hpp->size, fmt, buf);
295}
296
297static int hpp__header_wdiff(struct perf_hpp *hpp)
270{ 298{
271 return scnprintf(hpp->buf, hpp->size, "Displ."); 299 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
300
301 return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
272} 302}
273 303
274static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) 304static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
275{ 305{
276 return 6; 306 return 14;
277} 307}
278 308
279static int hpp__entry_displ(struct perf_hpp *hpp, 309static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
280 struct hist_entry *he)
281{ 310{
282 struct hist_entry *pair = he->pair; 311 struct hist_entry *pair = hist_entry__next_pair(he);
283 long displacement = pair ? pair->position - he->position : 0; 312 const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
284 const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s";
285 char buf[32] = " "; 313 char buf[32] = " ";
314 s64 wdiff = 0;
315
316 if (pair) {
317 if (he->diff.computed)
318 wdiff = he->diff.wdiff;
319 else
320 wdiff = perf_diff__compute_wdiff(he, pair);
321 }
322
323 if (wdiff != 0)
324 scnprintf(buf, sizeof(buf), "%14ld", wdiff);
325
326 return scnprintf(hpp->buf, hpp->size, fmt, buf);
327}
328
329static int hpp__header_formula(struct perf_hpp *hpp)
330{
331 const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
332
333 return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
334}
335
336static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
337{
338 return 70;
339}
340
341static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
342{
343 struct hist_entry *pair = hist_entry__next_pair(he);
344 const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
345 char buf[96] = " ";
286 346
287 if (displacement) 347 if (pair)
288 scnprintf(buf, sizeof(buf), "%+4ld", displacement); 348 perf_diff__formula(he, pair, buf, sizeof(buf));
289 349
290 return scnprintf(hpp->buf, hpp->size, fmt, buf); 350 return scnprintf(hpp->buf, hpp->size, fmt, buf);
291} 351}
292 352
293#define HPP__COLOR_PRINT_FNS(_name) \ 353#define HPP__COLOR_PRINT_FNS(_name) \
294 .header = hpp__header_ ## _name, \ 354 { \
295 .width = hpp__width_ ## _name, \ 355 .header = hpp__header_ ## _name, \
296 .color = hpp__color_ ## _name, \ 356 .width = hpp__width_ ## _name, \
297 .entry = hpp__entry_ ## _name 357 .color = hpp__color_ ## _name, \
358 .entry = hpp__entry_ ## _name \
359 }
298 360
299#define HPP__PRINT_FNS(_name) \ 361#define HPP__PRINT_FNS(_name) \
300 .header = hpp__header_ ## _name, \ 362 { \
301 .width = hpp__width_ ## _name, \ 363 .header = hpp__header_ ## _name, \
302 .entry = hpp__entry_ ## _name 364 .width = hpp__width_ ## _name, \
365 .entry = hpp__entry_ ## _name \
366 }
303 367
304struct perf_hpp_fmt perf_hpp__format[] = { 368struct perf_hpp_fmt perf_hpp__format[] = {
305 { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, 369 HPP__COLOR_PRINT_FNS(baseline),
306 { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, 370 HPP__COLOR_PRINT_FNS(overhead),
307 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, 371 HPP__COLOR_PRINT_FNS(overhead_sys),
308 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, 372 HPP__COLOR_PRINT_FNS(overhead_us),
309 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, 373 HPP__COLOR_PRINT_FNS(overhead_guest_sys),
310 { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, 374 HPP__COLOR_PRINT_FNS(overhead_guest_us),
311 { .cond = false, HPP__PRINT_FNS(samples) }, 375 HPP__PRINT_FNS(samples),
312 { .cond = false, HPP__PRINT_FNS(period) }, 376 HPP__PRINT_FNS(period),
313 { .cond = false, HPP__PRINT_FNS(delta) }, 377 HPP__PRINT_FNS(period_baseline),
314 { .cond = false, HPP__PRINT_FNS(displ) } 378 HPP__PRINT_FNS(delta),
379 HPP__PRINT_FNS(ratio),
380 HPP__PRINT_FNS(wdiff),
381 HPP__PRINT_FNS(formula)
315}; 382};
316 383
384LIST_HEAD(perf_hpp__list);
385
386
317#undef HPP__COLOR_PRINT_FNS 387#undef HPP__COLOR_PRINT_FNS
318#undef HPP__PRINT_FNS 388#undef HPP__PRINT_FNS
319 389
390#undef HPP_PERCENT_FNS
391#undef HPP_RAW_FNS
392
393#undef __HPP_HEADER_FN
394#undef __HPP_WIDTH_FN
395#undef __HPP_COLOR_PERCENT_FN
396#undef __HPP_ENTRY_PERCENT_FN
397#undef __HPP_ENTRY_RAW_FN
398
399
320void perf_hpp__init(void) 400void perf_hpp__init(void)
321{ 401{
322 if (symbol_conf.show_cpu_utilization) { 402 if (symbol_conf.show_cpu_utilization) {
323 perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; 403 perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
324 perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; 404 perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
325 405
326 if (perf_guest) { 406 if (perf_guest) {
327 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; 407 perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS);
328 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; 408 perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US);
329 } 409 }
330 } 410 }
331 411
332 if (symbol_conf.show_nr_samples) 412 if (symbol_conf.show_nr_samples)
333 perf_hpp__format[PERF_HPP__SAMPLES].cond = true; 413 perf_hpp__column_enable(PERF_HPP__SAMPLES);
334 414
335 if (symbol_conf.show_total_period) 415 if (symbol_conf.show_total_period)
336 perf_hpp__format[PERF_HPP__PERIOD].cond = true; 416 perf_hpp__column_enable(PERF_HPP__PERIOD);
417}
418
419void perf_hpp__column_register(struct perf_hpp_fmt *format)
420{
421 list_add_tail(&format->list, &perf_hpp__list);
337} 422}
338 423
339void perf_hpp__column_enable(unsigned col, bool enable) 424void perf_hpp__column_enable(unsigned col)
340{ 425{
341 BUG_ON(col >= PERF_HPP__MAX_INDEX); 426 BUG_ON(col >= PERF_HPP__MAX_INDEX);
342 perf_hpp__format[col].cond = enable; 427 perf_hpp__column_register(&perf_hpp__format[col]);
343} 428}
344 429
345static inline void advance_hpp(struct perf_hpp *hpp, int inc) 430static inline void advance_hpp(struct perf_hpp *hpp, int inc)
@@ -352,27 +437,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
352 bool color) 437 bool color)
353{ 438{
354 const char *sep = symbol_conf.field_sep; 439 const char *sep = symbol_conf.field_sep;
440 struct perf_hpp_fmt *fmt;
355 char *start = hpp->buf; 441 char *start = hpp->buf;
356 int i, ret; 442 int ret;
357 bool first = true; 443 bool first = true;
358 444
359 if (symbol_conf.exclude_other && !he->parent) 445 if (symbol_conf.exclude_other && !he->parent)
360 return 0; 446 return 0;
361 447
362 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 448 perf_hpp__for_each_format(fmt) {
363 if (!perf_hpp__format[i].cond) 449 /*
364 continue; 450 * If there's no field_sep, we still need
365 451 * to display initial ' '.
452 */
366 if (!sep || !first) { 453 if (!sep || !first) {
367 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 454 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
368 advance_hpp(hpp, ret); 455 advance_hpp(hpp, ret);
456 } else
369 first = false; 457 first = false;
370 }
371 458
372 if (color && perf_hpp__format[i].color) 459 if (color && fmt->color)
373 ret = perf_hpp__format[i].color(hpp, he); 460 ret = fmt->color(hpp, he);
374 else 461 else
375 ret = perf_hpp__format[i].entry(hpp, he); 462 ret = fmt->entry(hpp, he);
376 463
377 advance_hpp(hpp, ret); 464 advance_hpp(hpp, ret);
378 } 465 }
@@ -404,16 +491,18 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
404 */ 491 */
405unsigned int hists__sort_list_width(struct hists *hists) 492unsigned int hists__sort_list_width(struct hists *hists)
406{ 493{
494 struct perf_hpp_fmt *fmt;
407 struct sort_entry *se; 495 struct sort_entry *se;
408 int i, ret = 0; 496 int i = 0, ret = 0;
497 struct perf_hpp dummy_hpp = {
498 .ptr = hists_to_evsel(hists),
499 };
409 500
410 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 501 perf_hpp__for_each_format(fmt) {
411 if (!perf_hpp__format[i].cond)
412 continue;
413 if (i) 502 if (i)
414 ret += 2; 503 ret += 2;
415 504
416 ret += perf_hpp__format[i].width(NULL); 505 ret += fmt->width(&dummy_hpp);
417 } 506 }
418 507
419 list_for_each_entry(se, &hist_entry__sort_list, list) 508 list_for_each_entry(se, &hist_entry__sort_list, list)
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h
index 809eca5707fa..65092d576b4e 100644
--- a/tools/perf/ui/keysyms.h
+++ b/tools/perf/ui/keysyms.h
@@ -23,5 +23,6 @@
23#define K_TIMER -1 23#define K_TIMER -1
24#define K_ERROR -2 24#define K_ERROR -2
25#define K_RESIZE -3 25#define K_RESIZE -3
26#define K_SWITCH_INPUT_DATA -4
26 27
27#endif /* _PERF_KEYSYMS_H_ */ 28#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/ui/progress.c b/tools/perf/ui/progress.c
index 13aa64e50e11..3ec695607a4d 100644
--- a/tools/perf/ui/progress.c
+++ b/tools/perf/ui/progress.c
@@ -1,32 +1,26 @@
1#include "../cache.h" 1#include "../cache.h"
2#include "progress.h" 2#include "progress.h"
3#include "libslang.h"
4#include "ui.h"
5#include "browser.h"
6 3
7void ui_progress__update(u64 curr, u64 total, const char *title) 4static void nop_progress_update(u64 curr __maybe_unused,
5 u64 total __maybe_unused,
6 const char *title __maybe_unused)
8{ 7{
9 int bar, y; 8}
10 /*
11 * FIXME: We should have a per UI backend way of showing progress,
12 * stdio will just show a percentage as NN%, etc.
13 */
14 if (use_browser <= 0)
15 return;
16 9
17 if (total == 0) 10static struct ui_progress default_progress_fns =
18 return; 11{
12 .update = nop_progress_update,
13};
19 14
20 ui__refresh_dimensions(true); 15struct ui_progress *progress_fns = &default_progress_fns;
21 pthread_mutex_lock(&ui__lock); 16
22 y = SLtt_Screen_Rows / 2 - 2; 17void ui_progress__update(u64 curr, u64 total, const char *title)
23 SLsmg_set_color(0); 18{
24 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols); 19 return progress_fns->update(curr, total, title);
25 SLsmg_gotorc(y++, 1); 20}
26 SLsmg_write_string((char *)title); 21
27 SLsmg_set_color(HE_COLORSET_SELECTED); 22void ui_progress__finish(void)
28 bar = ((SLtt_Screen_Cols - 2) * curr) / total; 23{
29 SLsmg_fill_region(y, 1, 1, bar, ' '); 24 if (progress_fns->finish)
30 SLsmg_refresh(); 25 progress_fns->finish();
31 pthread_mutex_unlock(&ui__lock);
32} 26}
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h
index d9c205b59aa1..257cc224f9cf 100644
--- a/tools/perf/ui/progress.h
+++ b/tools/perf/ui/progress.h
@@ -3,6 +3,16 @@
3 3
4#include <../types.h> 4#include <../types.h>
5 5
6struct ui_progress {
7 void (*update)(u64, u64, const char *);
8 void (*finish)(void);
9};
10
11extern struct ui_progress *progress_fns;
12
13void ui_progress__init(void);
14
6void ui_progress__update(u64 curr, u64 total, const char *title); 15void ui_progress__update(u64 curr, u64 total, const char *title);
16void ui_progress__finish(void);
7 17
8#endif 18#endif
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index ebb4cc107876..ae6a789cb0f6 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
8 8
9void setup_browser(bool fallback_to_pager) 9void setup_browser(bool fallback_to_pager)
10{ 10{
11 if (!isatty(1) || dump_trace) 11 if (use_browser < 2 && (!isatty(1) || dump_trace))
12 use_browser = 0; 12 use_browser = 0;
13 13
14 /* default to TUI */ 14 /* default to TUI */
@@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager)
30 if (fallback_to_pager) 30 if (fallback_to_pager)
31 setup_pager(); 31 setup_pager();
32 32
33 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
33 perf_hpp__init(); 34 perf_hpp__init();
34 break; 35 break;
35 } 36 }
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index fbd4e32d0743..ff1f60cf442e 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -3,6 +3,7 @@
3#include "../../util/util.h" 3#include "../../util/util.h"
4#include "../../util/hist.h" 4#include "../../util/hist.h"
5#include "../../util/sort.h" 5#include "../../util/sort.h"
6#include "../../util/evsel.h"
6 7
7 8
8static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 9static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -335,17 +336,19 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
335size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 336size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
336 int max_cols, FILE *fp) 337 int max_cols, FILE *fp)
337{ 338{
339 struct perf_hpp_fmt *fmt;
338 struct sort_entry *se; 340 struct sort_entry *se;
339 struct rb_node *nd; 341 struct rb_node *nd;
340 size_t ret = 0; 342 size_t ret = 0;
341 unsigned int width; 343 unsigned int width;
342 const char *sep = symbol_conf.field_sep; 344 const char *sep = symbol_conf.field_sep;
343 const char *col_width = symbol_conf.col_width_list_str; 345 const char *col_width = symbol_conf.col_width_list_str;
344 int idx, nr_rows = 0; 346 int nr_rows = 0;
345 char bf[64]; 347 char bf[96];
346 struct perf_hpp dummy_hpp = { 348 struct perf_hpp dummy_hpp = {
347 .buf = bf, 349 .buf = bf,
348 .size = sizeof(bf), 350 .size = sizeof(bf),
351 .ptr = hists_to_evsel(hists),
349 }; 352 };
350 bool first = true; 353 bool first = true;
351 354
@@ -355,16 +358,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
355 goto print_entries; 358 goto print_entries;
356 359
357 fprintf(fp, "# "); 360 fprintf(fp, "# ");
358 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
359 if (!perf_hpp__format[idx].cond)
360 continue;
361 361
362 perf_hpp__for_each_format(fmt) {
362 if (!first) 363 if (!first)
363 fprintf(fp, "%s", sep ?: " "); 364 fprintf(fp, "%s", sep ?: " ");
364 else 365 else
365 first = false; 366 first = false;
366 367
367 perf_hpp__format[idx].header(&dummy_hpp); 368 fmt->header(&dummy_hpp);
368 fprintf(fp, "%s", bf); 369 fprintf(fp, "%s", bf);
369 } 370 }
370 371
@@ -400,18 +401,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
400 first = true; 401 first = true;
401 402
402 fprintf(fp, "# "); 403 fprintf(fp, "# ");
403 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
404 unsigned int i;
405 404
406 if (!perf_hpp__format[idx].cond) 405 perf_hpp__for_each_format(fmt) {
407 continue; 406 unsigned int i;
408 407
409 if (!first) 408 if (!first)
410 fprintf(fp, "%s", sep ?: " "); 409 fprintf(fp, "%s", sep ?: " ");
411 else 410 else
412 first = false; 411 first = false;
413 412
414 width = perf_hpp__format[idx].width(&dummy_hpp); 413 width = fmt->width(&dummy_hpp);
415 for (i = 0; i < width; i++) 414 for (i = 0; i < width; i++)
416 fprintf(fp, "."); 415 fprintf(fp, ".");
417 } 416 }
@@ -462,7 +461,7 @@ out:
462 return ret; 461 return ret;
463} 462}
464 463
465size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) 464size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
466{ 465{
467 int i; 466 int i;
468 size_t ret = 0; 467 size_t ret = 0;
@@ -470,7 +469,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
470 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 469 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
471 const char *name; 470 const char *name;
472 471
473 if (hists->stats.nr_events[i] == 0) 472 if (stats->nr_events[i] == 0)
474 continue; 473 continue;
475 474
476 name = perf_event__name(i); 475 name = perf_event__name(i);
@@ -478,7 +477,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp)
478 continue; 477 continue;
479 478
480 ret += fprintf(fp, "%16s events: %10d\n", name, 479 ret += fprintf(fp, "%16s events: %10d\n", name,
481 hists->stats.nr_events[i]); 480 stats->nr_events[i]);
482 } 481 }
483 482
484 return ret; 483 return ret;
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c
index 2884d2f41e33..1c8b9afd5d6e 100644
--- a/tools/perf/ui/tui/helpline.c
+++ b/tools/perf/ui/tui/helpline.c
@@ -8,6 +8,8 @@
8#include "../ui.h" 8#include "../ui.h"
9#include "../libslang.h" 9#include "../libslang.h"
10 10
11char ui_helpline__last_msg[1024];
12
11static void tui_helpline__pop(void) 13static void tui_helpline__pop(void)
12{ 14{
13} 15}
@@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg)
23 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; 25 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
24} 26}
25 27
26struct ui_helpline tui_helpline_fns = { 28static int tui_helpline__show(const char *format, va_list ap)
27 .pop = tui_helpline__pop,
28 .push = tui_helpline__push,
29};
30
31void ui_helpline__init(void)
32{
33 helpline_fns = &tui_helpline_fns;
34 ui_helpline__puts(" ");
35}
36
37char ui_helpline__last_msg[1024];
38
39int ui_helpline__show_help(const char *format, va_list ap)
40{ 29{
41 int ret; 30 int ret;
42 static int backlog; 31 static int backlog;
@@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap)
55 44
56 return ret; 45 return ret;
57} 46}
47
48struct ui_helpline tui_helpline_fns = {
49 .pop = tui_helpline__pop,
50 .push = tui_helpline__push,
51 .show = tui_helpline__show,
52};
53
54void ui_helpline__init(void)
55{
56 helpline_fns = &tui_helpline_fns;
57 ui_helpline__puts(" ");
58}
diff --git a/tools/perf/ui/tui/progress.c b/tools/perf/ui/tui/progress.c
new file mode 100644
index 000000000000..6c2184d53cbf
--- /dev/null
+++ b/tools/perf/ui/tui/progress.c
@@ -0,0 +1,42 @@
1#include "../cache.h"
2#include "../progress.h"
3#include "../libslang.h"
4#include "../ui.h"
5#include "../browser.h"
6
7static void tui_progress__update(u64 curr, u64 total, const char *title)
8{
9 int bar, y;
10 /*
11 * FIXME: We should have a per UI backend way of showing progress,
12 * stdio will just show a percentage as NN%, etc.
13 */
14 if (use_browser <= 0)
15 return;
16
17 if (total == 0)
18 return;
19
20 ui__refresh_dimensions(true);
21 pthread_mutex_lock(&ui__lock);
22 y = SLtt_Screen_Rows / 2 - 2;
23 SLsmg_set_color(0);
24 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
25 SLsmg_gotorc(y++, 1);
26 SLsmg_write_string((char *)title);
27 SLsmg_set_color(HE_COLORSET_SELECTED);
28 bar = ((SLtt_Screen_Cols - 2) * curr) / total;
29 SLsmg_fill_region(y, 1, 1, bar, ' ');
30 SLsmg_refresh();
31 pthread_mutex_unlock(&ui__lock);
32}
33
34static struct ui_progress tui_progress_fns =
35{
36 .update = tui_progress__update,
37};
38
39void ui_progress__init(void)
40{
41 progress_fns = &tui_progress_fns;
42}
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c
index 60debb81537a..81efa192e86c 100644
--- a/tools/perf/ui/tui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -118,6 +118,7 @@ int ui__init(void)
118 newtSetSuspendCallback(newt_suspend, NULL); 118 newtSetSuspendCallback(newt_suspend, NULL);
119 ui_helpline__init(); 119 ui_helpline__init();
120 ui_browser__init(); 120 ui_browser__init();
121 ui_progress__init();
121 122
122 signal(SIGSEGV, ui__signal); 123 signal(SIGSEGV, ui__signal);
123 signal(SIGFPE, ui__signal); 124 signal(SIGFPE, ui__signal);
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
index 7b67045479f6..d86359c99907 100644
--- a/tools/perf/ui/ui.h
+++ b/tools/perf/ui/ui.h
@@ -3,9 +3,37 @@
3 3
4#include <pthread.h> 4#include <pthread.h>
5#include <stdbool.h> 5#include <stdbool.h>
6#include <linux/compiler.h>
6 7
7extern pthread_mutex_t ui__lock; 8extern pthread_mutex_t ui__lock;
8 9
10extern int use_browser;
11
12void setup_browser(bool fallback_to_pager);
13void exit_browser(bool wait_for_ok);
14
15#ifdef NEWT_SUPPORT
16int ui__init(void);
17void ui__exit(bool wait_for_ok);
18#else
19static inline int ui__init(void)
20{
21 return -1;
22}
23static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
24#endif
25
26#ifdef GTK2_SUPPORT
27int perf_gtk__init(void);
28void perf_gtk__exit(bool wait_for_ok);
29#else
30static inline int perf_gtk__init(void)
31{
32 return -1;
33}
34static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
35#endif
36
9void ui__refresh_dimensions(bool force); 37void ui__refresh_dimensions(bool force);
10 38
11#endif /* _PERF_UI_H_ */ 39#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
index 4f989774c8c6..e3e0a963d03a 100644
--- a/tools/perf/ui/util.c
+++ b/tools/perf/ui/util.c
@@ -52,7 +52,6 @@ int ui__warning(const char *format, ...)
52 return ret; 52 return ret;
53} 53}
54 54
55
56/** 55/**
57 * perf_error__register - Register error logging functions 56 * perf_error__register - Register error logging functions
58 * @eops: The pointer to error logging function struct 57 * @eops: The pointer to error logging function struct
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 95264f304179..055fef34b6f6 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -9,18 +9,14 @@ GVF=${OUTPUT}PERF-VERSION-FILE
9LF=' 9LF='
10' 10'
11 11
12#
12# First check if there is a .git to get the version from git describe 13# First check if there is a .git to get the version from git describe
13# otherwise try to get the version from the kernel makefile 14# otherwise try to get the version from the kernel Makefile
15#
14if test -d ../../.git -o -f ../../.git && 16if test -d ../../.git -o -f ../../.git &&
15 VN=$(git describe --match 'v[0-9].[0-9]*' --abbrev=4 HEAD 2>/dev/null) && 17 VN=$(git tag 2>/dev/null | tail -1 | grep -E "v[0-9].[0-9]*")
16 case "$VN" in
17 *$LF*) (exit 1) ;;
18 v[0-9]*)
19 git update-index -q --refresh
20 test -z "$(git diff-index --name-only HEAD --)" ||
21 VN="$VN-dirty" ;;
22 esac
23then 18then
19 VN=$(echo $VN"-g"$(git log -1 --abbrev=4 --pretty=format:"%h" HEAD))
24 VN=$(echo "$VN" | sed -e 's/-/./g'); 20 VN=$(echo "$VN" | sed -e 's/-/./g');
25else 21else
26 VN=$(MAKEFLAGS= make -sC ../.. kernelversion) 22 VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
@@ -30,13 +26,13 @@ VN=$(expr "$VN" : v*'\(.*\)')
30 26
31if test -r $GVF 27if test -r $GVF
32then 28then
33 VC=$(sed -e 's/^PERF_VERSION = //' <$GVF) 29 VC=$(sed -e 's/^#define PERF_VERSION "\(.*\)"/\1/' <$GVF)
34else 30else
35 VC=unset 31 VC=unset
36fi 32fi
37test "$VN" = "$VC" || { 33test "$VN" = "$VC" || {
38 echo >&2 "PERF_VERSION = $VN" 34 echo >&2 "PERF_VERSION = $VN"
39 echo "PERF_VERSION = $VN" >$GVF 35 echo "#define PERF_VERSION \"$VN\"" >$GVF
40} 36}
41 37
42 38
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index f0a910371377..d33fe937e6f1 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -15,6 +15,7 @@
15#include "debug.h" 15#include "debug.h"
16#include "annotate.h" 16#include "annotate.h"
17#include <pthread.h> 17#include <pthread.h>
18#include <linux/bitops.h>
18 19
19const char *disassembler_style; 20const char *disassembler_style;
20const char *objdump_path; 21const char *objdump_path;
@@ -170,15 +171,15 @@ static int lock__parse(struct ins_operands *ops)
170 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) 171 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
171 goto out_free_ops; 172 goto out_free_ops;
172 173
173 ops->locked.ins = ins__find(name); 174 ops->locked.ins = ins__find(name);
174 if (ops->locked.ins == NULL) 175 if (ops->locked.ins == NULL)
175 goto out_free_ops; 176 goto out_free_ops;
176 177
177 if (!ops->locked.ins->ops) 178 if (!ops->locked.ins->ops)
178 return 0; 179 return 0;
179 180
180 if (ops->locked.ins->ops->parse) 181 if (ops->locked.ins->ops->parse)
181 ops->locked.ins->ops->parse(ops->locked.ops); 182 ops->locked.ins->ops->parse(ops->locked.ops);
182 183
183 return 0; 184 return 0;
184 185
@@ -400,6 +401,8 @@ static struct ins instructions[] = {
400 { .name = "testb", .ops = &mov_ops, }, 401 { .name = "testb", .ops = &mov_ops, },
401 { .name = "testl", .ops = &mov_ops, }, 402 { .name = "testl", .ops = &mov_ops, },
402 { .name = "xadd", .ops = &mov_ops, }, 403 { .name = "xadd", .ops = &mov_ops, },
404 { .name = "xbeginl", .ops = &jump_ops, },
405 { .name = "xbeginq", .ops = &jump_ops, },
403}; 406};
404 407
405static int ins__cmp(const void *name, const void *insp) 408static int ins__cmp(const void *name, const void *insp)
@@ -806,7 +809,7 @@ fallback:
806 pr_err("Can't annotate %s:\n\n" 809 pr_err("Can't annotate %s:\n\n"
807 "No vmlinux file%s\nwas found in the path.\n\n" 810 "No vmlinux file%s\nwas found in the path.\n\n"
808 "Please use:\n\n" 811 "Please use:\n\n"
809 " perf buildid-cache -av vmlinux\n\n" 812 " perf buildid-cache -vu vmlinux\n\n"
810 "or:\n\n" 813 "or:\n\n"
811 " --vmlinux vmlinux\n", 814 " --vmlinux vmlinux\n",
812 sym->name, build_id_msg ?: ""); 815 sym->name, build_id_msg ?: "");
@@ -855,21 +858,68 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
855 struct source_line *iter; 858 struct source_line *iter;
856 struct rb_node **p = &root->rb_node; 859 struct rb_node **p = &root->rb_node;
857 struct rb_node *parent = NULL; 860 struct rb_node *parent = NULL;
861 int ret;
858 862
859 while (*p != NULL) { 863 while (*p != NULL) {
860 parent = *p; 864 parent = *p;
861 iter = rb_entry(parent, struct source_line, node); 865 iter = rb_entry(parent, struct source_line, node);
862 866
863 if (src_line->percent > iter->percent) 867 ret = strcmp(iter->path, src_line->path);
868 if (ret == 0) {
869 iter->percent_sum += src_line->percent;
870 return;
871 }
872
873 if (ret < 0)
864 p = &(*p)->rb_left; 874 p = &(*p)->rb_left;
865 else 875 else
866 p = &(*p)->rb_right; 876 p = &(*p)->rb_right;
867 } 877 }
868 878
879 src_line->percent_sum = src_line->percent;
880
869 rb_link_node(&src_line->node, parent, p); 881 rb_link_node(&src_line->node, parent, p);
870 rb_insert_color(&src_line->node, root); 882 rb_insert_color(&src_line->node, root);
871} 883}
872 884
885static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
886{
887 struct source_line *iter;
888 struct rb_node **p = &root->rb_node;
889 struct rb_node *parent = NULL;
890
891 while (*p != NULL) {
892 parent = *p;
893 iter = rb_entry(parent, struct source_line, node);
894
895 if (src_line->percent_sum > iter->percent_sum)
896 p = &(*p)->rb_left;
897 else
898 p = &(*p)->rb_right;
899 }
900
901 rb_link_node(&src_line->node, parent, p);
902 rb_insert_color(&src_line->node, root);
903}
904
905static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
906{
907 struct source_line *src_line;
908 struct rb_node *node;
909
910 node = rb_first(src_root);
911 while (node) {
912 struct rb_node *next;
913
914 src_line = rb_entry(node, struct source_line, node);
915 next = rb_next(node);
916 rb_erase(node, src_root);
917
918 __resort_source_line(dest_root, src_line);
919 node = next;
920 }
921}
922
873static void symbol__free_source_line(struct symbol *sym, int len) 923static void symbol__free_source_line(struct symbol *sym, int len)
874{ 924{
875 struct annotation *notes = symbol__annotation(sym); 925 struct annotation *notes = symbol__annotation(sym);
@@ -894,6 +944,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
894 struct source_line *src_line; 944 struct source_line *src_line;
895 struct annotation *notes = symbol__annotation(sym); 945 struct annotation *notes = symbol__annotation(sym);
896 struct sym_hist *h = annotation__histogram(notes, evidx); 946 struct sym_hist *h = annotation__histogram(notes, evidx);
947 struct rb_root tmp_root = RB_ROOT;
897 948
898 if (!h->sum) 949 if (!h->sum)
899 return 0; 950 return 0;
@@ -928,12 +979,13 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
928 goto next; 979 goto next;
929 980
930 strcpy(src_line[i].path, path); 981 strcpy(src_line[i].path, path);
931 insert_source_line(root, &src_line[i]); 982 insert_source_line(&tmp_root, &src_line[i]);
932 983
933 next: 984 next:
934 pclose(fp); 985 pclose(fp);
935 } 986 }
936 987
988 resort_source_line(root, &tmp_root);
937 return 0; 989 return 0;
938} 990}
939 991
@@ -957,7 +1009,7 @@ static void print_summary(struct rb_root *root, const char *filename)
957 char *path; 1009 char *path;
958 1010
959 src_line = rb_entry(node, struct source_line, node); 1011 src_line = rb_entry(node, struct source_line, node);
960 percent = src_line->percent; 1012 percent = src_line->percent_sum;
961 color = get_percent_color(percent); 1013 color = get_percent_color(percent);
962 path = src_line->path; 1014 path = src_line->path;
963 1015
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 39242dcee8f2..c422440fe611 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -5,6 +5,8 @@
5#include <stdint.h> 5#include <stdint.h>
6#include "types.h" 6#include "types.h"
7#include "symbol.h" 7#include "symbol.h"
8#include "hist.h"
9#include "sort.h"
8#include <linux/list.h> 10#include <linux/list.h>
9#include <linux/rbtree.h> 11#include <linux/rbtree.h>
10#include <pthread.h> 12#include <pthread.h>
@@ -75,6 +77,7 @@ struct sym_hist {
75struct source_line { 77struct source_line {
76 struct rb_node node; 78 struct rb_node node;
77 double percent; 79 double percent;
80 double percent_sum;
78 char *path; 81 char *path;
79}; 82};
80 83
@@ -140,20 +143,41 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
140 143
141#ifdef NEWT_SUPPORT 144#ifdef NEWT_SUPPORT
142int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 145int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
143 void(*timer)(void *arg), void *arg, int delay_secs); 146 struct hist_browser_timer *hbt);
144#else 147#else
145static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, 148static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
146 struct map *map __maybe_unused, 149 struct map *map __maybe_unused,
147 int evidx __maybe_unused, 150 int evidx __maybe_unused,
148 void(*timer)(void *arg) __maybe_unused, 151 struct hist_browser_timer *hbt
149 void *arg __maybe_unused, 152 __maybe_unused)
150 int delay_secs __maybe_unused)
151{ 153{
152 return 0; 154 return 0;
153} 155}
154#endif 156#endif
155 157
158#ifdef GTK2_SUPPORT
159int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx,
160 struct hist_browser_timer *hbt);
161
162static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx,
163 struct hist_browser_timer *hbt)
164{
165 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt);
166}
167
168void perf_gtk__show_annotations(void);
169#else
170static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
171 int evidx __maybe_unused,
172 struct hist_browser_timer *hbt
173 __maybe_unused)
174{
175 return 0;
176}
177
178static inline void perf_gtk__show_annotations(void) {}
179#endif
180
156extern const char *disassembler_style; 181extern const char *disassembler_style;
157extern const char *objdump_path;
158 182
159#endif /* __PERF_ANNOTATE_H */ 183#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 8e3a740ddbd4..5295625c0c00 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -16,11 +16,11 @@
16#include "session.h" 16#include "session.h"
17#include "tool.h" 17#include "tool.h"
18 18
19static int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, 19int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
20 union perf_event *event, 20 union perf_event *event,
21 struct perf_sample *sample __maybe_unused, 21 struct perf_sample *sample __maybe_unused,
22 struct perf_evsel *evsel __maybe_unused, 22 struct perf_evsel *evsel __maybe_unused,
23 struct machine *machine) 23 struct machine *machine)
24{ 24{
25 struct addr_location al; 25 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -64,12 +64,27 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
64struct perf_tool build_id__mark_dso_hit_ops = { 64struct perf_tool build_id__mark_dso_hit_ops = {
65 .sample = build_id__mark_dso_hit, 65 .sample = build_id__mark_dso_hit,
66 .mmap = perf_event__process_mmap, 66 .mmap = perf_event__process_mmap,
67 .fork = perf_event__process_task, 67 .fork = perf_event__process_fork,
68 .exit = perf_event__exit_del_thread, 68 .exit = perf_event__exit_del_thread,
69 .attr = perf_event__process_attr, 69 .attr = perf_event__process_attr,
70 .build_id = perf_event__process_build_id, 70 .build_id = perf_event__process_build_id,
71}; 71};
72 72
73int build_id__sprintf(const u8 *build_id, int len, char *bf)
74{
75 char *bid = bf;
76 const u8 *raw = build_id;
77 int i;
78
79 for (i = 0; i < len; ++i) {
80 sprintf(bid, "%02x", *raw);
81 ++raw;
82 bid += 2;
83 }
84
85 return raw - build_id;
86}
87
73char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 88char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
74{ 89{
75 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 90 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index a993ba87d996..a811f5c62e18 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -1,10 +1,19 @@
1#ifndef PERF_BUILD_ID_H_ 1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1 2#define PERF_BUILD_ID_H_ 1
3 3
4#include "session.h" 4#define BUILD_ID_SIZE 20
5
6#include "tool.h"
7#include "types.h"
5 8
6extern struct perf_tool build_id__mark_dso_hit_ops; 9extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso;
7 11
12int build_id__sprintf(const u8 *build_id, int len, char *bf);
8char *dso__build_id_filename(struct dso *self, char *bf, size_t size); 13char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
9 14
15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
16 struct perf_sample *sample, struct perf_evsel *evsel,
17 struct machine *machine);
18
10#endif 19#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 2bd51370ad28..26e367239873 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -5,6 +5,7 @@
5#include "util.h" 5#include "util.h"
6#include "strbuf.h" 6#include "strbuf.h"
7#include "../perf.h" 7#include "../perf.h"
8#include "../ui/ui.h"
8 9
9#define CMD_EXEC_PATH "--exec-path" 10#define CMD_EXEC_PATH "--exec-path"
10#define CMD_PERF_DIR "--perf-dir=" 11#define CMD_PERF_DIR "--perf-dir="
@@ -31,44 +32,6 @@ extern const char *pager_program;
31extern int pager_in_use(void); 32extern int pager_in_use(void);
32extern int pager_use_color; 33extern int pager_use_color;
33 34
34extern int use_browser;
35
36#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT)
37void setup_browser(bool fallback_to_pager);
38void exit_browser(bool wait_for_ok);
39
40#ifdef NEWT_SUPPORT
41int ui__init(void);
42void ui__exit(bool wait_for_ok);
43#else
44static inline int ui__init(void)
45{
46 return -1;
47}
48static inline void ui__exit(bool wait_for_ok __maybe_unused) {}
49#endif
50
51#ifdef GTK2_SUPPORT
52int perf_gtk__init(void);
53void perf_gtk__exit(bool wait_for_ok);
54#else
55static inline int perf_gtk__init(void)
56{
57 return -1;
58}
59static inline void perf_gtk__exit(bool wait_for_ok __maybe_unused) {}
60#endif
61
62#else /* NEWT_SUPPORT || GTK2_SUPPORT */
63
64static inline void setup_browser(bool fallback_to_pager)
65{
66 if (fallback_to_pager)
67 setup_pager();
68}
69static inline void exit_browser(bool wait_for_ok __maybe_unused) {}
70#endif /* NEWT_SUPPORT || GTK2_SUPPORT */
71
72char *alias_lookup(const char *alias); 35char *alias_lookup(const char *alias);
73int split_cmdline(char *cmdline, const char ***argv); 36int split_cmdline(char *cmdline, const char ***argv);
74 37
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index d3b3f5d82137..42b6a632fe7b 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
444 struct callchain_cursor_node *node = *cursor->last; 444 struct callchain_cursor_node *node = *cursor->last;
445 445
446 if (!node) { 446 if (!node) {
447 node = calloc(sizeof(*node), 1); 447 node = calloc(1, sizeof(*node));
448 if (!node) 448 if (!node)
449 return -ENOMEM; 449 return -ENOMEM;
450 450
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index eb340571e7d6..3ee9f67d5af0 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
143 cursor->curr = cursor->curr->next; 143 cursor->curr = cursor->curr->next;
144 cursor->pos++; 144 cursor->pos++;
145} 145}
146
147struct option;
148
149int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
150extern const char record_callchain_help[];
146#endif /* __PERF_CALLCHAIN_H */ 151#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 2b32ffa9ebdb..f817046e22b1 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -1,4 +1,5 @@
1#include "util.h" 1#include "util.h"
2#include "sysfs.h"
2#include "../perf.h" 3#include "../perf.h"
3#include "cpumap.h" 4#include "cpumap.h"
4#include <assert.h> 5#include <assert.h>
@@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map)
201{ 202{
202 free(map); 203 free(map);
203} 204}
205
206int cpu_map__get_socket(struct cpu_map *map, int idx)
207{
208 FILE *fp;
209 const char *mnt;
210 char path[PATH_MAX];
211 int cpu, ret;
212
213 if (idx > map->nr)
214 return -1;
215
216 cpu = map->map[idx];
217
218 mnt = sysfs_find_mountpoint();
219 if (!mnt)
220 return -1;
221
222 sprintf(path,
223 "%s/devices/system/cpu/cpu%d/topology/physical_package_id",
224 mnt, cpu);
225
226 fp = fopen(path, "r");
227 if (!fp)
228 return -1;
229 ret = fscanf(fp, "%d", &cpu);
230 fclose(fp);
231 return ret == 1 ? cpu : -1;
232}
233
234int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
235{
236 struct cpu_map *sock;
237 int nr = cpus->nr;
238 int cpu, s1, s2;
239
240 sock = calloc(1, sizeof(*sock) + nr * sizeof(int));
241 if (!sock)
242 return -1;
243
244 for (cpu = 0; cpu < nr; cpu++) {
245 s1 = cpu_map__get_socket(cpus, cpu);
246 for (s2 = 0; s2 < sock->nr; s2++) {
247 if (s1 == sock->map[s2])
248 break;
249 }
250 if (s2 == sock->nr) {
251 sock->map[sock->nr] = s1;
252 sock->nr++;
253 }
254 }
255 *sockp = sock;
256 return 0;
257}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 2f68a3b8c285..161b00756a12 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -14,6 +14,15 @@ struct cpu_map *cpu_map__dummy_new(void);
14void cpu_map__delete(struct cpu_map *map); 14void cpu_map__delete(struct cpu_map *map);
15struct cpu_map *cpu_map__read(FILE *file); 15struct cpu_map *cpu_map__read(FILE *file);
16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 16size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
17int cpu_map__get_socket(struct cpu_map *map, int idx);
18int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
19
20static inline int cpu_map__socket(struct cpu_map *sock, int s)
21{
22 if (!sock || s > sock->nr || s < 0)
23 return 0;
24 return sock->map[s];
25}
17 26
18static inline int cpu_map__nr(const struct cpu_map *map) 27static inline int cpu_map__nr(const struct cpu_map *map)
19{ 28{
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 03f830b48148..399e74c34c1a 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -23,10 +23,8 @@ int eprintf(int level, const char *fmt, ...)
23 23
24 if (verbose >= level) { 24 if (verbose >= level) {
25 va_start(args, fmt); 25 va_start(args, fmt);
26 if (use_browser == 1) 26 if (use_browser >= 1)
27 ret = ui_helpline__show_help(fmt, args); 27 ui_helpline__vshow(fmt, args);
28 else if (use_browser == 2)
29 ret = perf_gtk__show_helpline(fmt, args);
30 else 28 else
31 ret = vfprintf(stderr, fmt, args); 29 ret = vfprintf(stderr, fmt, args);
32 va_end(args); 30 va_end(args);
@@ -49,28 +47,6 @@ int dump_printf(const char *fmt, ...)
49 return ret; 47 return ret;
50} 48}
51 49
52#if !defined(NEWT_SUPPORT) && !defined(GTK2_SUPPORT)
53int ui__warning(const char *format, ...)
54{
55 va_list args;
56
57 va_start(args, format);
58 vfprintf(stderr, format, args);
59 va_end(args);
60 return 0;
61}
62#endif
63
64int ui__error_paranoid(void)
65{
66 return ui__error("Permission error - are you root?\n"
67 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
68 " -1 - Not paranoid at all\n"
69 " 0 - Disallow raw tracepoint access for unpriv\n"
70 " 1 - Disallow cpu events for unpriv\n"
71 " 2 - Disallow kernel profiling for unpriv\n");
72}
73
74void trace_event(union perf_event *event) 50void trace_event(union perf_event *event)
75{ 51{
76 unsigned char *raw_event = (void *)event; 52 unsigned char *raw_event = (void *)event;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index dec98750b484..efbd98805ad0 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -5,6 +5,8 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include "event.h" 6#include "event.h"
7#include "../ui/helpline.h" 7#include "../ui/helpline.h"
8#include "../ui/progress.h"
9#include "../ui/util.h"
8 10
9extern int verbose; 11extern int verbose;
10extern bool quiet, dump_trace; 12extern bool quiet, dump_trace;
@@ -12,38 +14,7 @@ extern bool quiet, dump_trace;
12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 14int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(union perf_event *event); 15void trace_event(union perf_event *event);
14 16
15struct ui_progress;
16struct perf_error_ops;
17
18#if defined(NEWT_SUPPORT) || defined(GTK2_SUPPORT)
19
20#include "../ui/progress.h"
21int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 17int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
22#include "../ui/util.h"
23
24#else
25
26static inline void ui_progress__update(u64 curr __maybe_unused,
27 u64 total __maybe_unused,
28 const char *title __maybe_unused) {}
29
30#define ui__error(format, arg...) ui__warning(format, ##arg)
31
32static inline int
33perf_error__register(struct perf_error_ops *eops __maybe_unused)
34{
35 return 0;
36}
37
38static inline int
39perf_error__unregister(struct perf_error_ops *eops __maybe_unused)
40{
41 return 0;
42}
43
44#endif /* NEWT_SUPPORT || GTK2_SUPPORT */
45
46int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); 18int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
47int ui__error_paranoid(void);
48 19
49#endif /* __PERF_DEBUG_H */ 20#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
new file mode 100644
index 000000000000..6f7d5a9d6b05
--- /dev/null
+++ b/tools/perf/util/dso.c
@@ -0,0 +1,595 @@
1#include "symbol.h"
2#include "dso.h"
3#include "machine.h"
4#include "util.h"
5#include "debug.h"
6
7char dso__symtab_origin(const struct dso *dso)
8{
9 static const char origin[] = {
10 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
11 [DSO_BINARY_TYPE__VMLINUX] = 'v',
12 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
13 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
14 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
15 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
16 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
17 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
18 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
19 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
20 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
21 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
22 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
23 };
24
25 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
26 return '!';
27 return origin[dso->symtab_type];
28}
29
30int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
31 char *root_dir, char *file, size_t size)
32{
33 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
34 int ret = 0;
35
36 switch (type) {
37 case DSO_BINARY_TYPE__DEBUGLINK: {
38 char *debuglink;
39
40 strncpy(file, dso->long_name, size);
41 debuglink = file + dso->long_name_len;
42 while (debuglink != file && *debuglink != '/')
43 debuglink--;
44 if (*debuglink == '/')
45 debuglink++;
46 filename__read_debuglink(dso->long_name, debuglink,
47 size - (debuglink - file));
48 }
49 break;
50 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
51 /* skip the locally configured cache if a symfs is given */
52 if (symbol_conf.symfs[0] ||
53 (dso__build_id_filename(dso, file, size) == NULL))
54 ret = -1;
55 break;
56
57 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
58 snprintf(file, size, "%s/usr/lib/debug%s.debug",
59 symbol_conf.symfs, dso->long_name);
60 break;
61
62 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
63 snprintf(file, size, "%s/usr/lib/debug%s",
64 symbol_conf.symfs, dso->long_name);
65 break;
66
67 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
68 if (!dso->has_build_id) {
69 ret = -1;
70 break;
71 }
72
73 build_id__sprintf(dso->build_id,
74 sizeof(dso->build_id),
75 build_id_hex);
76 snprintf(file, size,
77 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
78 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
79 break;
80
81 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
82 snprintf(file, size, "%s%s",
83 symbol_conf.symfs, dso->long_name);
84 break;
85
86 case DSO_BINARY_TYPE__GUEST_KMODULE:
87 snprintf(file, size, "%s%s%s", symbol_conf.symfs,
88 root_dir, dso->long_name);
89 break;
90
91 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
92 snprintf(file, size, "%s%s", symbol_conf.symfs,
93 dso->long_name);
94 break;
95
96 default:
97 case DSO_BINARY_TYPE__KALLSYMS:
98 case DSO_BINARY_TYPE__VMLINUX:
99 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
100 case DSO_BINARY_TYPE__GUEST_VMLINUX:
101 case DSO_BINARY_TYPE__JAVA_JIT:
102 case DSO_BINARY_TYPE__NOT_FOUND:
103 ret = -1;
104 break;
105 }
106
107 return ret;
108}
109
110static int open_dso(struct dso *dso, struct machine *machine)
111{
112 char *root_dir = (char *) "";
113 char *name;
114 int fd;
115
116 name = malloc(PATH_MAX);
117 if (!name)
118 return -ENOMEM;
119
120 if (machine)
121 root_dir = machine->root_dir;
122
123 if (dso__binary_type_file(dso, dso->data_type,
124 root_dir, name, PATH_MAX)) {
125 free(name);
126 return -EINVAL;
127 }
128
129 fd = open(name, O_RDONLY);
130 free(name);
131 return fd;
132}
133
134int dso__data_fd(struct dso *dso, struct machine *machine)
135{
136 static enum dso_binary_type binary_type_data[] = {
137 DSO_BINARY_TYPE__BUILD_ID_CACHE,
138 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
139 DSO_BINARY_TYPE__NOT_FOUND,
140 };
141 int i = 0;
142
143 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
144 return open_dso(dso, machine);
145
146 do {
147 int fd;
148
149 dso->data_type = binary_type_data[i++];
150
151 fd = open_dso(dso, machine);
152 if (fd >= 0)
153 return fd;
154
155 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
156
157 return -EINVAL;
158}
159
160static void
161dso_cache__free(struct rb_root *root)
162{
163 struct rb_node *next = rb_first(root);
164
165 while (next) {
166 struct dso_cache *cache;
167
168 cache = rb_entry(next, struct dso_cache, rb_node);
169 next = rb_next(&cache->rb_node);
170 rb_erase(&cache->rb_node, root);
171 free(cache);
172 }
173}
174
175static struct dso_cache*
176dso_cache__find(struct rb_root *root, u64 offset)
177{
178 struct rb_node **p = &root->rb_node;
179 struct rb_node *parent = NULL;
180 struct dso_cache *cache;
181
182 while (*p != NULL) {
183 u64 end;
184
185 parent = *p;
186 cache = rb_entry(parent, struct dso_cache, rb_node);
187 end = cache->offset + DSO__DATA_CACHE_SIZE;
188
189 if (offset < cache->offset)
190 p = &(*p)->rb_left;
191 else if (offset >= end)
192 p = &(*p)->rb_right;
193 else
194 return cache;
195 }
196 return NULL;
197}
198
199static void
200dso_cache__insert(struct rb_root *root, struct dso_cache *new)
201{
202 struct rb_node **p = &root->rb_node;
203 struct rb_node *parent = NULL;
204 struct dso_cache *cache;
205 u64 offset = new->offset;
206
207 while (*p != NULL) {
208 u64 end;
209
210 parent = *p;
211 cache = rb_entry(parent, struct dso_cache, rb_node);
212 end = cache->offset + DSO__DATA_CACHE_SIZE;
213
214 if (offset < cache->offset)
215 p = &(*p)->rb_left;
216 else if (offset >= end)
217 p = &(*p)->rb_right;
218 }
219
220 rb_link_node(&new->rb_node, parent, p);
221 rb_insert_color(&new->rb_node, root);
222}
223
224static ssize_t
225dso_cache__memcpy(struct dso_cache *cache, u64 offset,
226 u8 *data, u64 size)
227{
228 u64 cache_offset = offset - cache->offset;
229 u64 cache_size = min(cache->size - cache_offset, size);
230
231 memcpy(data, cache->data + cache_offset, cache_size);
232 return cache_size;
233}
234
235static ssize_t
236dso_cache__read(struct dso *dso, struct machine *machine,
237 u64 offset, u8 *data, ssize_t size)
238{
239 struct dso_cache *cache;
240 ssize_t ret;
241 int fd;
242
243 fd = dso__data_fd(dso, machine);
244 if (fd < 0)
245 return -1;
246
247 do {
248 u64 cache_offset;
249
250 ret = -ENOMEM;
251
252 cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
253 if (!cache)
254 break;
255
256 cache_offset = offset & DSO__DATA_CACHE_MASK;
257 ret = -EINVAL;
258
259 if (-1 == lseek(fd, cache_offset, SEEK_SET))
260 break;
261
262 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
263 if (ret <= 0)
264 break;
265
266 cache->offset = cache_offset;
267 cache->size = ret;
268 dso_cache__insert(&dso->cache, cache);
269
270 ret = dso_cache__memcpy(cache, offset, data, size);
271
272 } while (0);
273
274 if (ret <= 0)
275 free(cache);
276
277 close(fd);
278 return ret;
279}
280
281static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
282 u64 offset, u8 *data, ssize_t size)
283{
284 struct dso_cache *cache;
285
286 cache = dso_cache__find(&dso->cache, offset);
287 if (cache)
288 return dso_cache__memcpy(cache, offset, data, size);
289 else
290 return dso_cache__read(dso, machine, offset, data, size);
291}
292
293ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
294 u64 offset, u8 *data, ssize_t size)
295{
296 ssize_t r = 0;
297 u8 *p = data;
298
299 do {
300 ssize_t ret;
301
302 ret = dso_cache_read(dso, machine, offset, p, size);
303 if (ret < 0)
304 return ret;
305
306 /* Reached EOF, return what we have. */
307 if (!ret)
308 break;
309
310 BUG_ON(ret > size);
311
312 r += ret;
313 p += ret;
314 offset += ret;
315 size -= ret;
316
317 } while (size);
318
319 return r;
320}
321
322ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
323 struct machine *machine, u64 addr,
324 u8 *data, ssize_t size)
325{
326 u64 offset = map->map_ip(map, addr);
327 return dso__data_read_offset(dso, machine, offset, data, size);
328}
329
330struct map *dso__new_map(const char *name)
331{
332 struct map *map = NULL;
333 struct dso *dso = dso__new(name);
334
335 if (dso)
336 map = map__new2(0, dso, MAP__FUNCTION);
337
338 return map;
339}
340
341struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
342 const char *short_name, int dso_type)
343{
344 /*
345 * The kernel dso could be created by build_id processing.
346 */
347 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
348
349 /*
350 * We need to run this in all cases, since during the build_id
351 * processing we had no idea this was the kernel dso.
352 */
353 if (dso != NULL) {
354 dso__set_short_name(dso, short_name);
355 dso->kernel = dso_type;
356 }
357
358 return dso;
359}
360
361void dso__set_long_name(struct dso *dso, char *name)
362{
363 if (name == NULL)
364 return;
365 dso->long_name = name;
366 dso->long_name_len = strlen(name);
367}
368
369void dso__set_short_name(struct dso *dso, const char *name)
370{
371 if (name == NULL)
372 return;
373 dso->short_name = name;
374 dso->short_name_len = strlen(name);
375}
376
377static void dso__set_basename(struct dso *dso)
378{
379 dso__set_short_name(dso, basename(dso->long_name));
380}
381
382int dso__name_len(const struct dso *dso)
383{
384 if (!dso)
385 return strlen("[unknown]");
386 if (verbose)
387 return dso->long_name_len;
388
389 return dso->short_name_len;
390}
391
392bool dso__loaded(const struct dso *dso, enum map_type type)
393{
394 return dso->loaded & (1 << type);
395}
396
397bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
398{
399 return dso->sorted_by_name & (1 << type);
400}
401
402void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
403{
404 dso->sorted_by_name |= (1 << type);
405}
406
407struct dso *dso__new(const char *name)
408{
409 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
410
411 if (dso != NULL) {
412 int i;
413 strcpy(dso->name, name);
414 dso__set_long_name(dso, dso->name);
415 dso__set_short_name(dso, dso->name);
416 for (i = 0; i < MAP__NR_TYPES; ++i)
417 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
418 dso->cache = RB_ROOT;
419 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
420 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
421 dso->loaded = 0;
422 dso->sorted_by_name = 0;
423 dso->has_build_id = 0;
424 dso->kernel = DSO_TYPE_USER;
425 dso->needs_swap = DSO_SWAP__UNSET;
426 INIT_LIST_HEAD(&dso->node);
427 }
428
429 return dso;
430}
431
432void dso__delete(struct dso *dso)
433{
434 int i;
435 for (i = 0; i < MAP__NR_TYPES; ++i)
436 symbols__delete(&dso->symbols[i]);
437 if (dso->sname_alloc)
438 free((char *)dso->short_name);
439 if (dso->lname_alloc)
440 free(dso->long_name);
441 dso_cache__free(&dso->cache);
442 free(dso);
443}
444
445void dso__set_build_id(struct dso *dso, void *build_id)
446{
447 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
448 dso->has_build_id = 1;
449}
450
451bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
452{
453 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
454}
455
456void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
457{
458 char path[PATH_MAX];
459
460 if (machine__is_default_guest(machine))
461 return;
462 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
463 if (sysfs__read_build_id(path, dso->build_id,
464 sizeof(dso->build_id)) == 0)
465 dso->has_build_id = true;
466}
467
468int dso__kernel_module_get_build_id(struct dso *dso,
469 const char *root_dir)
470{
471 char filename[PATH_MAX];
472 /*
473 * kernel module short names are of the form "[module]" and
474 * we need just "module" here.
475 */
476 const char *name = dso->short_name + 1;
477
478 snprintf(filename, sizeof(filename),
479 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
480 root_dir, (int)strlen(name) - 1, name);
481
482 if (sysfs__read_build_id(filename, dso->build_id,
483 sizeof(dso->build_id)) == 0)
484 dso->has_build_id = true;
485
486 return 0;
487}
488
489bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
490{
491 bool have_build_id = false;
492 struct dso *pos;
493
494 list_for_each_entry(pos, head, node) {
495 if (with_hits && !pos->hit)
496 continue;
497 if (pos->has_build_id) {
498 have_build_id = true;
499 continue;
500 }
501 if (filename__read_build_id(pos->long_name, pos->build_id,
502 sizeof(pos->build_id)) > 0) {
503 have_build_id = true;
504 pos->has_build_id = true;
505 }
506 }
507
508 return have_build_id;
509}
510
511void dsos__add(struct list_head *head, struct dso *dso)
512{
513 list_add_tail(&dso->node, head);
514}
515
516struct dso *dsos__find(struct list_head *head, const char *name)
517{
518 struct dso *pos;
519
520 list_for_each_entry(pos, head, node)
521 if (strcmp(pos->long_name, name) == 0)
522 return pos;
523 return NULL;
524}
525
526struct dso *__dsos__findnew(struct list_head *head, const char *name)
527{
528 struct dso *dso = dsos__find(head, name);
529
530 if (!dso) {
531 dso = dso__new(name);
532 if (dso != NULL) {
533 dsos__add(head, dso);
534 dso__set_basename(dso);
535 }
536 }
537
538 return dso;
539}
540
541size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
542 bool (skip)(struct dso *dso, int parm), int parm)
543{
544 struct dso *pos;
545 size_t ret = 0;
546
547 list_for_each_entry(pos, head, node) {
548 if (skip && skip(pos, parm))
549 continue;
550 ret += dso__fprintf_buildid(pos, fp);
551 ret += fprintf(fp, " %s\n", pos->long_name);
552 }
553 return ret;
554}
555
556size_t __dsos__fprintf(struct list_head *head, FILE *fp)
557{
558 struct dso *pos;
559 size_t ret = 0;
560
561 list_for_each_entry(pos, head, node) {
562 int i;
563 for (i = 0; i < MAP__NR_TYPES; ++i)
564 ret += dso__fprintf(pos, i, fp);
565 }
566
567 return ret;
568}
569
570size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
571{
572 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
573
574 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
575 return fprintf(fp, "%s", sbuild_id);
576}
577
578size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
579{
580 struct rb_node *nd;
581 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
582
583 if (dso->short_name != dso->long_name)
584 ret += fprintf(fp, "%s, ", dso->long_name);
585 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
586 dso__loaded(dso, type) ? "" : "NOT ");
587 ret += dso__fprintf_buildid(dso, fp);
588 ret += fprintf(fp, ")\n");
589 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
590 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
591 ret += symbol__fprintf(pos, fp);
592 }
593
594 return ret;
595}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
new file mode 100644
index 000000000000..450199ab51b5
--- /dev/null
+++ b/tools/perf/util/dso.h
@@ -0,0 +1,148 @@
1#ifndef __PERF_DSO
2#define __PERF_DSO
3
4#include <linux/types.h>
5#include <linux/rbtree.h>
6#include "types.h"
7#include "map.h"
8
9enum dso_binary_type {
10 DSO_BINARY_TYPE__KALLSYMS = 0,
11 DSO_BINARY_TYPE__GUEST_KALLSYMS,
12 DSO_BINARY_TYPE__VMLINUX,
13 DSO_BINARY_TYPE__GUEST_VMLINUX,
14 DSO_BINARY_TYPE__JAVA_JIT,
15 DSO_BINARY_TYPE__DEBUGLINK,
16 DSO_BINARY_TYPE__BUILD_ID_CACHE,
17 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
18 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
19 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
20 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
21 DSO_BINARY_TYPE__GUEST_KMODULE,
22 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
23 DSO_BINARY_TYPE__NOT_FOUND,
24};
25
26enum dso_kernel_type {
27 DSO_TYPE_USER = 0,
28 DSO_TYPE_KERNEL,
29 DSO_TYPE_GUEST_KERNEL
30};
31
32enum dso_swap_type {
33 DSO_SWAP__UNSET,
34 DSO_SWAP__NO,
35 DSO_SWAP__YES,
36};
37
38#define DSO__SWAP(dso, type, val) \
39({ \
40 type ____r = val; \
41 BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \
42 if (dso->needs_swap == DSO_SWAP__YES) { \
43 switch (sizeof(____r)) { \
44 case 2: \
45 ____r = bswap_16(val); \
46 break; \
47 case 4: \
48 ____r = bswap_32(val); \
49 break; \
50 case 8: \
51 ____r = bswap_64(val); \
52 break; \
53 default: \
54 BUG_ON(1); \
55 } \
56 } \
57 ____r; \
58})
59
60#define DSO__DATA_CACHE_SIZE 4096
61#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
62
63struct dso_cache {
64 struct rb_node rb_node;
65 u64 offset;
66 u64 size;
67 char data[0];
68};
69
70struct dso {
71 struct list_head node;
72 struct rb_root symbols[MAP__NR_TYPES];
73 struct rb_root symbol_names[MAP__NR_TYPES];
74 struct rb_root cache;
75 enum dso_kernel_type kernel;
76 enum dso_swap_type needs_swap;
77 enum dso_binary_type symtab_type;
78 enum dso_binary_type data_type;
79 u8 adjust_symbols:1;
80 u8 has_build_id:1;
81 u8 hit:1;
82 u8 annotate_warned:1;
83 u8 sname_alloc:1;
84 u8 lname_alloc:1;
85 u8 sorted_by_name;
86 u8 loaded;
87 u8 build_id[BUILD_ID_SIZE];
88 const char *short_name;
89 char *long_name;
90 u16 long_name_len;
91 u16 short_name_len;
92 char name[0];
93};
94
95static inline void dso__set_loaded(struct dso *dso, enum map_type type)
96{
97 dso->loaded |= (1 << type);
98}
99
100struct dso *dso__new(const char *name);
101void dso__delete(struct dso *dso);
102
103void dso__set_short_name(struct dso *dso, const char *name);
104void dso__set_long_name(struct dso *dso, char *name);
105
106int dso__name_len(const struct dso *dso);
107
108bool dso__loaded(const struct dso *dso, enum map_type type);
109
110bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
111void dso__set_sorted_by_name(struct dso *dso, enum map_type type);
112void dso__sort_by_name(struct dso *dso, enum map_type type);
113
114void dso__set_build_id(struct dso *dso, void *build_id);
115bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
116void dso__read_running_kernel_build_id(struct dso *dso,
117 struct machine *machine);
118int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
119
120char dso__symtab_origin(const struct dso *dso);
121int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
122 char *root_dir, char *file, size_t size);
123
124int dso__data_fd(struct dso *dso, struct machine *machine);
125ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
126 u64 offset, u8 *data, ssize_t size);
127ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
128 struct machine *machine, u64 addr,
129 u8 *data, ssize_t size);
130
131struct map *dso__new_map(const char *name);
132struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
133 const char *short_name, int dso_type);
134
135void dsos__add(struct list_head *head, struct dso *dso);
136struct dso *dsos__find(struct list_head *head, const char *name);
137struct dso *__dsos__findnew(struct list_head *head, const char *name);
138bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
139
140size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
141 bool (skip)(struct dso *dso, int parm), int parm);
142size_t __dsos__fprintf(struct list_head *head, FILE *fp);
143
144size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
145size_t dso__fprintf_symbols_by_name(struct dso *dso,
146 enum map_type type, FILE *fp);
147size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
148#endif /* __PERF_DSO */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 6715b1938725..5cd13d768cec 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,6 +1,7 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "machine.h"
4#include "sort.h" 5#include "sort.h"
5#include "string.h" 6#include "string.h"
6#include "strlist.h" 7#include "strlist.h"
@@ -192,55 +193,43 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
192 event->header.misc = PERF_RECORD_MISC_USER; 193 event->header.misc = PERF_RECORD_MISC_USER;
193 194
194 while (1) { 195 while (1) {
195 char bf[BUFSIZ], *pbf = bf; 196 char bf[BUFSIZ];
196 int n; 197 char prot[5];
198 char execname[PATH_MAX];
199 char anonstr[] = "//anon";
197 size_t size; 200 size_t size;
201
198 if (fgets(bf, sizeof(bf), fp) == NULL) 202 if (fgets(bf, sizeof(bf), fp) == NULL)
199 break; 203 break;
200 204
205 /* ensure null termination since stack will be reused. */
206 strcpy(execname, "");
207
201 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 208 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
202 n = hex2u64(pbf, &event->mmap.start); 209 sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
203 if (n < 0) 210 &event->mmap.start, &event->mmap.len, prot,
204 continue; 211 &event->mmap.pgoff, execname);
205 pbf += n + 1; 212
206 n = hex2u64(pbf, &event->mmap.len); 213 if (prot[2] != 'x')
207 if (n < 0)
208 continue; 214 continue;
209 pbf += n + 3; 215
210 if (*pbf == 'x') { /* vm_exec */ 216 if (!strcmp(execname, ""))
211 char anonstr[] = "//anon\n"; 217 strcpy(execname, anonstr);
212 char *execname = strchr(bf, '/'); 218
213 219 size = strlen(execname) + 1;
214 /* Catch VDSO */ 220 memcpy(event->mmap.filename, execname, size);
215 if (execname == NULL) 221 size = PERF_ALIGN(size, sizeof(u64));
216 execname = strstr(bf, "[vdso]"); 222 event->mmap.len -= event->mmap.start;
217 223 event->mmap.header.size = (sizeof(event->mmap) -
218 /* Catch anonymous mmaps */ 224 (sizeof(event->mmap.filename) - size));
219 if ((execname == NULL) && !strstr(bf, "[")) 225 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
220 execname = anonstr; 226 event->mmap.header.size += machine->id_hdr_size;
221 227 event->mmap.pid = tgid;
222 if (execname == NULL) 228 event->mmap.tid = pid;
223 continue; 229
224 230 if (process(tool, event, &synth_sample, machine) != 0) {
225 pbf += 3; 231 rc = -1;
226 n = hex2u64(pbf, &event->mmap.pgoff); 232 break;
227
228 size = strlen(execname);
229 execname[size - 1] = '\0'; /* Remove \n */
230 memcpy(event->mmap.filename, execname, size);
231 size = PERF_ALIGN(size, sizeof(u64));
232 event->mmap.len -= event->mmap.start;
233 event->mmap.header.size = (sizeof(event->mmap) -
234 (sizeof(event->mmap.filename) - size));
235 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
236 event->mmap.header.size += machine->id_hdr_size;
237 event->mmap.pid = tgid;
238 event->mmap.tid = pid;
239
240 if (process(tool, event, &synth_sample, machine) != 0) {
241 rc = -1;
242 break;
243 }
244 } 233 }
245 } 234 }
246 235
@@ -404,16 +393,15 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
404 393
405 if (*end) /* only interested in proper numerical dirents */ 394 if (*end) /* only interested in proper numerical dirents */
406 continue; 395 continue;
407 396 /*
408 if (__event__synthesize_thread(comm_event, mmap_event, pid, 1, 397 * We may race with exiting thread, so don't stop just because
409 process, tool, machine) != 0) { 398 * one thread couldn't be synthesized.
410 err = -1; 399 */
411 goto out_closedir; 400 __event__synthesize_thread(comm_event, mmap_event, pid, 1,
412 } 401 process, tool, machine);
413 } 402 }
414 403
415 err = 0; 404 err = 0;
416out_closedir:
417 closedir(proc); 405 closedir(proc);
418out_free_mmap: 406out_free_mmap:
419 free(mmap_event); 407 free(mmap_event);
@@ -488,8 +476,10 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
488 } 476 }
489 } 477 }
490 478
491 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) 479 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) {
480 free(event);
492 return -ENOENT; 481 return -ENOENT;
482 }
493 483
494 map = machine->vmlinux_maps[MAP__FUNCTION]; 484 map = machine->vmlinux_maps[MAP__FUNCTION];
495 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 485 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
@@ -519,134 +509,15 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
519 struct perf_sample *sample __maybe_unused, 509 struct perf_sample *sample __maybe_unused,
520 struct machine *machine) 510 struct machine *machine)
521{ 511{
522 struct thread *thread = machine__findnew_thread(machine, event->comm.tid); 512 return machine__process_comm_event(machine, event);
523
524 if (dump_trace)
525 perf_event__fprintf_comm(event, stdout);
526
527 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
528 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
529 return -1;
530 }
531
532 return 0;
533} 513}
534 514
535int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 515int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
536 union perf_event *event, 516 union perf_event *event,
537 struct perf_sample *sample __maybe_unused, 517 struct perf_sample *sample __maybe_unused,
538 struct machine *machine __maybe_unused) 518 struct machine *machine)
539{
540 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
541 event->lost.id, event->lost.lost);
542 return 0;
543}
544
545static void perf_event__set_kernel_mmap_len(union perf_event *event,
546 struct map **maps)
547{ 519{
548 maps[MAP__FUNCTION]->start = event->mmap.start; 520 return machine__process_lost_event(machine, event);
549 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
550 /*
551 * Be a bit paranoid here, some perf.data file came with
552 * a zero sized synthesized MMAP event for the kernel.
553 */
554 if (maps[MAP__FUNCTION]->end == 0)
555 maps[MAP__FUNCTION]->end = ~0ULL;
556}
557
558static int perf_event__process_kernel_mmap(struct perf_tool *tool
559 __maybe_unused,
560 union perf_event *event,
561 struct machine *machine)
562{
563 struct map *map;
564 char kmmap_prefix[PATH_MAX];
565 enum dso_kernel_type kernel_type;
566 bool is_kernel_mmap;
567
568 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
569 if (machine__is_host(machine))
570 kernel_type = DSO_TYPE_KERNEL;
571 else
572 kernel_type = DSO_TYPE_GUEST_KERNEL;
573
574 is_kernel_mmap = memcmp(event->mmap.filename,
575 kmmap_prefix,
576 strlen(kmmap_prefix) - 1) == 0;
577 if (event->mmap.filename[0] == '/' ||
578 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
579
580 char short_module_name[1024];
581 char *name, *dot;
582
583 if (event->mmap.filename[0] == '/') {
584 name = strrchr(event->mmap.filename, '/');
585 if (name == NULL)
586 goto out_problem;
587
588 ++name; /* skip / */
589 dot = strrchr(name, '.');
590 if (dot == NULL)
591 goto out_problem;
592 snprintf(short_module_name, sizeof(short_module_name),
593 "[%.*s]", (int)(dot - name), name);
594 strxfrchar(short_module_name, '-', '_');
595 } else
596 strcpy(short_module_name, event->mmap.filename);
597
598 map = machine__new_module(machine, event->mmap.start,
599 event->mmap.filename);
600 if (map == NULL)
601 goto out_problem;
602
603 name = strdup(short_module_name);
604 if (name == NULL)
605 goto out_problem;
606
607 map->dso->short_name = name;
608 map->dso->sname_alloc = 1;
609 map->end = map->start + event->mmap.len;
610 } else if (is_kernel_mmap) {
611 const char *symbol_name = (event->mmap.filename +
612 strlen(kmmap_prefix));
613 /*
614 * Should be there already, from the build-id table in
615 * the header.
616 */
617 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
618 kmmap_prefix);
619 if (kernel == NULL)
620 goto out_problem;
621
622 kernel->kernel = kernel_type;
623 if (__machine__create_kernel_maps(machine, kernel) < 0)
624 goto out_problem;
625
626 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
627
628 /*
629 * Avoid using a zero address (kptr_restrict) for the ref reloc
630 * symbol. Effectively having zero here means that at record
631 * time /proc/sys/kernel/kptr_restrict was non zero.
632 */
633 if (event->mmap.pgoff != 0) {
634 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
635 symbol_name,
636 event->mmap.pgoff);
637 }
638
639 if (machine__is_default_guest(machine)) {
640 /*
641 * preload dso of guest kernel and modules
642 */
643 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
644 NULL);
645 }
646 }
647 return 0;
648out_problem:
649 return -1;
650} 521}
651 522
652size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 523size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
@@ -656,43 +527,12 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
656 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 527 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
657} 528}
658 529
659int perf_event__process_mmap(struct perf_tool *tool, 530int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
660 union perf_event *event, 531 union perf_event *event,
661 struct perf_sample *sample __maybe_unused, 532 struct perf_sample *sample __maybe_unused,
662 struct machine *machine) 533 struct machine *machine)
663{ 534{
664 struct thread *thread; 535 return machine__process_mmap_event(machine, event);
665 struct map *map;
666 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
667 int ret = 0;
668
669 if (dump_trace)
670 perf_event__fprintf_mmap(event, stdout);
671
672 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
673 cpumode == PERF_RECORD_MISC_KERNEL) {
674 ret = perf_event__process_kernel_mmap(tool, event, machine);
675 if (ret < 0)
676 goto out_problem;
677 return 0;
678 }
679
680 thread = machine__findnew_thread(machine, event->mmap.pid);
681 if (thread == NULL)
682 goto out_problem;
683 map = map__new(&machine->user_dsos, event->mmap.start,
684 event->mmap.len, event->mmap.pgoff,
685 event->mmap.pid, event->mmap.filename,
686 MAP__FUNCTION);
687 if (map == NULL)
688 goto out_problem;
689
690 thread__insert_map(thread, map);
691 return 0;
692
693out_problem:
694 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
695 return 0;
696} 536}
697 537
698size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 538size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
@@ -702,29 +542,20 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
702 event->fork.ppid, event->fork.ptid); 542 event->fork.ppid, event->fork.ptid);
703} 543}
704 544
705int perf_event__process_task(struct perf_tool *tool __maybe_unused, 545int perf_event__process_fork(struct perf_tool *tool __maybe_unused,
706 union perf_event *event, 546 union perf_event *event,
707 struct perf_sample *sample __maybe_unused, 547 struct perf_sample *sample __maybe_unused,
708 struct machine *machine) 548 struct machine *machine)
709{ 549{
710 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 550 return machine__process_fork_event(machine, event);
711 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); 551}
712
713 if (dump_trace)
714 perf_event__fprintf_task(event, stdout);
715
716 if (event->header.type == PERF_RECORD_EXIT) {
717 machine__remove_thread(machine, thread);
718 return 0;
719 }
720
721 if (thread == NULL || parent == NULL ||
722 thread__fork(thread, parent) < 0) {
723 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
724 return -1;
725 }
726 552
727 return 0; 553int perf_event__process_exit(struct perf_tool *tool __maybe_unused,
554 union perf_event *event,
555 struct perf_sample *sample __maybe_unused,
556 struct machine *machine)
557{
558 return machine__process_exit_event(machine, event);
728} 559}
729 560
730size_t perf_event__fprintf(union perf_event *event, FILE *fp) 561size_t perf_event__fprintf(union perf_event *event, FILE *fp)
@@ -750,27 +581,12 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
750 return ret; 581 return ret;
751} 582}
752 583
753int perf_event__process(struct perf_tool *tool, union perf_event *event, 584int perf_event__process(struct perf_tool *tool __maybe_unused,
754 struct perf_sample *sample, struct machine *machine) 585 union perf_event *event,
586 struct perf_sample *sample __maybe_unused,
587 struct machine *machine)
755{ 588{
756 switch (event->header.type) { 589 return machine__process_event(machine, event);
757 case PERF_RECORD_COMM:
758 perf_event__process_comm(tool, event, sample, machine);
759 break;
760 case PERF_RECORD_MMAP:
761 perf_event__process_mmap(tool, event, sample, machine);
762 break;
763 case PERF_RECORD_FORK:
764 case PERF_RECORD_EXIT:
765 perf_event__process_task(tool, event, sample, machine);
766 break;
767 case PERF_RECORD_LOST:
768 perf_event__process_lost(tool, event, sample, machine);
769 default:
770 break;
771 }
772
773 return 0;
774} 590}
775 591
776void thread__find_addr_map(struct thread *self, 592void thread__find_addr_map(struct thread *self,
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 21b99e741a87..0d573ff4771a 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -6,6 +6,7 @@
6 6
7#include "../perf.h" 7#include "../perf.h"
8#include "map.h" 8#include "map.h"
9#include "build-id.h"
9 10
10/* 11/*
11 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 12 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -96,8 +97,6 @@ struct perf_sample {
96 struct stack_dump user_stack; 97 struct stack_dump user_stack;
97}; 98};
98 99
99#define BUILD_ID_SIZE 20
100
101struct build_id_event { 100struct build_id_event {
102 struct perf_event_header header; 101 struct perf_event_header header;
103 pid_t pid; 102 pid_t pid;
@@ -191,7 +190,11 @@ int perf_event__process_mmap(struct perf_tool *tool,
191 union perf_event *event, 190 union perf_event *event,
192 struct perf_sample *sample, 191 struct perf_sample *sample,
193 struct machine *machine); 192 struct machine *machine);
194int perf_event__process_task(struct perf_tool *tool, 193int perf_event__process_fork(struct perf_tool *tool,
194 union perf_event *event,
195 struct perf_sample *sample,
196 struct machine *machine);
197int perf_event__process_exit(struct perf_tool *tool,
195 union perf_event *event, 198 union perf_event *event,
196 struct perf_sample *sample, 199 struct perf_sample *sample,
197 struct machine *machine); 200 struct machine *machine);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 186b87730396..c8be0fbc5145 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -49,21 +49,25 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
49 return evlist; 49 return evlist;
50} 50}
51 51
52void perf_evlist__config_attrs(struct perf_evlist *evlist, 52void perf_evlist__config(struct perf_evlist *evlist,
53 struct perf_record_opts *opts) 53 struct perf_record_opts *opts)
54{ 54{
55 struct perf_evsel *evsel, *first; 55 struct perf_evsel *evsel;
56 /*
57 * Set the evsel leader links before we configure attributes,
58 * since some might depend on this info.
59 */
60 if (opts->group)
61 perf_evlist__set_leader(evlist);
56 62
57 if (evlist->cpus->map[0] < 0) 63 if (evlist->cpus->map[0] < 0)
58 opts->no_inherit = true; 64 opts->no_inherit = true;
59 65
60 first = perf_evlist__first(evlist);
61
62 list_for_each_entry(evsel, &evlist->entries, node) { 66 list_for_each_entry(evsel, &evlist->entries, node) {
63 perf_evsel__config(evsel, opts, first); 67 perf_evsel__config(evsel, opts);
64 68
65 if (evlist->nr_entries > 1) 69 if (evlist->nr_entries > 1)
66 evsel->attr.sample_type |= PERF_SAMPLE_ID; 70 perf_evsel__set_sample_id(evsel);
67 } 71 }
68} 72}
69 73
@@ -113,18 +117,21 @@ void __perf_evlist__set_leader(struct list_head *list)
113 struct perf_evsel *evsel, *leader; 117 struct perf_evsel *evsel, *leader;
114 118
115 leader = list_entry(list->next, struct perf_evsel, node); 119 leader = list_entry(list->next, struct perf_evsel, node);
116 leader->leader = NULL; 120 evsel = list_entry(list->prev, struct perf_evsel, node);
121
122 leader->nr_members = evsel->idx - leader->idx + 1;
117 123
118 list_for_each_entry(evsel, list, node) { 124 list_for_each_entry(evsel, list, node) {
119 if (evsel != leader) 125 evsel->leader = leader;
120 evsel->leader = leader;
121 } 126 }
122} 127}
123 128
124void perf_evlist__set_leader(struct perf_evlist *evlist) 129void perf_evlist__set_leader(struct perf_evlist *evlist)
125{ 130{
126 if (evlist->nr_entries) 131 if (evlist->nr_entries) {
132 evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0;
127 __perf_evlist__set_leader(&evlist->entries); 133 __perf_evlist__set_leader(&evlist->entries);
134 }
128} 135}
129 136
130int perf_evlist__add_default(struct perf_evlist *evlist) 137int perf_evlist__add_default(struct perf_evlist *evlist)
@@ -224,6 +231,8 @@ void perf_evlist__disable(struct perf_evlist *evlist)
224 231
225 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 232 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
226 list_for_each_entry(pos, &evlist->entries, node) { 233 list_for_each_entry(pos, &evlist->entries, node) {
234 if (!perf_evsel__is_group_leader(pos))
235 continue;
227 for (thread = 0; thread < evlist->threads->nr; thread++) 236 for (thread = 0; thread < evlist->threads->nr; thread++)
228 ioctl(FD(pos, cpu, thread), 237 ioctl(FD(pos, cpu, thread),
229 PERF_EVENT_IOC_DISABLE, 0); 238 PERF_EVENT_IOC_DISABLE, 0);
@@ -238,6 +247,8 @@ void perf_evlist__enable(struct perf_evlist *evlist)
238 247
239 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { 248 for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) {
240 list_for_each_entry(pos, &evlist->entries, node) { 249 list_for_each_entry(pos, &evlist->entries, node) {
250 if (!perf_evsel__is_group_leader(pos))
251 continue;
241 for (thread = 0; thread < evlist->threads->nr; thread++) 252 for (thread = 0; thread < evlist->threads->nr; thread++)
242 ioctl(FD(pos, cpu, thread), 253 ioctl(FD(pos, cpu, thread),
243 PERF_EVENT_IOC_ENABLE, 0); 254 PERF_EVENT_IOC_ENABLE, 0);
@@ -303,7 +314,6 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
303struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) 314struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
304{ 315{
305 struct hlist_head *head; 316 struct hlist_head *head;
306 struct hlist_node *pos;
307 struct perf_sample_id *sid; 317 struct perf_sample_id *sid;
308 int hash; 318 int hash;
309 319
@@ -313,7 +323,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
313 hash = hash_64(id, PERF_EVLIST__HLIST_BITS); 323 hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
314 head = &evlist->heads[hash]; 324 head = &evlist->heads[hash];
315 325
316 hlist_for_each_entry(sid, pos, head, node) 326 hlist_for_each_entry(sid, head, node)
317 if (sid->id == id) 327 if (sid->id == id)
318 return sid->evsel; 328 return sid->evsel;
319 329
@@ -325,8 +335,6 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id)
325 335
326union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) 336union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
327{ 337{
328 /* XXX Move this to perf.c, making it generally available */
329 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
330 struct perf_mmap *md = &evlist->mmap[idx]; 338 struct perf_mmap *md = &evlist->mmap[idx];
331 unsigned int head = perf_mmap__read_head(md); 339 unsigned int head = perf_mmap__read_head(md);
332 unsigned int old = md->prev; 340 unsigned int old = md->prev;
@@ -366,7 +374,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
366 if ((old & md->mask) + size != ((old + size) & md->mask)) { 374 if ((old & md->mask) + size != ((old + size) & md->mask)) {
367 unsigned int offset = old; 375 unsigned int offset = old;
368 unsigned int len = min(sizeof(*event), size), cpy; 376 unsigned int len = min(sizeof(*event), size), cpy;
369 void *dst = &evlist->event_copy; 377 void *dst = &md->event_copy;
370 378
371 do { 379 do {
372 cpy = min(md->mask + 1 - (offset & md->mask), len); 380 cpy = min(md->mask + 1 - (offset & md->mask), len);
@@ -376,7 +384,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
376 len -= cpy; 384 len -= cpy;
377 } while (len); 385 } while (len);
378 386
379 event = &evlist->event_copy; 387 event = &md->event_copy;
380 } 388 }
381 389
382 old += size; 390 old += size;
@@ -528,7 +536,6 @@ out_unmap:
528int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 536int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
529 bool overwrite) 537 bool overwrite)
530{ 538{
531 unsigned int page_size = sysconf(_SC_PAGE_SIZE);
532 struct perf_evsel *evsel; 539 struct perf_evsel *evsel;
533 const struct cpu_map *cpus = evlist->cpus; 540 const struct cpu_map *cpus = evlist->cpus;
534 const struct thread_map *threads = evlist->threads; 541 const struct thread_map *threads = evlist->threads;
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 56003f779e60..2dd07bd60b4f 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -17,10 +17,18 @@ struct perf_record_opts;
17#define PERF_EVLIST__HLIST_BITS 8 17#define PERF_EVLIST__HLIST_BITS 8
18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) 18#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
19 19
20struct perf_mmap {
21 void *base;
22 int mask;
23 unsigned int prev;
24 union perf_event event_copy;
25};
26
20struct perf_evlist { 27struct perf_evlist {
21 struct list_head entries; 28 struct list_head entries;
22 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; 29 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
23 int nr_entries; 30 int nr_entries;
31 int nr_groups;
24 int nr_fds; 32 int nr_fds;
25 int nr_mmaps; 33 int nr_mmaps;
26 int mmap_len; 34 int mmap_len;
@@ -29,7 +37,6 @@ struct perf_evlist {
29 pid_t pid; 37 pid_t pid;
30 } workload; 38 } workload;
31 bool overwrite; 39 bool overwrite;
32 union perf_event event_copy;
33 struct perf_mmap *mmap; 40 struct perf_mmap *mmap;
34 struct pollfd *pollfd; 41 struct pollfd *pollfd;
35 struct thread_map *threads; 42 struct thread_map *threads;
@@ -76,8 +83,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx);
76 83
77int perf_evlist__open(struct perf_evlist *evlist); 84int perf_evlist__open(struct perf_evlist *evlist);
78 85
79void perf_evlist__config_attrs(struct perf_evlist *evlist, 86void perf_evlist__config(struct perf_evlist *evlist,
80 struct perf_record_opts *opts); 87 struct perf_record_opts *opts);
81 88
82int perf_evlist__prepare_workload(struct perf_evlist *evlist, 89int perf_evlist__prepare_workload(struct perf_evlist *evlist,
83 struct perf_record_opts *opts, 90 struct perf_record_opts *opts,
@@ -135,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
135} 142}
136 143
137size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 144size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
145
146static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
147{
148 struct perf_event_mmap_page *pc = mm->base;
149 int head = pc->data_head;
150 rmb();
151 return head;
152}
153
154static inline void perf_mmap__write_tail(struct perf_mmap *md,
155 unsigned long tail)
156{
157 struct perf_event_mmap_page *pc = md->base;
158
159 /*
160 * ensure all reads are done before we write the tail out.
161 */
162 /* mb(); */
163 pc->data_tail = tail;
164}
165
138#endif /* __PERF_EVLIST_H */ 166#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 618d41140abd..9c82f98f26de 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -18,10 +18,15 @@
18#include "cpumap.h" 18#include "cpumap.h"
19#include "thread_map.h" 19#include "thread_map.h"
20#include "target.h" 20#include "target.h"
21#include "../../../include/linux/hw_breakpoint.h" 21#include <linux/hw_breakpoint.h>
22#include "../../../include/uapi/linux/perf_event.h" 22#include <linux/perf_event.h>
23#include "perf_regs.h" 23#include "perf_regs.h"
24 24
25static struct {
26 bool sample_id_all;
27 bool exclude_guest;
28} perf_missing_features;
29
25#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 30#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
26 31
27static int __perf_evsel__sample_size(u64 sample_type) 32static int __perf_evsel__sample_size(u64 sample_type)
@@ -50,11 +55,36 @@ void hists__init(struct hists *hists)
50 pthread_mutex_init(&hists->lock, NULL); 55 pthread_mutex_init(&hists->lock, NULL);
51} 56}
52 57
58void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
59 enum perf_event_sample_format bit)
60{
61 if (!(evsel->attr.sample_type & bit)) {
62 evsel->attr.sample_type |= bit;
63 evsel->sample_size += sizeof(u64);
64 }
65}
66
67void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
68 enum perf_event_sample_format bit)
69{
70 if (evsel->attr.sample_type & bit) {
71 evsel->attr.sample_type &= ~bit;
72 evsel->sample_size -= sizeof(u64);
73 }
74}
75
76void perf_evsel__set_sample_id(struct perf_evsel *evsel)
77{
78 perf_evsel__set_sample_bit(evsel, ID);
79 evsel->attr.read_format |= PERF_FORMAT_ID;
80}
81
53void perf_evsel__init(struct perf_evsel *evsel, 82void perf_evsel__init(struct perf_evsel *evsel,
54 struct perf_event_attr *attr, int idx) 83 struct perf_event_attr *attr, int idx)
55{ 84{
56 evsel->idx = idx; 85 evsel->idx = idx;
57 evsel->attr = *attr; 86 evsel->attr = *attr;
87 evsel->leader = evsel;
58 INIT_LIST_HEAD(&evsel->node); 88 INIT_LIST_HEAD(&evsel->node);
59 hists__init(&evsel->hists); 89 hists__init(&evsel->hists);
60 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 90 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
@@ -404,20 +434,70 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
404 return evsel->name ?: "unknown"; 434 return evsel->name ?: "unknown";
405} 435}
406 436
407void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, 437const char *perf_evsel__group_name(struct perf_evsel *evsel)
408 struct perf_evsel *first) 438{
439 return evsel->group_name ?: "anon group";
440}
441
442int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
443{
444 int ret;
445 struct perf_evsel *pos;
446 const char *group_name = perf_evsel__group_name(evsel);
447
448 ret = scnprintf(buf, size, "%s", group_name);
449
450 ret += scnprintf(buf + ret, size - ret, " { %s",
451 perf_evsel__name(evsel));
452
453 for_each_group_member(pos, evsel)
454 ret += scnprintf(buf + ret, size - ret, ", %s",
455 perf_evsel__name(pos));
456
457 ret += scnprintf(buf + ret, size - ret, " }");
458
459 return ret;
460}
461
462/*
463 * The enable_on_exec/disabled value strategy:
464 *
465 * 1) For any type of traced program:
466 * - all independent events and group leaders are disabled
467 * - all group members are enabled
468 *
469 * Group members are ruled by group leaders. They need to
470 * be enabled, because the group scheduling relies on that.
471 *
472 * 2) For traced programs executed by perf:
473 * - all independent events and group leaders have
474 * enable_on_exec set
475 * - we don't specifically enable or disable any event during
476 * the record command
477 *
478 * Independent events and group leaders are initially disabled
479 * and get enabled by exec. Group members are ruled by group
480 * leaders as stated in 1).
481 *
482 * 3) For traced programs attached by perf (pid/tid):
483 * - we specifically enable or disable all events during
484 * the record command
485 *
486 * When attaching events to already running traced we
487 * enable/disable events specifically, as there's no
488 * initial traced exec call.
489 */
490void perf_evsel__config(struct perf_evsel *evsel,
491 struct perf_record_opts *opts)
409{ 492{
410 struct perf_event_attr *attr = &evsel->attr; 493 struct perf_event_attr *attr = &evsel->attr;
411 int track = !evsel->idx; /* only the first counter needs these */ 494 int track = !evsel->idx; /* only the first counter needs these */
412 495
413 attr->disabled = 1; 496 attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1;
414 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
415 attr->inherit = !opts->no_inherit; 497 attr->inherit = !opts->no_inherit;
416 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
417 PERF_FORMAT_TOTAL_TIME_RUNNING |
418 PERF_FORMAT_ID;
419 498
420 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 499 perf_evsel__set_sample_bit(evsel, IP);
500 perf_evsel__set_sample_bit(evsel, TID);
421 501
422 /* 502 /*
423 * We default some events to a 1 default interval. But keep 503 * We default some events to a 1 default interval. But keep
@@ -426,7 +506,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
426 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 506 if (!attr->sample_period || (opts->user_freq != UINT_MAX &&
427 opts->user_interval != ULLONG_MAX)) { 507 opts->user_interval != ULLONG_MAX)) {
428 if (opts->freq) { 508 if (opts->freq) {
429 attr->sample_type |= PERF_SAMPLE_PERIOD; 509 perf_evsel__set_sample_bit(evsel, PERIOD);
430 attr->freq = 1; 510 attr->freq = 1;
431 attr->sample_freq = opts->freq; 511 attr->sample_freq = opts->freq;
432 } else { 512 } else {
@@ -441,16 +521,16 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
441 attr->inherit_stat = 1; 521 attr->inherit_stat = 1;
442 522
443 if (opts->sample_address) { 523 if (opts->sample_address) {
444 attr->sample_type |= PERF_SAMPLE_ADDR; 524 perf_evsel__set_sample_bit(evsel, ADDR);
445 attr->mmap_data = track; 525 attr->mmap_data = track;
446 } 526 }
447 527
448 if (opts->call_graph) { 528 if (opts->call_graph) {
449 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 529 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
450 530
451 if (opts->call_graph == CALLCHAIN_DWARF) { 531 if (opts->call_graph == CALLCHAIN_DWARF) {
452 attr->sample_type |= PERF_SAMPLE_REGS_USER | 532 perf_evsel__set_sample_bit(evsel, REGS_USER);
453 PERF_SAMPLE_STACK_USER; 533 perf_evsel__set_sample_bit(evsel, STACK_USER);
454 attr->sample_regs_user = PERF_REGS_MASK; 534 attr->sample_regs_user = PERF_REGS_MASK;
455 attr->sample_stack_user = opts->stack_dump_size; 535 attr->sample_stack_user = opts->stack_dump_size;
456 attr->exclude_callchain_user = 1; 536 attr->exclude_callchain_user = 1;
@@ -458,20 +538,20 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
458 } 538 }
459 539
460 if (perf_target__has_cpu(&opts->target)) 540 if (perf_target__has_cpu(&opts->target))
461 attr->sample_type |= PERF_SAMPLE_CPU; 541 perf_evsel__set_sample_bit(evsel, CPU);
462 542
463 if (opts->period) 543 if (opts->period)
464 attr->sample_type |= PERF_SAMPLE_PERIOD; 544 perf_evsel__set_sample_bit(evsel, PERIOD);
465 545
466 if (!opts->sample_id_all_missing && 546 if (!perf_missing_features.sample_id_all &&
467 (opts->sample_time || !opts->no_inherit || 547 (opts->sample_time || !opts->no_inherit ||
468 perf_target__has_cpu(&opts->target))) 548 perf_target__has_cpu(&opts->target)))
469 attr->sample_type |= PERF_SAMPLE_TIME; 549 perf_evsel__set_sample_bit(evsel, TIME);
470 550
471 if (opts->raw_samples) { 551 if (opts->raw_samples) {
472 attr->sample_type |= PERF_SAMPLE_TIME; 552 perf_evsel__set_sample_bit(evsel, TIME);
473 attr->sample_type |= PERF_SAMPLE_RAW; 553 perf_evsel__set_sample_bit(evsel, RAW);
474 attr->sample_type |= PERF_SAMPLE_CPU; 554 perf_evsel__set_sample_bit(evsel, CPU);
475 } 555 }
476 556
477 if (opts->no_delay) { 557 if (opts->no_delay) {
@@ -479,17 +559,28 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
479 attr->wakeup_events = 1; 559 attr->wakeup_events = 1;
480 } 560 }
481 if (opts->branch_stack) { 561 if (opts->branch_stack) {
482 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; 562 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
483 attr->branch_sample_type = opts->branch_stack; 563 attr->branch_sample_type = opts->branch_stack;
484 } 564 }
485 565
486 attr->mmap = track; 566 attr->mmap = track;
487 attr->comm = track; 567 attr->comm = track;
488 568
489 if (perf_target__none(&opts->target) && 569 /*
490 (!opts->group || evsel == first)) { 570 * XXX see the function comment above
571 *
572 * Disabling only independent events or group leaders,
573 * keeping group members enabled.
574 */
575 if (perf_evsel__is_group_leader(evsel))
576 attr->disabled = 1;
577
578 /*
579 * Setting enable_on_exec for independent events and
580 * group leaders for traced executed by perf.
581 */
582 if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel))
491 attr->enable_on_exec = 1; 583 attr->enable_on_exec = 1;
492 }
493} 584}
494 585
495int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 586int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -574,6 +665,11 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
574 } 665 }
575} 666}
576 667
668void perf_evsel__free_counts(struct perf_evsel *evsel)
669{
670 free(evsel->counts);
671}
672
577void perf_evsel__exit(struct perf_evsel *evsel) 673void perf_evsel__exit(struct perf_evsel *evsel)
578{ 674{
579 assert(list_empty(&evsel->node)); 675 assert(list_empty(&evsel->node));
@@ -593,6 +689,28 @@ void perf_evsel__delete(struct perf_evsel *evsel)
593 free(evsel); 689 free(evsel);
594} 690}
595 691
692static inline void compute_deltas(struct perf_evsel *evsel,
693 int cpu,
694 struct perf_counts_values *count)
695{
696 struct perf_counts_values tmp;
697
698 if (!evsel->prev_raw_counts)
699 return;
700
701 if (cpu == -1) {
702 tmp = evsel->prev_raw_counts->aggr;
703 evsel->prev_raw_counts->aggr = *count;
704 } else {
705 tmp = evsel->prev_raw_counts->cpu[cpu];
706 evsel->prev_raw_counts->cpu[cpu] = *count;
707 }
708
709 count->val = count->val - tmp.val;
710 count->ena = count->ena - tmp.ena;
711 count->run = count->run - tmp.run;
712}
713
596int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 714int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
597 int cpu, int thread, bool scale) 715 int cpu, int thread, bool scale)
598{ 716{
@@ -608,6 +726,8 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
608 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) 726 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
609 return -errno; 727 return -errno;
610 728
729 compute_deltas(evsel, cpu, &count);
730
611 if (scale) { 731 if (scale) {
612 if (count.run == 0) 732 if (count.run == 0)
613 count.val = 0; 733 count.val = 0;
@@ -646,6 +766,8 @@ int __perf_evsel__read(struct perf_evsel *evsel,
646 } 766 }
647 } 767 }
648 768
769 compute_deltas(evsel, -1, aggr);
770
649 evsel->counts->scaled = 0; 771 evsel->counts->scaled = 0;
650 if (scale) { 772 if (scale) {
651 if (aggr->run == 0) { 773 if (aggr->run == 0) {
@@ -669,7 +791,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread)
669 struct perf_evsel *leader = evsel->leader; 791 struct perf_evsel *leader = evsel->leader;
670 int fd; 792 int fd;
671 793
672 if (!leader) 794 if (perf_evsel__is_group_leader(evsel))
673 return -1; 795 return -1;
674 796
675 /* 797 /*
@@ -700,6 +822,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
700 pid = evsel->cgrp->fd; 822 pid = evsel->cgrp->fd;
701 } 823 }
702 824
825fallback_missing_features:
826 if (perf_missing_features.exclude_guest)
827 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
828retry_sample_id:
829 if (perf_missing_features.sample_id_all)
830 evsel->attr.sample_id_all = 0;
831
703 for (cpu = 0; cpu < cpus->nr; cpu++) { 832 for (cpu = 0; cpu < cpus->nr; cpu++) {
704 833
705 for (thread = 0; thread < threads->nr; thread++) { 834 for (thread = 0; thread < threads->nr; thread++) {
@@ -716,13 +845,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
716 group_fd, flags); 845 group_fd, flags);
717 if (FD(evsel, cpu, thread) < 0) { 846 if (FD(evsel, cpu, thread) < 0) {
718 err = -errno; 847 err = -errno;
719 goto out_close; 848 goto try_fallback;
720 } 849 }
721 } 850 }
722 } 851 }
723 852
724 return 0; 853 return 0;
725 854
855try_fallback:
856 if (err != -EINVAL || cpu > 0 || thread > 0)
857 goto out_close;
858
859 if (!perf_missing_features.exclude_guest &&
860 (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
861 perf_missing_features.exclude_guest = true;
862 goto fallback_missing_features;
863 } else if (!perf_missing_features.sample_id_all) {
864 perf_missing_features.sample_id_all = true;
865 goto retry_sample_id;
866 }
867
726out_close: 868out_close:
727 do { 869 do {
728 while (--thread >= 0) { 870 while (--thread >= 0) {
@@ -1167,3 +1309,225 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample,
1167 1309
1168 return 0; 1310 return 0;
1169} 1311}
1312
1313static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
1314{
1315 va_list args;
1316 int ret = 0;
1317
1318 if (!*first) {
1319 ret += fprintf(fp, ",");
1320 } else {
1321 ret += fprintf(fp, ":");
1322 *first = false;
1323 }
1324
1325 va_start(args, fmt);
1326 ret += vfprintf(fp, fmt, args);
1327 va_end(args);
1328 return ret;
1329}
1330
1331static int __if_fprintf(FILE *fp, bool *first, const char *field, u64 value)
1332{
1333 if (value == 0)
1334 return 0;
1335
1336 return comma_fprintf(fp, first, " %s: %" PRIu64, field, value);
1337}
1338
1339#define if_print(field) printed += __if_fprintf(fp, &first, #field, evsel->attr.field)
1340
1341struct bit_names {
1342 int bit;
1343 const char *name;
1344};
1345
1346static int bits__fprintf(FILE *fp, const char *field, u64 value,
1347 struct bit_names *bits, bool *first)
1348{
1349 int i = 0, printed = comma_fprintf(fp, first, " %s: ", field);
1350 bool first_bit = true;
1351
1352 do {
1353 if (value & bits[i].bit) {
1354 printed += fprintf(fp, "%s%s", first_bit ? "" : "|", bits[i].name);
1355 first_bit = false;
1356 }
1357 } while (bits[++i].name != NULL);
1358
1359 return printed;
1360}
1361
1362static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
1363{
1364#define bit_name(n) { PERF_SAMPLE_##n, #n }
1365 struct bit_names bits[] = {
1366 bit_name(IP), bit_name(TID), bit_name(TIME), bit_name(ADDR),
1367 bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
1368 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1369 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1370 { .name = NULL, }
1371 };
1372#undef bit_name
1373 return bits__fprintf(fp, "sample_type", value, bits, first);
1374}
1375
1376static int read_format__fprintf(FILE *fp, bool *first, u64 value)
1377{
1378#define bit_name(n) { PERF_FORMAT_##n, #n }
1379 struct bit_names bits[] = {
1380 bit_name(TOTAL_TIME_ENABLED), bit_name(TOTAL_TIME_RUNNING),
1381 bit_name(ID), bit_name(GROUP),
1382 { .name = NULL, }
1383 };
1384#undef bit_name
1385 return bits__fprintf(fp, "read_format", value, bits, first);
1386}
1387
1388int perf_evsel__fprintf(struct perf_evsel *evsel,
1389 struct perf_attr_details *details, FILE *fp)
1390{
1391 bool first = true;
1392 int printed = 0;
1393
1394 if (details->event_group) {
1395 struct perf_evsel *pos;
1396
1397 if (!perf_evsel__is_group_leader(evsel))
1398 return 0;
1399
1400 if (evsel->nr_members > 1)
1401 printed += fprintf(fp, "%s{", evsel->group_name ?: "");
1402
1403 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
1404 for_each_group_member(pos, evsel)
1405 printed += fprintf(fp, ",%s", perf_evsel__name(pos));
1406
1407 if (evsel->nr_members > 1)
1408 printed += fprintf(fp, "}");
1409 goto out;
1410 }
1411
1412 printed += fprintf(fp, "%s", perf_evsel__name(evsel));
1413
1414 if (details->verbose || details->freq) {
1415 printed += comma_fprintf(fp, &first, " sample_freq=%" PRIu64,
1416 (u64)evsel->attr.sample_freq);
1417 }
1418
1419 if (details->verbose) {
1420 if_print(type);
1421 if_print(config);
1422 if_print(config1);
1423 if_print(config2);
1424 if_print(size);
1425 printed += sample_type__fprintf(fp, &first, evsel->attr.sample_type);
1426 if (evsel->attr.read_format)
1427 printed += read_format__fprintf(fp, &first, evsel->attr.read_format);
1428 if_print(disabled);
1429 if_print(inherit);
1430 if_print(pinned);
1431 if_print(exclusive);
1432 if_print(exclude_user);
1433 if_print(exclude_kernel);
1434 if_print(exclude_hv);
1435 if_print(exclude_idle);
1436 if_print(mmap);
1437 if_print(comm);
1438 if_print(freq);
1439 if_print(inherit_stat);
1440 if_print(enable_on_exec);
1441 if_print(task);
1442 if_print(watermark);
1443 if_print(precise_ip);
1444 if_print(mmap_data);
1445 if_print(sample_id_all);
1446 if_print(exclude_host);
1447 if_print(exclude_guest);
1448 if_print(__reserved_1);
1449 if_print(wakeup_events);
1450 if_print(bp_type);
1451 if_print(branch_sample_type);
1452 }
1453out:
1454 fputc('\n', fp);
1455 return ++printed;
1456}
1457
1458bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1459 char *msg, size_t msgsize)
1460{
1461 if ((err == ENOENT || err == ENXIO) &&
1462 evsel->attr.type == PERF_TYPE_HARDWARE &&
1463 evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
1464 /*
1465 * If it's cycles then fall back to hrtimer based
1466 * cpu-clock-tick sw counter, which is always available even if
1467 * no PMU support.
1468 *
1469 * PPC returns ENXIO until 2.6.37 (behavior changed with commit
1470 * b0a873e).
1471 */
1472 scnprintf(msg, msgsize, "%s",
1473"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
1474
1475 evsel->attr.type = PERF_TYPE_SOFTWARE;
1476 evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK;
1477
1478 free(evsel->name);
1479 evsel->name = NULL;
1480 return true;
1481 }
1482
1483 return false;
1484}
1485
1486int perf_evsel__open_strerror(struct perf_evsel *evsel,
1487 struct perf_target *target,
1488 int err, char *msg, size_t size)
1489{
1490 switch (err) {
1491 case EPERM:
1492 case EACCES:
1493 return scnprintf(msg, size, "%s",
1494 "You may not have permission to collect %sstats.\n"
1495 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n"
1496 " -1 - Not paranoid at all\n"
1497 " 0 - Disallow raw tracepoint access for unpriv\n"
1498 " 1 - Disallow cpu events for unpriv\n"
1499 " 2 - Disallow kernel profiling for unpriv",
1500 target->system_wide ? "system-wide " : "");
1501 case ENOENT:
1502 return scnprintf(msg, size, "The %s event is not supported.",
1503 perf_evsel__name(evsel));
1504 case EMFILE:
1505 return scnprintf(msg, size, "%s",
1506 "Too many events are opened.\n"
1507 "Try again after reducing the number of events.");
1508 case ENODEV:
1509 if (target->cpu_list)
1510 return scnprintf(msg, size, "%s",
1511 "No such device - did you specify an out-of-range profile CPU?\n");
1512 break;
1513 case EOPNOTSUPP:
1514 if (evsel->attr.precise_ip)
1515 return scnprintf(msg, size, "%s",
1516 "\'precise\' request may not be supported. Try removing 'p' modifier.");
1517#if defined(__i386__) || defined(__x86_64__)
1518 if (evsel->attr.type == PERF_TYPE_HARDWARE)
1519 return scnprintf(msg, size, "%s",
1520 "No hardware sampling interrupt available.\n"
1521 "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
1522#endif
1523 break;
1524 default:
1525 break;
1526 }
1527
1528 return scnprintf(msg, size,
1529 "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n"
1530 "/bin/dmesg may provide additional information.\n"
1531 "No CONFIG_PERF_EVENTS=y kernel support configured?\n",
1532 err, strerror(err), perf_evsel__name(evsel));
1533}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 6f94d6dea00f..52021c3087df 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -3,7 +3,8 @@
3 3
4#include <linux/list.h> 4#include <linux/list.h>
5#include <stdbool.h> 5#include <stdbool.h>
6#include "../../../include/uapi/linux/perf_event.h" 6#include <stddef.h>
7#include <linux/perf_event.h>
7#include "types.h" 8#include "types.h"
8#include "xyarray.h" 9#include "xyarray.h"
9#include "cgroup.h" 10#include "cgroup.h"
@@ -52,6 +53,7 @@ struct perf_evsel {
52 struct xyarray *sample_id; 53 struct xyarray *sample_id;
53 u64 *id; 54 u64 *id;
54 struct perf_counts *counts; 55 struct perf_counts *counts;
56 struct perf_counts *prev_raw_counts;
55 int idx; 57 int idx;
56 u32 ids; 58 u32 ids;
57 struct hists hists; 59 struct hists hists;
@@ -72,10 +74,13 @@ struct perf_evsel {
72 bool needs_swap; 74 bool needs_swap;
73 /* parse modifier helper */ 75 /* parse modifier helper */
74 int exclude_GH; 76 int exclude_GH;
77 int nr_members;
75 struct perf_evsel *leader; 78 struct perf_evsel *leader;
76 char *group_name; 79 char *group_name;
77}; 80};
78 81
82#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
83
79struct cpu_map; 84struct cpu_map;
80struct thread_map; 85struct thread_map;
81struct perf_evlist; 86struct perf_evlist;
@@ -92,8 +97,7 @@ void perf_evsel__exit(struct perf_evsel *evsel);
92void perf_evsel__delete(struct perf_evsel *evsel); 97void perf_evsel__delete(struct perf_evsel *evsel);
93 98
94void perf_evsel__config(struct perf_evsel *evsel, 99void perf_evsel__config(struct perf_evsel *evsel,
95 struct perf_record_opts *opts, 100 struct perf_record_opts *opts);
96 struct perf_evsel *first);
97 101
98bool perf_evsel__is_cache_op_valid(u8 type, u8 op); 102bool perf_evsel__is_cache_op_valid(u8 type, u8 op);
99 103
@@ -110,14 +114,30 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
110int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, 114int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result,
111 char *bf, size_t size); 115 char *bf, size_t size);
112const char *perf_evsel__name(struct perf_evsel *evsel); 116const char *perf_evsel__name(struct perf_evsel *evsel);
117const char *perf_evsel__group_name(struct perf_evsel *evsel);
118int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
113 119
114int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 120int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
115int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 121int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
116int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 122int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
117void perf_evsel__free_fd(struct perf_evsel *evsel); 123void perf_evsel__free_fd(struct perf_evsel *evsel);
118void perf_evsel__free_id(struct perf_evsel *evsel); 124void perf_evsel__free_id(struct perf_evsel *evsel);
125void perf_evsel__free_counts(struct perf_evsel *evsel);
119void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 126void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
120 127
128void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
129 enum perf_event_sample_format bit);
130void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel,
131 enum perf_event_sample_format bit);
132
133#define perf_evsel__set_sample_bit(evsel, bit) \
134 __perf_evsel__set_sample_bit(evsel, PERF_SAMPLE_##bit)
135
136#define perf_evsel__reset_sample_bit(evsel, bit) \
137 __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit)
138
139void perf_evsel__set_sample_id(struct perf_evsel *evsel);
140
121int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 141int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
122 const char *filter); 142 const char *filter);
123 143
@@ -225,4 +245,35 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
225{ 245{
226 return list_entry(evsel->node.next, struct perf_evsel, node); 246 return list_entry(evsel->node.next, struct perf_evsel, node);
227} 247}
248
249static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel)
250{
251 return evsel->leader == evsel;
252}
253
254struct perf_attr_details {
255 bool freq;
256 bool verbose;
257 bool event_group;
258};
259
260int perf_evsel__fprintf(struct perf_evsel *evsel,
261 struct perf_attr_details *details, FILE *fp);
262
263bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
264 char *msg, size_t msgsize);
265int perf_evsel__open_strerror(struct perf_evsel *evsel,
266 struct perf_target *target,
267 int err, char *msg, size_t size);
268
269static inline int perf_evsel__group_idx(struct perf_evsel *evsel)
270{
271 return evsel->idx - evsel->leader->idx;
272}
273
274#define for_each_group_member(_evsel, _leader) \
275for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \
276 (_evsel) && (_evsel)->leader == (_leader); \
277 (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node))
278
228#endif /* __PERF_EVSEL_H */ 279#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7daad237dea5..f4bfd79ef6a7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,7 @@
23#include "pmu.h" 23#include "pmu.h"
24#include "vdso.h" 24#include "vdso.h"
25#include "strbuf.h" 25#include "strbuf.h"
26#include "build-id.h"
26 27
27static bool no_buildid_cache = false; 28static bool no_buildid_cache = false;
28 29
@@ -147,7 +148,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
147 u32 len; 148 u32 len;
148 char *buf; 149 char *buf;
149 150
150 sz = read(fd, &len, sizeof(len)); 151 sz = readn(fd, &len, sizeof(len));
151 if (sz < (ssize_t)sizeof(len)) 152 if (sz < (ssize_t)sizeof(len))
152 return NULL; 153 return NULL;
153 154
@@ -158,7 +159,7 @@ static char *do_read_string(int fd, struct perf_header *ph)
158 if (!buf) 159 if (!buf)
159 return NULL; 160 return NULL;
160 161
161 ret = read(fd, buf, len); 162 ret = readn(fd, buf, len);
162 if (ret == (ssize_t)len) { 163 if (ret == (ssize_t)len) {
163 /* 164 /*
164 * strings are padded by zeroes 165 * strings are padded by zeroes
@@ -286,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
286 struct perf_session *session = container_of(header, 287 struct perf_session *session = container_of(header,
287 struct perf_session, header); 288 struct perf_session, header);
288 struct rb_node *nd; 289 struct rb_node *nd;
289 int err = machine__write_buildid_table(&session->host_machine, fd); 290 int err = machine__write_buildid_table(&session->machines.host, fd);
290 291
291 if (err) 292 if (err)
292 return err; 293 return err;
293 294
294 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 295 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
295 struct machine *pos = rb_entry(nd, struct machine, rb_node); 296 struct machine *pos = rb_entry(nd, struct machine, rb_node);
296 err = machine__write_buildid_table(pos, fd); 297 err = machine__write_buildid_table(pos, fd);
297 if (err) 298 if (err)
@@ -312,7 +313,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
312 if (is_kallsyms) { 313 if (is_kallsyms) {
313 if (symbol_conf.kptr_restrict) { 314 if (symbol_conf.kptr_restrict) {
314 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); 315 pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
315 return 0; 316 err = 0;
317 goto out_free;
316 } 318 }
317 realname = (char *) name; 319 realname = (char *) name;
318 } else 320 } else
@@ -447,9 +449,9 @@ static int perf_session__cache_build_ids(struct perf_session *session)
447 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) 449 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
448 return -1; 450 return -1;
449 451
450 ret = machine__cache_build_ids(&session->host_machine, debugdir); 452 ret = machine__cache_build_ids(&session->machines.host, debugdir);
451 453
452 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 454 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
453 struct machine *pos = rb_entry(nd, struct machine, rb_node); 455 struct machine *pos = rb_entry(nd, struct machine, rb_node);
454 ret |= machine__cache_build_ids(pos, debugdir); 456 ret |= machine__cache_build_ids(pos, debugdir);
455 } 457 }
@@ -466,9 +468,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits)
466static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) 468static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
467{ 469{
468 struct rb_node *nd; 470 struct rb_node *nd;
469 bool ret = machine__read_build_ids(&session->host_machine, with_hits); 471 bool ret = machine__read_build_ids(&session->machines.host, with_hits);
470 472
471 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { 473 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
472 struct machine *pos = rb_entry(nd, struct machine, rb_node); 474 struct machine *pos = rb_entry(nd, struct machine, rb_node);
473 ret |= machine__read_build_ids(pos, with_hits); 475 ret |= machine__read_build_ids(pos, with_hits);
474 } 476 }
@@ -953,6 +955,7 @@ static int write_topo_node(int fd, int node)
953 } 955 }
954 956
955 fclose(fp); 957 fclose(fp);
958 fp = NULL;
956 959
957 ret = do_write(fd, &mem_total, sizeof(u64)); 960 ret = do_write(fd, &mem_total, sizeof(u64));
958 if (ret) 961 if (ret)
@@ -979,7 +982,8 @@ static int write_topo_node(int fd, int node)
979 ret = do_write_string(fd, buf); 982 ret = do_write_string(fd, buf);
980done: 983done:
981 free(buf); 984 free(buf);
982 fclose(fp); 985 if (fp)
986 fclose(fp);
983 return ret; 987 return ret;
984} 988}
985 989
@@ -1050,16 +1054,25 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1050 struct perf_pmu *pmu = NULL; 1054 struct perf_pmu *pmu = NULL;
1051 off_t offset = lseek(fd, 0, SEEK_CUR); 1055 off_t offset = lseek(fd, 0, SEEK_CUR);
1052 __u32 pmu_num = 0; 1056 __u32 pmu_num = 0;
1057 int ret;
1053 1058
1054 /* write real pmu_num later */ 1059 /* write real pmu_num later */
1055 do_write(fd, &pmu_num, sizeof(pmu_num)); 1060 ret = do_write(fd, &pmu_num, sizeof(pmu_num));
1061 if (ret < 0)
1062 return ret;
1056 1063
1057 while ((pmu = perf_pmu__scan(pmu))) { 1064 while ((pmu = perf_pmu__scan(pmu))) {
1058 if (!pmu->name) 1065 if (!pmu->name)
1059 continue; 1066 continue;
1060 pmu_num++; 1067 pmu_num++;
1061 do_write(fd, &pmu->type, sizeof(pmu->type)); 1068
1062 do_write_string(fd, pmu->name); 1069 ret = do_write(fd, &pmu->type, sizeof(pmu->type));
1070 if (ret < 0)
1071 return ret;
1072
1073 ret = do_write_string(fd, pmu->name);
1074 if (ret < 0)
1075 return ret;
1063 } 1076 }
1064 1077
1065 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) { 1078 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
@@ -1072,6 +1085,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1072} 1085}
1073 1086
1074/* 1087/*
1088 * File format:
1089 *
1090 * struct group_descs {
1091 * u32 nr_groups;
1092 * struct group_desc {
1093 * char name[];
1094 * u32 leader_idx;
1095 * u32 nr_members;
1096 * }[nr_groups];
1097 * };
1098 */
1099static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
1100 struct perf_evlist *evlist)
1101{
1102 u32 nr_groups = evlist->nr_groups;
1103 struct perf_evsel *evsel;
1104 int ret;
1105
1106 ret = do_write(fd, &nr_groups, sizeof(nr_groups));
1107 if (ret < 0)
1108 return ret;
1109
1110 list_for_each_entry(evsel, &evlist->entries, node) {
1111 if (perf_evsel__is_group_leader(evsel) &&
1112 evsel->nr_members > 1) {
1113 const char *name = evsel->group_name ?: "{anon_group}";
1114 u32 leader_idx = evsel->idx;
1115 u32 nr_members = evsel->nr_members;
1116
1117 ret = do_write_string(fd, name);
1118 if (ret < 0)
1119 return ret;
1120
1121 ret = do_write(fd, &leader_idx, sizeof(leader_idx));
1122 if (ret < 0)
1123 return ret;
1124
1125 ret = do_write(fd, &nr_members, sizeof(nr_members));
1126 if (ret < 0)
1127 return ret;
1128 }
1129 }
1130 return 0;
1131}
1132
1133/*
1075 * default get_cpuid(): nothing gets recorded 1134 * default get_cpuid(): nothing gets recorded
1076 * actual implementation must be in arch/$(ARCH)/util/header.c 1135 * actual implementation must be in arch/$(ARCH)/util/header.c
1077 */ 1136 */
@@ -1208,14 +1267,14 @@ read_event_desc(struct perf_header *ph, int fd)
1208 size_t msz; 1267 size_t msz;
1209 1268
1210 /* number of events */ 1269 /* number of events */
1211 ret = read(fd, &nre, sizeof(nre)); 1270 ret = readn(fd, &nre, sizeof(nre));
1212 if (ret != (ssize_t)sizeof(nre)) 1271 if (ret != (ssize_t)sizeof(nre))
1213 goto error; 1272 goto error;
1214 1273
1215 if (ph->needs_swap) 1274 if (ph->needs_swap)
1216 nre = bswap_32(nre); 1275 nre = bswap_32(nre);
1217 1276
1218 ret = read(fd, &sz, sizeof(sz)); 1277 ret = readn(fd, &sz, sizeof(sz));
1219 if (ret != (ssize_t)sizeof(sz)) 1278 if (ret != (ssize_t)sizeof(sz))
1220 goto error; 1279 goto error;
1221 1280
@@ -1243,7 +1302,7 @@ read_event_desc(struct perf_header *ph, int fd)
1243 * must read entire on-file attr struct to 1302 * must read entire on-file attr struct to
1244 * sync up with layout. 1303 * sync up with layout.
1245 */ 1304 */
1246 ret = read(fd, buf, sz); 1305 ret = readn(fd, buf, sz);
1247 if (ret != (ssize_t)sz) 1306 if (ret != (ssize_t)sz)
1248 goto error; 1307 goto error;
1249 1308
@@ -1252,7 +1311,7 @@ read_event_desc(struct perf_header *ph, int fd)
1252 1311
1253 memcpy(&evsel->attr, buf, msz); 1312 memcpy(&evsel->attr, buf, msz);
1254 1313
1255 ret = read(fd, &nr, sizeof(nr)); 1314 ret = readn(fd, &nr, sizeof(nr));
1256 if (ret != (ssize_t)sizeof(nr)) 1315 if (ret != (ssize_t)sizeof(nr))
1257 goto error; 1316 goto error;
1258 1317
@@ -1273,7 +1332,7 @@ read_event_desc(struct perf_header *ph, int fd)
1273 evsel->id = id; 1332 evsel->id = id;
1274 1333
1275 for (j = 0 ; j < nr; j++) { 1334 for (j = 0 ; j < nr; j++) {
1276 ret = read(fd, id, sizeof(*id)); 1335 ret = readn(fd, id, sizeof(*id));
1277 if (ret != (ssize_t)sizeof(*id)) 1336 if (ret != (ssize_t)sizeof(*id))
1278 goto error; 1337 goto error;
1279 if (ph->needs_swap) 1338 if (ph->needs_swap)
@@ -1378,6 +1437,8 @@ static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused,
1378 1437
1379 str = tmp + 1; 1438 str = tmp + 1;
1380 fprintf(fp, "# node%u cpu list : %s\n", c, str); 1439 fprintf(fp, "# node%u cpu list : %s\n", c, str);
1440
1441 str += strlen(str) + 1;
1381 } 1442 }
1382 return; 1443 return;
1383error: 1444error:
@@ -1432,6 +1493,31 @@ error:
1432 fprintf(fp, "# pmu mappings: unable to read\n"); 1493 fprintf(fp, "# pmu mappings: unable to read\n");
1433} 1494}
1434 1495
1496static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
1497 FILE *fp)
1498{
1499 struct perf_session *session;
1500 struct perf_evsel *evsel;
1501 u32 nr = 0;
1502
1503 session = container_of(ph, struct perf_session, header);
1504
1505 list_for_each_entry(evsel, &session->evlist->entries, node) {
1506 if (perf_evsel__is_group_leader(evsel) &&
1507 evsel->nr_members > 1) {
1508 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
1509 perf_evsel__name(evsel));
1510
1511 nr = evsel->nr_members - 1;
1512 } else if (nr) {
1513 fprintf(fp, ",%s", perf_evsel__name(evsel));
1514
1515 if (--nr == 0)
1516 fprintf(fp, "}\n");
1517 }
1518 }
1519}
1520
1435static int __event_process_build_id(struct build_id_event *bev, 1521static int __event_process_build_id(struct build_id_event *bev,
1436 char *filename, 1522 char *filename,
1437 struct perf_session *session) 1523 struct perf_session *session)
@@ -1503,14 +1589,14 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
1503 while (offset < limit) { 1589 while (offset < limit) {
1504 ssize_t len; 1590 ssize_t len;
1505 1591
1506 if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) 1592 if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
1507 return -1; 1593 return -1;
1508 1594
1509 if (header->needs_swap) 1595 if (header->needs_swap)
1510 perf_event_header__bswap(&old_bev.header); 1596 perf_event_header__bswap(&old_bev.header);
1511 1597
1512 len = old_bev.header.size - sizeof(old_bev); 1598 len = old_bev.header.size - sizeof(old_bev);
1513 if (read(input, filename, len) != len) 1599 if (readn(input, filename, len) != len)
1514 return -1; 1600 return -1;
1515 1601
1516 bev.header = old_bev.header; 1602 bev.header = old_bev.header;
@@ -1545,14 +1631,14 @@ static int perf_header__read_build_ids(struct perf_header *header,
1545 while (offset < limit) { 1631 while (offset < limit) {
1546 ssize_t len; 1632 ssize_t len;
1547 1633
1548 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 1634 if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
1549 goto out; 1635 goto out;
1550 1636
1551 if (header->needs_swap) 1637 if (header->needs_swap)
1552 perf_event_header__bswap(&bev.header); 1638 perf_event_header__bswap(&bev.header);
1553 1639
1554 len = bev.header.size - sizeof(bev); 1640 len = bev.header.size - sizeof(bev);
1555 if (read(input, filename, len) != len) 1641 if (readn(input, filename, len) != len)
1556 goto out; 1642 goto out;
1557 /* 1643 /*
1558 * The a1645ce1 changeset: 1644 * The a1645ce1 changeset:
@@ -1638,7 +1724,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1638 size_t ret; 1724 size_t ret;
1639 u32 nr; 1725 u32 nr;
1640 1726
1641 ret = read(fd, &nr, sizeof(nr)); 1727 ret = readn(fd, &nr, sizeof(nr));
1642 if (ret != sizeof(nr)) 1728 if (ret != sizeof(nr))
1643 return -1; 1729 return -1;
1644 1730
@@ -1647,7 +1733,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,
1647 1733
1648 ph->env.nr_cpus_online = nr; 1734 ph->env.nr_cpus_online = nr;
1649 1735
1650 ret = read(fd, &nr, sizeof(nr)); 1736 ret = readn(fd, &nr, sizeof(nr));
1651 if (ret != sizeof(nr)) 1737 if (ret != sizeof(nr))
1652 return -1; 1738 return -1;
1653 1739
@@ -1681,7 +1767,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused,
1681 uint64_t mem; 1767 uint64_t mem;
1682 size_t ret; 1768 size_t ret;
1683 1769
1684 ret = read(fd, &mem, sizeof(mem)); 1770 ret = readn(fd, &mem, sizeof(mem));
1685 if (ret != sizeof(mem)) 1771 if (ret != sizeof(mem))
1686 return -1; 1772 return -1;
1687 1773
@@ -1753,7 +1839,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,
1753 u32 nr, i; 1839 u32 nr, i;
1754 struct strbuf sb; 1840 struct strbuf sb;
1755 1841
1756 ret = read(fd, &nr, sizeof(nr)); 1842 ret = readn(fd, &nr, sizeof(nr));
1757 if (ret != sizeof(nr)) 1843 if (ret != sizeof(nr))
1758 return -1; 1844 return -1;
1759 1845
@@ -1789,7 +1875,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1789 char *str; 1875 char *str;
1790 struct strbuf sb; 1876 struct strbuf sb;
1791 1877
1792 ret = read(fd, &nr, sizeof(nr)); 1878 ret = readn(fd, &nr, sizeof(nr));
1793 if (ret != sizeof(nr)) 1879 if (ret != sizeof(nr))
1794 return -1; 1880 return -1;
1795 1881
@@ -1810,7 +1896,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused
1810 } 1896 }
1811 ph->env.sibling_cores = strbuf_detach(&sb, NULL); 1897 ph->env.sibling_cores = strbuf_detach(&sb, NULL);
1812 1898
1813 ret = read(fd, &nr, sizeof(nr)); 1899 ret = readn(fd, &nr, sizeof(nr));
1814 if (ret != sizeof(nr)) 1900 if (ret != sizeof(nr))
1815 return -1; 1901 return -1;
1816 1902
@@ -1847,7 +1933,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1847 struct strbuf sb; 1933 struct strbuf sb;
1848 1934
1849 /* nr nodes */ 1935 /* nr nodes */
1850 ret = read(fd, &nr, sizeof(nr)); 1936 ret = readn(fd, &nr, sizeof(nr));
1851 if (ret != sizeof(nr)) 1937 if (ret != sizeof(nr))
1852 goto error; 1938 goto error;
1853 1939
@@ -1859,15 +1945,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse
1859 1945
1860 for (i = 0; i < nr; i++) { 1946 for (i = 0; i < nr; i++) {
1861 /* node number */ 1947 /* node number */
1862 ret = read(fd, &node, sizeof(node)); 1948 ret = readn(fd, &node, sizeof(node));
1863 if (ret != sizeof(node)) 1949 if (ret != sizeof(node))
1864 goto error; 1950 goto error;
1865 1951
1866 ret = read(fd, &mem_total, sizeof(u64)); 1952 ret = readn(fd, &mem_total, sizeof(u64));
1867 if (ret != sizeof(u64)) 1953 if (ret != sizeof(u64))
1868 goto error; 1954 goto error;
1869 1955
1870 ret = read(fd, &mem_free, sizeof(u64)); 1956 ret = readn(fd, &mem_free, sizeof(u64));
1871 if (ret != sizeof(u64)) 1957 if (ret != sizeof(u64))
1872 goto error; 1958 goto error;
1873 1959
@@ -1906,7 +1992,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1906 u32 type; 1992 u32 type;
1907 struct strbuf sb; 1993 struct strbuf sb;
1908 1994
1909 ret = read(fd, &pmu_num, sizeof(pmu_num)); 1995 ret = readn(fd, &pmu_num, sizeof(pmu_num));
1910 if (ret != sizeof(pmu_num)) 1996 if (ret != sizeof(pmu_num))
1911 return -1; 1997 return -1;
1912 1998
@@ -1922,7 +2008,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
1922 strbuf_init(&sb, 128); 2008 strbuf_init(&sb, 128);
1923 2009
1924 while (pmu_num) { 2010 while (pmu_num) {
1925 if (read(fd, &type, sizeof(type)) != sizeof(type)) 2011 if (readn(fd, &type, sizeof(type)) != sizeof(type))
1926 goto error; 2012 goto error;
1927 if (ph->needs_swap) 2013 if (ph->needs_swap)
1928 type = bswap_32(type); 2014 type = bswap_32(type);
@@ -1946,6 +2032,98 @@ error:
1946 return -1; 2032 return -1;
1947} 2033}
1948 2034
2035static int process_group_desc(struct perf_file_section *section __maybe_unused,
2036 struct perf_header *ph, int fd,
2037 void *data __maybe_unused)
2038{
2039 size_t ret = -1;
2040 u32 i, nr, nr_groups;
2041 struct perf_session *session;
2042 struct perf_evsel *evsel, *leader = NULL;
2043 struct group_desc {
2044 char *name;
2045 u32 leader_idx;
2046 u32 nr_members;
2047 } *desc;
2048
2049 if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups))
2050 return -1;
2051
2052 if (ph->needs_swap)
2053 nr_groups = bswap_32(nr_groups);
2054
2055 ph->env.nr_groups = nr_groups;
2056 if (!nr_groups) {
2057 pr_debug("group desc not available\n");
2058 return 0;
2059 }
2060
2061 desc = calloc(nr_groups, sizeof(*desc));
2062 if (!desc)
2063 return -1;
2064
2065 for (i = 0; i < nr_groups; i++) {
2066 desc[i].name = do_read_string(fd, ph);
2067 if (!desc[i].name)
2068 goto out_free;
2069
2070 if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32))
2071 goto out_free;
2072
2073 if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32))
2074 goto out_free;
2075
2076 if (ph->needs_swap) {
2077 desc[i].leader_idx = bswap_32(desc[i].leader_idx);
2078 desc[i].nr_members = bswap_32(desc[i].nr_members);
2079 }
2080 }
2081
2082 /*
2083 * Rebuild group relationship based on the group_desc
2084 */
2085 session = container_of(ph, struct perf_session, header);
2086 session->evlist->nr_groups = nr_groups;
2087
2088 i = nr = 0;
2089 list_for_each_entry(evsel, &session->evlist->entries, node) {
2090 if (evsel->idx == (int) desc[i].leader_idx) {
2091 evsel->leader = evsel;
2092 /* {anon_group} is a dummy name */
2093 if (strcmp(desc[i].name, "{anon_group}"))
2094 evsel->group_name = desc[i].name;
2095 evsel->nr_members = desc[i].nr_members;
2096
2097 if (i >= nr_groups || nr > 0) {
2098 pr_debug("invalid group desc\n");
2099 goto out_free;
2100 }
2101
2102 leader = evsel;
2103 nr = evsel->nr_members - 1;
2104 i++;
2105 } else if (nr) {
2106 /* This is a group member */
2107 evsel->leader = leader;
2108
2109 nr--;
2110 }
2111 }
2112
2113 if (i != nr_groups || nr != 0) {
2114 pr_debug("invalid group desc\n");
2115 goto out_free;
2116 }
2117
2118 ret = 0;
2119out_free:
2120 while ((int) --i >= 0)
2121 free(desc[i].name);
2122 free(desc);
2123
2124 return ret;
2125}
2126
1949struct feature_ops { 2127struct feature_ops {
1950 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 2128 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1951 void (*print)(struct perf_header *h, int fd, FILE *fp); 2129 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1985,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1985 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), 2163 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1986 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), 2164 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1987 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 2165 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
2166 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1988}; 2167};
1989 2168
1990struct header_print_data { 2169struct header_print_data {
@@ -2074,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header,
2074 if (!nr_sections) 2253 if (!nr_sections)
2075 return 0; 2254 return 0;
2076 2255
2077 feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); 2256 feat_sec = p = calloc(nr_sections, sizeof(*feat_sec));
2078 if (feat_sec == NULL) 2257 if (feat_sec == NULL)
2079 return -ENOMEM; 2258 return -ENOMEM;
2080 2259
@@ -2246,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
2246 if (!nr_sections) 2425 if (!nr_sections)
2247 return 0; 2426 return 0;
2248 2427
2249 feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); 2428 feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec));
2250 if (!feat_sec) 2429 if (!feat_sec)
2251 return -1; 2430 return -1;
2252 2431
@@ -2340,6 +2519,16 @@ static int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
2340 return -1; 2519 return -1;
2341} 2520}
2342 2521
2522bool is_perf_magic(u64 magic)
2523{
2524 if (!memcmp(&magic, __perf_magic1, sizeof(magic))
2525 || magic == __perf_magic2
2526 || magic == __perf_magic2_sw)
2527 return true;
2528
2529 return false;
2530}
2531
2343static int check_magic_endian(u64 magic, uint64_t hdr_sz, 2532static int check_magic_endian(u64 magic, uint64_t hdr_sz,
2344 bool is_pipe, struct perf_header *ph) 2533 bool is_pipe, struct perf_header *ph)
2345{ 2534{
@@ -2899,16 +3088,22 @@ int perf_event__process_tracing_data(union perf_event *event,
2899 session->repipe); 3088 session->repipe);
2900 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3089 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
2901 3090
2902 if (read(session->fd, buf, padding) < 0) 3091 if (readn(session->fd, buf, padding) < 0) {
2903 die("reading input file"); 3092 pr_err("%s: reading input file", __func__);
3093 return -1;
3094 }
2904 if (session->repipe) { 3095 if (session->repipe) {
2905 int retw = write(STDOUT_FILENO, buf, padding); 3096 int retw = write(STDOUT_FILENO, buf, padding);
2906 if (retw <= 0 || retw != padding) 3097 if (retw <= 0 || retw != padding) {
2907 die("repiping tracing data padding"); 3098 pr_err("%s: repiping tracing data padding", __func__);
3099 return -1;
3100 }
2908 } 3101 }
2909 3102
2910 if (size_read + padding != size) 3103 if (size_read + padding != size) {
2911 die("tracing data size mismatch"); 3104 pr_err("%s: tracing data size mismatch", __func__);
3105 return -1;
3106 }
2912 3107
2913 perf_evlist__prepare_tracepoint_events(session->evlist, 3108 perf_evlist__prepare_tracepoint_events(session->evlist,
2914 session->pevent); 3109 session->pevent);
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 879d215cdac9..c9fc55cada6d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_HEADER_H 1#ifndef __PERF_HEADER_H
2#define __PERF_HEADER_H 2#define __PERF_HEADER_H
3 3
4#include "../../../include/uapi/linux/perf_event.h" 4#include <linux/perf_event.h>
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
@@ -29,6 +29,7 @@ enum {
29 HEADER_NUMA_TOPOLOGY, 29 HEADER_NUMA_TOPOLOGY,
30 HEADER_BRANCH_STACK, 30 HEADER_BRANCH_STACK,
31 HEADER_PMU_MAPPINGS, 31 HEADER_PMU_MAPPINGS,
32 HEADER_GROUP_DESC,
32 HEADER_LAST_FEATURE, 33 HEADER_LAST_FEATURE,
33 HEADER_FEAT_BITS = 256, 34 HEADER_FEAT_BITS = 256,
34}; 35};
@@ -79,6 +80,7 @@ struct perf_session_env {
79 char *numa_nodes; 80 char *numa_nodes;
80 int nr_pmu_mappings; 81 int nr_pmu_mappings;
81 char *pmu_mappings; 82 char *pmu_mappings;
83 int nr_groups;
82}; 84};
83 85
84struct perf_header { 86struct perf_header {
@@ -154,6 +156,7 @@ int perf_event__synthesize_build_id(struct perf_tool *tool,
154int perf_event__process_build_id(struct perf_tool *tool, 156int perf_event__process_build_id(struct perf_tool *tool,
155 union perf_event *event, 157 union perf_event *event,
156 struct perf_session *session); 158 struct perf_session *session);
159bool is_perf_magic(u64 magic);
157 160
158/* 161/*
159 * arch specific callback 162 * arch specific callback
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 277947a669b2..f855941bebea 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "hist.h" 4#include "hist.h"
5#include "session.h" 5#include "session.h"
6#include "sort.h" 6#include "sort.h"
7#include "evsel.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -82,6 +83,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
82 hists__new_col_len(hists, HISTC_DSO, len); 83 hists__new_col_len(hists, HISTC_DSO, len);
83 } 84 }
84 85
86 if (h->parent)
87 hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
88
85 if (h->branch_info) { 89 if (h->branch_info) {
86 int symlen; 90 int symlen;
87 /* 91 /*
@@ -242,14 +246,24 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
242 246
243 if (he->ms.map) 247 if (he->ms.map)
244 he->ms.map->referenced = true; 248 he->ms.map->referenced = true;
249
250 if (he->branch_info) {
251 if (he->branch_info->from.map)
252 he->branch_info->from.map->referenced = true;
253 if (he->branch_info->to.map)
254 he->branch_info->to.map->referenced = true;
255 }
256
245 if (symbol_conf.use_callchain) 257 if (symbol_conf.use_callchain)
246 callchain_init(he->callchain); 258 callchain_init(he->callchain);
259
260 INIT_LIST_HEAD(&he->pairs.node);
247 } 261 }
248 262
249 return he; 263 return he;
250} 264}
251 265
252static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) 266void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
253{ 267{
254 if (!h->filtered) { 268 if (!h->filtered) {
255 hists__calc_col_len(hists, h); 269 hists__calc_col_len(hists, h);
@@ -283,7 +297,13 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
283 parent = *p; 297 parent = *p;
284 he = rb_entry(parent, struct hist_entry, rb_node_in); 298 he = rb_entry(parent, struct hist_entry, rb_node_in);
285 299
286 cmp = hist_entry__cmp(entry, he); 300 /*
301 * Make sure that it receives arguments in a same order as
302 * hist_entry__collapse() so that we can use an appropriate
303 * function when searching an entry regardless which sort
304 * keys were used.
305 */
306 cmp = hist_entry__cmp(he, entry);
287 307
288 if (!cmp) { 308 if (!cmp) {
289 he_stat__add_period(&he->stat, period); 309 he_stat__add_period(&he->stat, period);
@@ -410,6 +430,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
410 430
411void hist_entry__free(struct hist_entry *he) 431void hist_entry__free(struct hist_entry *he)
412{ 432{
433 free(he->branch_info);
413 free(he); 434 free(he);
414} 435}
415 436
@@ -520,6 +541,62 @@ void hists__collapse_resort_threaded(struct hists *hists)
520 * reverse the map, sort on period. 541 * reverse the map, sort on period.
521 */ 542 */
522 543
544static int period_cmp(u64 period_a, u64 period_b)
545{
546 if (period_a > period_b)
547 return 1;
548 if (period_a < period_b)
549 return -1;
550 return 0;
551}
552
553static int hist_entry__sort_on_period(struct hist_entry *a,
554 struct hist_entry *b)
555{
556 int ret;
557 int i, nr_members;
558 struct perf_evsel *evsel;
559 struct hist_entry *pair;
560 u64 *periods_a, *periods_b;
561
562 ret = period_cmp(a->stat.period, b->stat.period);
563 if (ret || !symbol_conf.event_group)
564 return ret;
565
566 evsel = hists_to_evsel(a->hists);
567 nr_members = evsel->nr_members;
568 if (nr_members <= 1)
569 return ret;
570
571 periods_a = zalloc(sizeof(periods_a) * nr_members);
572 periods_b = zalloc(sizeof(periods_b) * nr_members);
573
574 if (!periods_a || !periods_b)
575 goto out;
576
577 list_for_each_entry(pair, &a->pairs.head, pairs.node) {
578 evsel = hists_to_evsel(pair->hists);
579 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period;
580 }
581
582 list_for_each_entry(pair, &b->pairs.head, pairs.node) {
583 evsel = hists_to_evsel(pair->hists);
584 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
585 }
586
587 for (i = 1; i < nr_members; i++) {
588 ret = period_cmp(periods_a[i], periods_b[i]);
589 if (ret)
590 break;
591 }
592
593out:
594 free(periods_a);
595 free(periods_b);
596
597 return ret;
598}
599
523static void __hists__insert_output_entry(struct rb_root *entries, 600static void __hists__insert_output_entry(struct rb_root *entries,
524 struct hist_entry *he, 601 struct hist_entry *he,
525 u64 min_callchain_hits) 602 u64 min_callchain_hits)
@@ -536,7 +613,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
536 parent = *p; 613 parent = *p;
537 iter = rb_entry(parent, struct hist_entry, rb_node); 614 iter = rb_entry(parent, struct hist_entry, rb_node);
538 615
539 if (he->stat.period > iter->stat.period) 616 if (hist_entry__sort_on_period(he, iter) > 0)
540 p = &(*p)->rb_left; 617 p = &(*p)->rb_left;
541 else 618 else
542 p = &(*p)->rb_right; 619 p = &(*p)->rb_right;
@@ -708,8 +785,134 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
708 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 785 return symbol__annotate(he->ms.sym, he->ms.map, privsize);
709} 786}
710 787
788void events_stats__inc(struct events_stats *stats, u32 type)
789{
790 ++stats->nr_events[0];
791 ++stats->nr_events[type];
792}
793
711void hists__inc_nr_events(struct hists *hists, u32 type) 794void hists__inc_nr_events(struct hists *hists, u32 type)
712{ 795{
713 ++hists->stats.nr_events[0]; 796 events_stats__inc(&hists->stats, type);
714 ++hists->stats.nr_events[type]; 797}
798
799static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
800 struct hist_entry *pair)
801{
802 struct rb_root *root;
803 struct rb_node **p;
804 struct rb_node *parent = NULL;
805 struct hist_entry *he;
806 int cmp;
807
808 if (sort__need_collapse)
809 root = &hists->entries_collapsed;
810 else
811 root = hists->entries_in;
812
813 p = &root->rb_node;
814
815 while (*p != NULL) {
816 parent = *p;
817 he = rb_entry(parent, struct hist_entry, rb_node_in);
818
819 cmp = hist_entry__collapse(he, pair);
820
821 if (!cmp)
822 goto out;
823
824 if (cmp < 0)
825 p = &(*p)->rb_left;
826 else
827 p = &(*p)->rb_right;
828 }
829
830 he = hist_entry__new(pair);
831 if (he) {
832 memset(&he->stat, 0, sizeof(he->stat));
833 he->hists = hists;
834 rb_link_node(&he->rb_node_in, parent, p);
835 rb_insert_color(&he->rb_node_in, root);
836 hists__inc_nr_entries(hists, he);
837 }
838out:
839 return he;
840}
841
842static struct hist_entry *hists__find_entry(struct hists *hists,
843 struct hist_entry *he)
844{
845 struct rb_node *n;
846
847 if (sort__need_collapse)
848 n = hists->entries_collapsed.rb_node;
849 else
850 n = hists->entries_in->rb_node;
851
852 while (n) {
853 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node_in);
854 int64_t cmp = hist_entry__collapse(iter, he);
855
856 if (cmp < 0)
857 n = n->rb_left;
858 else if (cmp > 0)
859 n = n->rb_right;
860 else
861 return iter;
862 }
863
864 return NULL;
865}
866
867/*
868 * Look for pairs to link to the leader buckets (hist_entries):
869 */
870void hists__match(struct hists *leader, struct hists *other)
871{
872 struct rb_root *root;
873 struct rb_node *nd;
874 struct hist_entry *pos, *pair;
875
876 if (sort__need_collapse)
877 root = &leader->entries_collapsed;
878 else
879 root = leader->entries_in;
880
881 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
882 pos = rb_entry(nd, struct hist_entry, rb_node_in);
883 pair = hists__find_entry(other, pos);
884
885 if (pair)
886 hist_entry__add_pair(pair, pos);
887 }
888}
889
890/*
891 * Look for entries in the other hists that are not present in the leader, if
892 * we find them, just add a dummy entry on the leader hists, with period=0,
893 * nr_events=0, to serve as the list header.
894 */
895int hists__link(struct hists *leader, struct hists *other)
896{
897 struct rb_root *root;
898 struct rb_node *nd;
899 struct hist_entry *pos, *pair;
900
901 if (sort__need_collapse)
902 root = &other->entries_collapsed;
903 else
904 root = other->entries_in;
905
906 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
907 pos = rb_entry(nd, struct hist_entry, rb_node_in);
908
909 if (!hist_entry__has_pairs(pos)) {
910 pair = hists__add_dummy_entry(leader, pos);
911 if (pair == NULL)
912 return -1;
913 hist_entry__add_pair(pos, pair);
914 }
915 }
916
917 return 0;
715} 918}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 66cb31fe81d2..38624686ee9a 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -4,6 +4,7 @@
4#include <linux/types.h> 4#include <linux/types.h>
5#include <pthread.h> 5#include <pthread.h>
6#include "callchain.h" 6#include "callchain.h"
7#include "header.h"
7 8
8extern struct callchain_param callchain_param; 9extern struct callchain_param callchain_param;
9 10
@@ -95,8 +96,10 @@ void hists__decay_entries_threaded(struct hists *hists, bool zap_user,
95 bool zap_kernel); 96 bool zap_kernel);
96void hists__output_recalc_col_len(struct hists *hists, int max_rows); 97void hists__output_recalc_col_len(struct hists *hists, int max_rows);
97 98
99void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
98void hists__inc_nr_events(struct hists *self, u32 type); 100void hists__inc_nr_events(struct hists *self, u32 type);
99size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); 101void events_stats__inc(struct events_stats *stats, u32 type);
102size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
100 103
101size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, 104size_t hists__fprintf(struct hists *self, bool show_header, int max_rows,
102 int max_cols, FILE *fp); 105 int max_cols, FILE *fp);
@@ -114,6 +117,9 @@ bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
114void hists__reset_col_len(struct hists *hists); 117void hists__reset_col_len(struct hists *hists);
115void hists__calc_col_len(struct hists *hists, struct hist_entry *he); 118void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
116 119
120void hists__match(struct hists *leader, struct hists *other);
121int hists__link(struct hists *leader, struct hists *other);
122
117struct perf_hpp { 123struct perf_hpp {
118 char *buf; 124 char *buf;
119 size_t size; 125 size_t size;
@@ -122,13 +128,19 @@ struct perf_hpp {
122}; 128};
123 129
124struct perf_hpp_fmt { 130struct perf_hpp_fmt {
125 bool cond;
126 int (*header)(struct perf_hpp *hpp); 131 int (*header)(struct perf_hpp *hpp);
127 int (*width)(struct perf_hpp *hpp); 132 int (*width)(struct perf_hpp *hpp);
128 int (*color)(struct perf_hpp *hpp, struct hist_entry *he); 133 int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
129 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); 134 int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
135
136 struct list_head list;
130}; 137};
131 138
139extern struct list_head perf_hpp__list;
140
141#define perf_hpp__for_each_format(format) \
142 list_for_each_entry(format, &perf_hpp__list, list)
143
132extern struct perf_hpp_fmt perf_hpp__format[]; 144extern struct perf_hpp_fmt perf_hpp__format[];
133 145
134enum { 146enum {
@@ -140,34 +152,44 @@ enum {
140 PERF_HPP__OVERHEAD_GUEST_US, 152 PERF_HPP__OVERHEAD_GUEST_US,
141 PERF_HPP__SAMPLES, 153 PERF_HPP__SAMPLES,
142 PERF_HPP__PERIOD, 154 PERF_HPP__PERIOD,
155 PERF_HPP__PERIOD_BASELINE,
143 PERF_HPP__DELTA, 156 PERF_HPP__DELTA,
144 PERF_HPP__DISPL, 157 PERF_HPP__RATIO,
158 PERF_HPP__WEIGHTED_DIFF,
159 PERF_HPP__FORMULA,
145 160
146 PERF_HPP__MAX_INDEX 161 PERF_HPP__MAX_INDEX
147}; 162};
148 163
149void perf_hpp__init(void); 164void perf_hpp__init(void);
150void perf_hpp__column_enable(unsigned col, bool enable); 165void perf_hpp__column_register(struct perf_hpp_fmt *format);
166void perf_hpp__column_enable(unsigned col);
151int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, 167int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
152 bool color); 168 bool color);
153 169
154struct perf_evlist; 170struct perf_evlist;
155 171
172struct hist_browser_timer {
173 void (*timer)(void *arg);
174 void *arg;
175 int refresh;
176};
177
156#ifdef NEWT_SUPPORT 178#ifdef NEWT_SUPPORT
157#include "../ui/keysyms.h" 179#include "../ui/keysyms.h"
158int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 180int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
159 void(*timer)(void *arg), void *arg, int delay_secs); 181 struct hist_browser_timer *hbt);
160 182
161int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, 183int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
162 void(*timer)(void *arg), void *arg, 184 struct hist_browser_timer *hbt,
163 int refresh); 185 struct perf_session_env *env);
186int script_browse(const char *script_opt);
164#else 187#else
165static inline 188static inline
166int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, 189int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
167 const char *help __maybe_unused, 190 const char *help __maybe_unused,
168 void(*timer)(void *arg) __maybe_unused, 191 struct hist_browser_timer *hbt __maybe_unused,
169 void *arg __maybe_unused, 192 struct perf_session_env *env __maybe_unused)
170 int refresh __maybe_unused)
171{ 193{
172 return 0; 194 return 0;
173} 195}
@@ -175,28 +197,29 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
175static inline int hist_entry__tui_annotate(struct hist_entry *self 197static inline int hist_entry__tui_annotate(struct hist_entry *self
176 __maybe_unused, 198 __maybe_unused,
177 int evidx __maybe_unused, 199 int evidx __maybe_unused,
178 void(*timer)(void *arg) 200 struct hist_browser_timer *hbt
179 __maybe_unused, 201 __maybe_unused)
180 void *arg __maybe_unused, 202{
181 int delay_secs __maybe_unused) 203 return 0;
204}
205
206static inline int script_browse(const char *script_opt __maybe_unused)
182{ 207{
183 return 0; 208 return 0;
184} 209}
210
185#define K_LEFT -1 211#define K_LEFT -1
186#define K_RIGHT -2 212#define K_RIGHT -2
187#endif 213#endif
188 214
189#ifdef GTK2_SUPPORT 215#ifdef GTK2_SUPPORT
190int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help, 216int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
191 void(*timer)(void *arg), void *arg, 217 struct hist_browser_timer *hbt __maybe_unused);
192 int refresh);
193#else 218#else
194static inline 219static inline
195int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, 220int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
196 const char *help __maybe_unused, 221 const char *help __maybe_unused,
197 void(*timer)(void *arg) __maybe_unused, 222 struct hist_browser_timer *hbt __maybe_unused)
198 void *arg __maybe_unused,
199 int refresh __maybe_unused)
200{ 223{
201 return 0; 224 return 0;
202} 225}
@@ -204,4 +227,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
204 227
205unsigned int hists__sort_list_width(struct hists *self); 228unsigned int hists__sort_list_width(struct hists *self);
206 229
230double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
231double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
232s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
233int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
234 char *buf, size_t size);
235double perf_diff__period_percent(struct hist_entry *he, u64 period);
207#endif /* __PERF_HIST_H */ 236#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index a55d8cf083c9..45cf10a562bd 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -14,6 +14,7 @@
14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 14#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) 15#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) 16#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
17#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE)
17 18
18#define for_each_set_bit(bit, addr, size) \ 19#define for_each_set_bit(bit, addr, size) \
19 for ((bit) = find_first_bit((addr), (size)); \ 20 for ((bit) = find_first_bit((addr), (size)); \
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
index 9d0740024ba8..11a8d86f7fea 100644
--- a/tools/perf/util/intlist.c
+++ b/tools/perf/util/intlist.c
@@ -59,16 +59,40 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
59 59
60struct int_node *intlist__find(struct intlist *ilist, int i) 60struct int_node *intlist__find(struct intlist *ilist, int i)
61{ 61{
62 struct int_node *node = NULL; 62 struct int_node *node;
63 struct rb_node *rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); 63 struct rb_node *rb_node;
64 64
65 if (ilist == NULL)
66 return NULL;
67
68 node = NULL;
69 rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
65 if (rb_node) 70 if (rb_node)
66 node = container_of(rb_node, struct int_node, rb_node); 71 node = container_of(rb_node, struct int_node, rb_node);
67 72
68 return node; 73 return node;
69} 74}
70 75
71struct intlist *intlist__new(void) 76static int intlist__parse_list(struct intlist *ilist, const char *s)
77{
78 char *sep;
79 int err;
80
81 do {
82 long value = strtol(s, &sep, 10);
83 err = -EINVAL;
84 if (*sep != ',' && *sep != '\0')
85 break;
86 err = intlist__add(ilist, value);
87 if (err)
88 break;
89 s = sep + 1;
90 } while (*sep != '\0');
91
92 return err;
93}
94
95struct intlist *intlist__new(const char *slist)
72{ 96{
73 struct intlist *ilist = malloc(sizeof(*ilist)); 97 struct intlist *ilist = malloc(sizeof(*ilist));
74 98
@@ -77,9 +101,15 @@ struct intlist *intlist__new(void)
77 ilist->rblist.node_cmp = intlist__node_cmp; 101 ilist->rblist.node_cmp = intlist__node_cmp;
78 ilist->rblist.node_new = intlist__node_new; 102 ilist->rblist.node_new = intlist__node_new;
79 ilist->rblist.node_delete = intlist__node_delete; 103 ilist->rblist.node_delete = intlist__node_delete;
104
105 if (slist && intlist__parse_list(ilist, slist))
106 goto out_delete;
80 } 107 }
81 108
82 return ilist; 109 return ilist;
110out_delete:
111 intlist__delete(ilist);
112 return NULL;
83} 113}
84 114
85void intlist__delete(struct intlist *ilist) 115void intlist__delete(struct intlist *ilist)
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
index 6d63ab90db50..62351dad848f 100644
--- a/tools/perf/util/intlist.h
+++ b/tools/perf/util/intlist.h
@@ -15,7 +15,7 @@ struct intlist {
15 struct rblist rblist; 15 struct rblist rblist;
16}; 16};
17 17
18struct intlist *intlist__new(void); 18struct intlist *intlist__new(const char *slist);
19void intlist__delete(struct intlist *ilist); 19void intlist__delete(struct intlist *ilist);
20 20
21void intlist__remove(struct intlist *ilist, struct int_node *in); 21void intlist__remove(struct intlist *ilist, struct int_node *in);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
new file mode 100644
index 000000000000..efdb38e65a92
--- /dev/null
+++ b/tools/perf/util/machine.c
@@ -0,0 +1,1226 @@
1#include "callchain.h"
2#include "debug.h"
3#include "event.h"
4#include "evsel.h"
5#include "hist.h"
6#include "machine.h"
7#include "map.h"
8#include "sort.h"
9#include "strlist.h"
10#include "thread.h"
11#include <stdbool.h>
12#include "unwind.h"
13
14int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
15{
16 map_groups__init(&machine->kmaps);
17 RB_CLEAR_NODE(&machine->rb_node);
18 INIT_LIST_HEAD(&machine->user_dsos);
19 INIT_LIST_HEAD(&machine->kernel_dsos);
20
21 machine->threads = RB_ROOT;
22 INIT_LIST_HEAD(&machine->dead_threads);
23 machine->last_match = NULL;
24
25 machine->kmaps.machine = machine;
26 machine->pid = pid;
27
28 machine->root_dir = strdup(root_dir);
29 if (machine->root_dir == NULL)
30 return -ENOMEM;
31
32 if (pid != HOST_KERNEL_ID) {
33 struct thread *thread = machine__findnew_thread(machine, pid);
34 char comm[64];
35
36 if (thread == NULL)
37 return -ENOMEM;
38
39 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
40 thread__set_comm(thread, comm);
41 }
42
43 return 0;
44}
45
46static void dsos__delete(struct list_head *dsos)
47{
48 struct dso *pos, *n;
49
50 list_for_each_entry_safe(pos, n, dsos, node) {
51 list_del(&pos->node);
52 dso__delete(pos);
53 }
54}
55
56void machine__delete_dead_threads(struct machine *machine)
57{
58 struct thread *n, *t;
59
60 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
61 list_del(&t->node);
62 thread__delete(t);
63 }
64}
65
66void machine__delete_threads(struct machine *machine)
67{
68 struct rb_node *nd = rb_first(&machine->threads);
69
70 while (nd) {
71 struct thread *t = rb_entry(nd, struct thread, rb_node);
72
73 rb_erase(&t->rb_node, &machine->threads);
74 nd = rb_next(nd);
75 thread__delete(t);
76 }
77}
78
79void machine__exit(struct machine *machine)
80{
81 map_groups__exit(&machine->kmaps);
82 dsos__delete(&machine->user_dsos);
83 dsos__delete(&machine->kernel_dsos);
84 free(machine->root_dir);
85 machine->root_dir = NULL;
86}
87
88void machine__delete(struct machine *machine)
89{
90 machine__exit(machine);
91 free(machine);
92}
93
94void machines__init(struct machines *machines)
95{
96 machine__init(&machines->host, "", HOST_KERNEL_ID);
97 machines->guests = RB_ROOT;
98}
99
100void machines__exit(struct machines *machines)
101{
102 machine__exit(&machines->host);
103 /* XXX exit guest */
104}
105
106struct machine *machines__add(struct machines *machines, pid_t pid,
107 const char *root_dir)
108{
109 struct rb_node **p = &machines->guests.rb_node;
110 struct rb_node *parent = NULL;
111 struct machine *pos, *machine = malloc(sizeof(*machine));
112
113 if (machine == NULL)
114 return NULL;
115
116 if (machine__init(machine, root_dir, pid) != 0) {
117 free(machine);
118 return NULL;
119 }
120
121 while (*p != NULL) {
122 parent = *p;
123 pos = rb_entry(parent, struct machine, rb_node);
124 if (pid < pos->pid)
125 p = &(*p)->rb_left;
126 else
127 p = &(*p)->rb_right;
128 }
129
130 rb_link_node(&machine->rb_node, parent, p);
131 rb_insert_color(&machine->rb_node, &machines->guests);
132
133 return machine;
134}
135
136struct machine *machines__find(struct machines *machines, pid_t pid)
137{
138 struct rb_node **p = &machines->guests.rb_node;
139 struct rb_node *parent = NULL;
140 struct machine *machine;
141 struct machine *default_machine = NULL;
142
143 if (pid == HOST_KERNEL_ID)
144 return &machines->host;
145
146 while (*p != NULL) {
147 parent = *p;
148 machine = rb_entry(parent, struct machine, rb_node);
149 if (pid < machine->pid)
150 p = &(*p)->rb_left;
151 else if (pid > machine->pid)
152 p = &(*p)->rb_right;
153 else
154 return machine;
155 if (!machine->pid)
156 default_machine = machine;
157 }
158
159 return default_machine;
160}
161
162struct machine *machines__findnew(struct machines *machines, pid_t pid)
163{
164 char path[PATH_MAX];
165 const char *root_dir = "";
166 struct machine *machine = machines__find(machines, pid);
167
168 if (machine && (machine->pid == pid))
169 goto out;
170
171 if ((pid != HOST_KERNEL_ID) &&
172 (pid != DEFAULT_GUEST_KERNEL_ID) &&
173 (symbol_conf.guestmount)) {
174 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
175 if (access(path, R_OK)) {
176 static struct strlist *seen;
177
178 if (!seen)
179 seen = strlist__new(true, NULL);
180
181 if (!strlist__has_entry(seen, path)) {
182 pr_err("Can't access file %s\n", path);
183 strlist__add(seen, path);
184 }
185 machine = NULL;
186 goto out;
187 }
188 root_dir = path;
189 }
190
191 machine = machines__add(machines, pid, root_dir);
192out:
193 return machine;
194}
195
196void machines__process_guests(struct machines *machines,
197 machine__process_t process, void *data)
198{
199 struct rb_node *nd;
200
201 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
202 struct machine *pos = rb_entry(nd, struct machine, rb_node);
203 process(pos, data);
204 }
205}
206
207char *machine__mmap_name(struct machine *machine, char *bf, size_t size)
208{
209 if (machine__is_host(machine))
210 snprintf(bf, size, "[%s]", "kernel.kallsyms");
211 else if (machine__is_default_guest(machine))
212 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
213 else {
214 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms",
215 machine->pid);
216 }
217
218 return bf;
219}
220
221void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
222{
223 struct rb_node *node;
224 struct machine *machine;
225
226 machines->host.id_hdr_size = id_hdr_size;
227
228 for (node = rb_first(&machines->guests); node; node = rb_next(node)) {
229 machine = rb_entry(node, struct machine, rb_node);
230 machine->id_hdr_size = id_hdr_size;
231 }
232
233 return;
234}
235
236static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid,
237 bool create)
238{
239 struct rb_node **p = &machine->threads.rb_node;
240 struct rb_node *parent = NULL;
241 struct thread *th;
242
243 /*
244 * Font-end cache - PID lookups come in blocks,
245 * so most of the time we dont have to look up
246 * the full rbtree:
247 */
248 if (machine->last_match && machine->last_match->pid == pid)
249 return machine->last_match;
250
251 while (*p != NULL) {
252 parent = *p;
253 th = rb_entry(parent, struct thread, rb_node);
254
255 if (th->pid == pid) {
256 machine->last_match = th;
257 return th;
258 }
259
260 if (pid < th->pid)
261 p = &(*p)->rb_left;
262 else
263 p = &(*p)->rb_right;
264 }
265
266 if (!create)
267 return NULL;
268
269 th = thread__new(pid);
270 if (th != NULL) {
271 rb_link_node(&th->rb_node, parent, p);
272 rb_insert_color(&th->rb_node, &machine->threads);
273 machine->last_match = th;
274 }
275
276 return th;
277}
278
279struct thread *machine__findnew_thread(struct machine *machine, pid_t pid)
280{
281 return __machine__findnew_thread(machine, pid, true);
282}
283
284struct thread *machine__find_thread(struct machine *machine, pid_t pid)
285{
286 return __machine__findnew_thread(machine, pid, false);
287}
288
289int machine__process_comm_event(struct machine *machine, union perf_event *event)
290{
291 struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
292
293 if (dump_trace)
294 perf_event__fprintf_comm(event, stdout);
295
296 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
297 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
298 return -1;
299 }
300
301 return 0;
302}
303
304int machine__process_lost_event(struct machine *machine __maybe_unused,
305 union perf_event *event)
306{
307 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
308 event->lost.id, event->lost.lost);
309 return 0;
310}
311
312struct map *machine__new_module(struct machine *machine, u64 start,
313 const char *filename)
314{
315 struct map *map;
316 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
317
318 if (dso == NULL)
319 return NULL;
320
321 map = map__new2(start, dso, MAP__FUNCTION);
322 if (map == NULL)
323 return NULL;
324
325 if (machine__is_host(machine))
326 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
327 else
328 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
329 map_groups__insert(&machine->kmaps, map);
330 return map;
331}
332
333size_t machines__fprintf_dsos(struct machines *machines, FILE *fp)
334{
335 struct rb_node *nd;
336 size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) +
337 __dsos__fprintf(&machines->host.user_dsos, fp);
338
339 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
340 struct machine *pos = rb_entry(nd, struct machine, rb_node);
341 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
342 ret += __dsos__fprintf(&pos->user_dsos, fp);
343 }
344
345 return ret;
346}
347
348size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
349 bool (skip)(struct dso *dso, int parm), int parm)
350{
351 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) +
352 __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm);
353}
354
355size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
356 bool (skip)(struct dso *dso, int parm), int parm)
357{
358 struct rb_node *nd;
359 size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm);
360
361 for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) {
362 struct machine *pos = rb_entry(nd, struct machine, rb_node);
363 ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm);
364 }
365 return ret;
366}
367
368size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
369{
370 int i;
371 size_t printed = 0;
372 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
373
374 if (kdso->has_build_id) {
375 char filename[PATH_MAX];
376 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
377 printed += fprintf(fp, "[0] %s\n", filename);
378 }
379
380 for (i = 0; i < vmlinux_path__nr_entries; ++i)
381 printed += fprintf(fp, "[%d] %s\n",
382 i + kdso->has_build_id, vmlinux_path[i]);
383
384 return printed;
385}
386
387size_t machine__fprintf(struct machine *machine, FILE *fp)
388{
389 size_t ret = 0;
390 struct rb_node *nd;
391
392 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
393 struct thread *pos = rb_entry(nd, struct thread, rb_node);
394
395 ret += thread__fprintf(pos, fp);
396 }
397
398 return ret;
399}
400
401static struct dso *machine__get_kernel(struct machine *machine)
402{
403 const char *vmlinux_name = NULL;
404 struct dso *kernel;
405
406 if (machine__is_host(machine)) {
407 vmlinux_name = symbol_conf.vmlinux_name;
408 if (!vmlinux_name)
409 vmlinux_name = "[kernel.kallsyms]";
410
411 kernel = dso__kernel_findnew(machine, vmlinux_name,
412 "[kernel]",
413 DSO_TYPE_KERNEL);
414 } else {
415 char bf[PATH_MAX];
416
417 if (machine__is_default_guest(machine))
418 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
419 if (!vmlinux_name)
420 vmlinux_name = machine__mmap_name(machine, bf,
421 sizeof(bf));
422
423 kernel = dso__kernel_findnew(machine, vmlinux_name,
424 "[guest.kernel]",
425 DSO_TYPE_GUEST_KERNEL);
426 }
427
428 if (kernel != NULL && (!kernel->has_build_id))
429 dso__read_running_kernel_build_id(kernel, machine);
430
431 return kernel;
432}
433
434struct process_args {
435 u64 start;
436};
437
438static int symbol__in_kernel(void *arg, const char *name,
439 char type __maybe_unused, u64 start)
440{
441 struct process_args *args = arg;
442
443 if (strchr(name, '['))
444 return 0;
445
446 args->start = start;
447 return 1;
448}
449
450/* Figure out the start address of kernel map from /proc/kallsyms */
451static u64 machine__get_kernel_start_addr(struct machine *machine)
452{
453 const char *filename;
454 char path[PATH_MAX];
455 struct process_args args;
456
457 if (machine__is_host(machine)) {
458 filename = "/proc/kallsyms";
459 } else {
460 if (machine__is_default_guest(machine))
461 filename = (char *)symbol_conf.default_guest_kallsyms;
462 else {
463 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
464 filename = path;
465 }
466 }
467
468 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
469 return 0;
470
471 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
472 return 0;
473
474 return args.start;
475}
476
477int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
478{
479 enum map_type type;
480 u64 start = machine__get_kernel_start_addr(machine);
481
482 for (type = 0; type < MAP__NR_TYPES; ++type) {
483 struct kmap *kmap;
484
485 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
486 if (machine->vmlinux_maps[type] == NULL)
487 return -1;
488
489 machine->vmlinux_maps[type]->map_ip =
490 machine->vmlinux_maps[type]->unmap_ip =
491 identity__map_ip;
492 kmap = map__kmap(machine->vmlinux_maps[type]);
493 kmap->kmaps = &machine->kmaps;
494 map_groups__insert(&machine->kmaps,
495 machine->vmlinux_maps[type]);
496 }
497
498 return 0;
499}
500
501void machine__destroy_kernel_maps(struct machine *machine)
502{
503 enum map_type type;
504
505 for (type = 0; type < MAP__NR_TYPES; ++type) {
506 struct kmap *kmap;
507
508 if (machine->vmlinux_maps[type] == NULL)
509 continue;
510
511 kmap = map__kmap(machine->vmlinux_maps[type]);
512 map_groups__remove(&machine->kmaps,
513 machine->vmlinux_maps[type]);
514 if (kmap->ref_reloc_sym) {
515 /*
516 * ref_reloc_sym is shared among all maps, so free just
517 * on one of them.
518 */
519 if (type == MAP__FUNCTION) {
520 free((char *)kmap->ref_reloc_sym->name);
521 kmap->ref_reloc_sym->name = NULL;
522 free(kmap->ref_reloc_sym);
523 }
524 kmap->ref_reloc_sym = NULL;
525 }
526
527 map__delete(machine->vmlinux_maps[type]);
528 machine->vmlinux_maps[type] = NULL;
529 }
530}
531
532int machines__create_guest_kernel_maps(struct machines *machines)
533{
534 int ret = 0;
535 struct dirent **namelist = NULL;
536 int i, items = 0;
537 char path[PATH_MAX];
538 pid_t pid;
539 char *endp;
540
541 if (symbol_conf.default_guest_vmlinux_name ||
542 symbol_conf.default_guest_modules ||
543 symbol_conf.default_guest_kallsyms) {
544 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
545 }
546
547 if (symbol_conf.guestmount) {
548 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
549 if (items <= 0)
550 return -ENOENT;
551 for (i = 0; i < items; i++) {
552 if (!isdigit(namelist[i]->d_name[0])) {
553 /* Filter out . and .. */
554 continue;
555 }
556 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
557 if ((*endp != '\0') ||
558 (endp == namelist[i]->d_name) ||
559 (errno == ERANGE)) {
560 pr_debug("invalid directory (%s). Skipping.\n",
561 namelist[i]->d_name);
562 continue;
563 }
564 sprintf(path, "%s/%s/proc/kallsyms",
565 symbol_conf.guestmount,
566 namelist[i]->d_name);
567 ret = access(path, R_OK);
568 if (ret) {
569 pr_debug("Can't access file %s\n", path);
570 goto failure;
571 }
572 machines__create_kernel_maps(machines, pid);
573 }
574failure:
575 free(namelist);
576 }
577
578 return ret;
579}
580
581void machines__destroy_kernel_maps(struct machines *machines)
582{
583 struct rb_node *next = rb_first(&machines->guests);
584
585 machine__destroy_kernel_maps(&machines->host);
586
587 while (next) {
588 struct machine *pos = rb_entry(next, struct machine, rb_node);
589
590 next = rb_next(&pos->rb_node);
591 rb_erase(&pos->rb_node, &machines->guests);
592 machine__delete(pos);
593 }
594}
595
596int machines__create_kernel_maps(struct machines *machines, pid_t pid)
597{
598 struct machine *machine = machines__findnew(machines, pid);
599
600 if (machine == NULL)
601 return -1;
602
603 return machine__create_kernel_maps(machine);
604}
605
606int machine__load_kallsyms(struct machine *machine, const char *filename,
607 enum map_type type, symbol_filter_t filter)
608{
609 struct map *map = machine->vmlinux_maps[type];
610 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
611
612 if (ret > 0) {
613 dso__set_loaded(map->dso, type);
614 /*
615 * Since /proc/kallsyms will have multiple sessions for the
616 * kernel, with modules between them, fixup the end of all
617 * sections.
618 */
619 __map_groups__fixup_end(&machine->kmaps, type);
620 }
621
622 return ret;
623}
624
625int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
626 symbol_filter_t filter)
627{
628 struct map *map = machine->vmlinux_maps[type];
629 int ret = dso__load_vmlinux_path(map->dso, map, filter);
630
631 if (ret > 0) {
632 dso__set_loaded(map->dso, type);
633 map__reloc_vmlinux(map);
634 }
635
636 return ret;
637}
638
639static void map_groups__fixup_end(struct map_groups *mg)
640{
641 int i;
642 for (i = 0; i < MAP__NR_TYPES; ++i)
643 __map_groups__fixup_end(mg, i);
644}
645
646static char *get_kernel_version(const char *root_dir)
647{
648 char version[PATH_MAX];
649 FILE *file;
650 char *name, *tmp;
651 const char *prefix = "Linux version ";
652
653 sprintf(version, "%s/proc/version", root_dir);
654 file = fopen(version, "r");
655 if (!file)
656 return NULL;
657
658 version[0] = '\0';
659 tmp = fgets(version, sizeof(version), file);
660 fclose(file);
661
662 name = strstr(version, prefix);
663 if (!name)
664 return NULL;
665 name += strlen(prefix);
666 tmp = strchr(name, ' ');
667 if (tmp)
668 *tmp = '\0';
669
670 return strdup(name);
671}
672
673static int map_groups__set_modules_path_dir(struct map_groups *mg,
674 const char *dir_name)
675{
676 struct dirent *dent;
677 DIR *dir = opendir(dir_name);
678 int ret = 0;
679
680 if (!dir) {
681 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
682 return -1;
683 }
684
685 while ((dent = readdir(dir)) != NULL) {
686 char path[PATH_MAX];
687 struct stat st;
688
689 /*sshfs might return bad dent->d_type, so we have to stat*/
690 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
691 if (stat(path, &st))
692 continue;
693
694 if (S_ISDIR(st.st_mode)) {
695 if (!strcmp(dent->d_name, ".") ||
696 !strcmp(dent->d_name, ".."))
697 continue;
698
699 ret = map_groups__set_modules_path_dir(mg, path);
700 if (ret < 0)
701 goto out;
702 } else {
703 char *dot = strrchr(dent->d_name, '.'),
704 dso_name[PATH_MAX];
705 struct map *map;
706 char *long_name;
707
708 if (dot == NULL || strcmp(dot, ".ko"))
709 continue;
710 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
711 (int)(dot - dent->d_name), dent->d_name);
712
713 strxfrchar(dso_name, '-', '_');
714 map = map_groups__find_by_name(mg, MAP__FUNCTION,
715 dso_name);
716 if (map == NULL)
717 continue;
718
719 long_name = strdup(path);
720 if (long_name == NULL) {
721 ret = -1;
722 goto out;
723 }
724 dso__set_long_name(map->dso, long_name);
725 map->dso->lname_alloc = 1;
726 dso__kernel_module_get_build_id(map->dso, "");
727 }
728 }
729
730out:
731 closedir(dir);
732 return ret;
733}
734
735static int machine__set_modules_path(struct machine *machine)
736{
737 char *version;
738 char modules_path[PATH_MAX];
739
740 version = get_kernel_version(machine->root_dir);
741 if (!version)
742 return -1;
743
744 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
745 machine->root_dir, version);
746 free(version);
747
748 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
749}
750
751static int machine__create_modules(struct machine *machine)
752{
753 char *line = NULL;
754 size_t n;
755 FILE *file;
756 struct map *map;
757 const char *modules;
758 char path[PATH_MAX];
759
760 if (machine__is_default_guest(machine))
761 modules = symbol_conf.default_guest_modules;
762 else {
763 sprintf(path, "%s/proc/modules", machine->root_dir);
764 modules = path;
765 }
766
767 if (symbol__restricted_filename(path, "/proc/modules"))
768 return -1;
769
770 file = fopen(modules, "r");
771 if (file == NULL)
772 return -1;
773
774 while (!feof(file)) {
775 char name[PATH_MAX];
776 u64 start;
777 char *sep;
778 int line_len;
779
780 line_len = getline(&line, &n, file);
781 if (line_len < 0)
782 break;
783
784 if (!line)
785 goto out_failure;
786
787 line[--line_len] = '\0'; /* \n */
788
789 sep = strrchr(line, 'x');
790 if (sep == NULL)
791 continue;
792
793 hex2u64(sep + 1, &start);
794
795 sep = strchr(line, ' ');
796 if (sep == NULL)
797 continue;
798
799 *sep = '\0';
800
801 snprintf(name, sizeof(name), "[%s]", line);
802 map = machine__new_module(machine, start, name);
803 if (map == NULL)
804 goto out_delete_line;
805 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
806 }
807
808 free(line);
809 fclose(file);
810
811 return machine__set_modules_path(machine);
812
813out_delete_line:
814 free(line);
815out_failure:
816 return -1;
817}
818
819int machine__create_kernel_maps(struct machine *machine)
820{
821 struct dso *kernel = machine__get_kernel(machine);
822
823 if (kernel == NULL ||
824 __machine__create_kernel_maps(machine, kernel) < 0)
825 return -1;
826
827 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
828 if (machine__is_host(machine))
829 pr_debug("Problems creating module maps, "
830 "continuing anyway...\n");
831 else
832 pr_debug("Problems creating module maps for guest %d, "
833 "continuing anyway...\n", machine->pid);
834 }
835
836 /*
837 * Now that we have all the maps created, just set the ->end of them:
838 */
839 map_groups__fixup_end(&machine->kmaps);
840 return 0;
841}
842
843static void machine__set_kernel_mmap_len(struct machine *machine,
844 union perf_event *event)
845{
846 int i;
847
848 for (i = 0; i < MAP__NR_TYPES; i++) {
849 machine->vmlinux_maps[i]->start = event->mmap.start;
850 machine->vmlinux_maps[i]->end = (event->mmap.start +
851 event->mmap.len);
852 /*
853 * Be a bit paranoid here, some perf.data file came with
854 * a zero sized synthesized MMAP event for the kernel.
855 */
856 if (machine->vmlinux_maps[i]->end == 0)
857 machine->vmlinux_maps[i]->end = ~0ULL;
858 }
859}
860
861static int machine__process_kernel_mmap_event(struct machine *machine,
862 union perf_event *event)
863{
864 struct map *map;
865 char kmmap_prefix[PATH_MAX];
866 enum dso_kernel_type kernel_type;
867 bool is_kernel_mmap;
868
869 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
870 if (machine__is_host(machine))
871 kernel_type = DSO_TYPE_KERNEL;
872 else
873 kernel_type = DSO_TYPE_GUEST_KERNEL;
874
875 is_kernel_mmap = memcmp(event->mmap.filename,
876 kmmap_prefix,
877 strlen(kmmap_prefix) - 1) == 0;
878 if (event->mmap.filename[0] == '/' ||
879 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
880
881 char short_module_name[1024];
882 char *name, *dot;
883
884 if (event->mmap.filename[0] == '/') {
885 name = strrchr(event->mmap.filename, '/');
886 if (name == NULL)
887 goto out_problem;
888
889 ++name; /* skip / */
890 dot = strrchr(name, '.');
891 if (dot == NULL)
892 goto out_problem;
893 snprintf(short_module_name, sizeof(short_module_name),
894 "[%.*s]", (int)(dot - name), name);
895 strxfrchar(short_module_name, '-', '_');
896 } else
897 strcpy(short_module_name, event->mmap.filename);
898
899 map = machine__new_module(machine, event->mmap.start,
900 event->mmap.filename);
901 if (map == NULL)
902 goto out_problem;
903
904 name = strdup(short_module_name);
905 if (name == NULL)
906 goto out_problem;
907
908 map->dso->short_name = name;
909 map->dso->sname_alloc = 1;
910 map->end = map->start + event->mmap.len;
911 } else if (is_kernel_mmap) {
912 const char *symbol_name = (event->mmap.filename +
913 strlen(kmmap_prefix));
914 /*
915 * Should be there already, from the build-id table in
916 * the header.
917 */
918 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
919 kmmap_prefix);
920 if (kernel == NULL)
921 goto out_problem;
922
923 kernel->kernel = kernel_type;
924 if (__machine__create_kernel_maps(machine, kernel) < 0)
925 goto out_problem;
926
927 machine__set_kernel_mmap_len(machine, event);
928
929 /*
930 * Avoid using a zero address (kptr_restrict) for the ref reloc
931 * symbol. Effectively having zero here means that at record
932 * time /proc/sys/kernel/kptr_restrict was non zero.
933 */
934 if (event->mmap.pgoff != 0) {
935 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
936 symbol_name,
937 event->mmap.pgoff);
938 }
939
940 if (machine__is_default_guest(machine)) {
941 /*
942 * preload dso of guest kernel and modules
943 */
944 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
945 NULL);
946 }
947 }
948 return 0;
949out_problem:
950 return -1;
951}
952
953int machine__process_mmap_event(struct machine *machine, union perf_event *event)
954{
955 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
956 struct thread *thread;
957 struct map *map;
958 int ret = 0;
959
960 if (dump_trace)
961 perf_event__fprintf_mmap(event, stdout);
962
963 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
964 cpumode == PERF_RECORD_MISC_KERNEL) {
965 ret = machine__process_kernel_mmap_event(machine, event);
966 if (ret < 0)
967 goto out_problem;
968 return 0;
969 }
970
971 thread = machine__findnew_thread(machine, event->mmap.pid);
972 if (thread == NULL)
973 goto out_problem;
974 map = map__new(&machine->user_dsos, event->mmap.start,
975 event->mmap.len, event->mmap.pgoff,
976 event->mmap.pid, event->mmap.filename,
977 MAP__FUNCTION);
978 if (map == NULL)
979 goto out_problem;
980
981 thread__insert_map(thread, map);
982 return 0;
983
984out_problem:
985 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
986 return 0;
987}
988
989int machine__process_fork_event(struct machine *machine, union perf_event *event)
990{
991 struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
992 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
993
994 if (dump_trace)
995 perf_event__fprintf_task(event, stdout);
996
997 if (thread == NULL || parent == NULL ||
998 thread__fork(thread, parent) < 0) {
999 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1000 return -1;
1001 }
1002
1003 return 0;
1004}
1005
1006int machine__process_exit_event(struct machine *machine, union perf_event *event)
1007{
1008 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1009
1010 if (dump_trace)
1011 perf_event__fprintf_task(event, stdout);
1012
1013 if (thread != NULL)
1014 machine__remove_thread(machine, thread);
1015
1016 return 0;
1017}
1018
1019int machine__process_event(struct machine *machine, union perf_event *event)
1020{
1021 int ret;
1022
1023 switch (event->header.type) {
1024 case PERF_RECORD_COMM:
1025 ret = machine__process_comm_event(machine, event); break;
1026 case PERF_RECORD_MMAP:
1027 ret = machine__process_mmap_event(machine, event); break;
1028 case PERF_RECORD_FORK:
1029 ret = machine__process_fork_event(machine, event); break;
1030 case PERF_RECORD_EXIT:
1031 ret = machine__process_exit_event(machine, event); break;
1032 case PERF_RECORD_LOST:
1033 ret = machine__process_lost_event(machine, event); break;
1034 default:
1035 ret = -1;
1036 break;
1037 }
1038
1039 return ret;
1040}
1041
1042void machine__remove_thread(struct machine *machine, struct thread *th)
1043{
1044 machine->last_match = NULL;
1045 rb_erase(&th->rb_node, &machine->threads);
1046 /*
1047 * We may have references to this thread, for instance in some hist_entry
1048 * instances, so just move them to a separate list.
1049 */
1050 list_add_tail(&th->node, &machine->dead_threads);
1051}
1052
1053static bool symbol__match_parent_regex(struct symbol *sym)
1054{
1055 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
1056 return 1;
1057
1058 return 0;
1059}
1060
1061static const u8 cpumodes[] = {
1062 PERF_RECORD_MISC_USER,
1063 PERF_RECORD_MISC_KERNEL,
1064 PERF_RECORD_MISC_GUEST_USER,
1065 PERF_RECORD_MISC_GUEST_KERNEL
1066};
1067#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
1068
1069static void ip__resolve_ams(struct machine *machine, struct thread *thread,
1070 struct addr_map_symbol *ams,
1071 u64 ip)
1072{
1073 struct addr_location al;
1074 size_t i;
1075 u8 m;
1076
1077 memset(&al, 0, sizeof(al));
1078
1079 for (i = 0; i < NCPUMODES; i++) {
1080 m = cpumodes[i];
1081 /*
1082 * We cannot use the header.misc hint to determine whether a
1083 * branch stack address is user, kernel, guest, hypervisor.
1084 * Branches may straddle the kernel/user/hypervisor boundaries.
1085 * Thus, we have to try consecutively until we find a match
1086 * or else, the symbol is unknown
1087 */
1088 thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
1089 ip, &al, NULL);
1090 if (al.sym)
1091 goto found;
1092 }
1093found:
1094 ams->addr = ip;
1095 ams->al_addr = al.addr;
1096 ams->sym = al.sym;
1097 ams->map = al.map;
1098}
1099
1100struct branch_info *machine__resolve_bstack(struct machine *machine,
1101 struct thread *thr,
1102 struct branch_stack *bs)
1103{
1104 struct branch_info *bi;
1105 unsigned int i;
1106
1107 bi = calloc(bs->nr, sizeof(struct branch_info));
1108 if (!bi)
1109 return NULL;
1110
1111 for (i = 0; i < bs->nr; i++) {
1112 ip__resolve_ams(machine, thr, &bi[i].to, bs->entries[i].to);
1113 ip__resolve_ams(machine, thr, &bi[i].from, bs->entries[i].from);
1114 bi[i].flags = bs->entries[i].flags;
1115 }
1116 return bi;
1117}
1118
1119static int machine__resolve_callchain_sample(struct machine *machine,
1120 struct thread *thread,
1121 struct ip_callchain *chain,
1122 struct symbol **parent)
1123
1124{
1125 u8 cpumode = PERF_RECORD_MISC_USER;
1126 unsigned int i;
1127 int err;
1128
1129 callchain_cursor_reset(&callchain_cursor);
1130
1131 if (chain->nr > PERF_MAX_STACK_DEPTH) {
1132 pr_warning("corrupted callchain. skipping...\n");
1133 return 0;
1134 }
1135
1136 for (i = 0; i < chain->nr; i++) {
1137 u64 ip;
1138 struct addr_location al;
1139
1140 if (callchain_param.order == ORDER_CALLEE)
1141 ip = chain->ips[i];
1142 else
1143 ip = chain->ips[chain->nr - i - 1];
1144
1145 if (ip >= PERF_CONTEXT_MAX) {
1146 switch (ip) {
1147 case PERF_CONTEXT_HV:
1148 cpumode = PERF_RECORD_MISC_HYPERVISOR;
1149 break;
1150 case PERF_CONTEXT_KERNEL:
1151 cpumode = PERF_RECORD_MISC_KERNEL;
1152 break;
1153 case PERF_CONTEXT_USER:
1154 cpumode = PERF_RECORD_MISC_USER;
1155 break;
1156 default:
1157 pr_debug("invalid callchain context: "
1158 "%"PRId64"\n", (s64) ip);
1159 /*
1160 * It seems the callchain is corrupted.
1161 * Discard all.
1162 */
1163 callchain_cursor_reset(&callchain_cursor);
1164 return 0;
1165 }
1166 continue;
1167 }
1168
1169 al.filtered = false;
1170 thread__find_addr_location(thread, machine, cpumode,
1171 MAP__FUNCTION, ip, &al, NULL);
1172 if (al.sym != NULL) {
1173 if (sort__has_parent && !*parent &&
1174 symbol__match_parent_regex(al.sym))
1175 *parent = al.sym;
1176 if (!symbol_conf.use_callchain)
1177 break;
1178 }
1179
1180 err = callchain_cursor_append(&callchain_cursor,
1181 ip, al.map, al.sym);
1182 if (err)
1183 return err;
1184 }
1185
1186 return 0;
1187}
1188
1189static int unwind_entry(struct unwind_entry *entry, void *arg)
1190{
1191 struct callchain_cursor *cursor = arg;
1192 return callchain_cursor_append(cursor, entry->ip,
1193 entry->map, entry->sym);
1194}
1195
1196int machine__resolve_callchain(struct machine *machine,
1197 struct perf_evsel *evsel,
1198 struct thread *thread,
1199 struct perf_sample *sample,
1200 struct symbol **parent)
1201
1202{
1203 int ret;
1204
1205 callchain_cursor_reset(&callchain_cursor);
1206
1207 ret = machine__resolve_callchain_sample(machine, thread,
1208 sample->callchain, parent);
1209 if (ret)
1210 return ret;
1211
1212 /* Can we do dwarf post unwind? */
1213 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
1214 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
1215 return 0;
1216
1217 /* Bail out if nothing was captured. */
1218 if ((!sample->user_regs.regs) ||
1219 (!sample->user_stack.size))
1220 return 0;
1221
1222 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
1223 thread, evsel->attr.sample_regs_user,
1224 sample);
1225
1226}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
new file mode 100644
index 000000000000..5ac5892f2326
--- /dev/null
+++ b/tools/perf/util/machine.h
@@ -0,0 +1,157 @@
1#ifndef __PERF_MACHINE_H
2#define __PERF_MACHINE_H
3
4#include <sys/types.h>
5#include <linux/rbtree.h>
6#include "map.h"
7
8struct branch_stack;
9struct perf_evsel;
10struct perf_sample;
11struct symbol;
12struct thread;
13union perf_event;
14
15/* Native host kernel uses -1 as pid index in machine */
16#define HOST_KERNEL_ID (-1)
17#define DEFAULT_GUEST_KERNEL_ID (0)
18
19struct machine {
20 struct rb_node rb_node;
21 pid_t pid;
22 u16 id_hdr_size;
23 char *root_dir;
24 struct rb_root threads;
25 struct list_head dead_threads;
26 struct thread *last_match;
27 struct list_head user_dsos;
28 struct list_head kernel_dsos;
29 struct map_groups kmaps;
30 struct map *vmlinux_maps[MAP__NR_TYPES];
31};
32
33static inline
34struct map *machine__kernel_map(struct machine *machine, enum map_type type)
35{
36 return machine->vmlinux_maps[type];
37}
38
39struct thread *machine__find_thread(struct machine *machine, pid_t pid);
40
41int machine__process_comm_event(struct machine *machine, union perf_event *event);
42int machine__process_exit_event(struct machine *machine, union perf_event *event);
43int machine__process_fork_event(struct machine *machine, union perf_event *event);
44int machine__process_lost_event(struct machine *machine, union perf_event *event);
45int machine__process_mmap_event(struct machine *machine, union perf_event *event);
46int machine__process_event(struct machine *machine, union perf_event *event);
47
48typedef void (*machine__process_t)(struct machine *machine, void *data);
49
50struct machines {
51 struct machine host;
52 struct rb_root guests;
53};
54
55void machines__init(struct machines *machines);
56void machines__exit(struct machines *machines);
57
58void machines__process_guests(struct machines *machines,
59 machine__process_t process, void *data);
60
61struct machine *machines__add(struct machines *machines, pid_t pid,
62 const char *root_dir);
63struct machine *machines__find_host(struct machines *machines);
64struct machine *machines__find(struct machines *machines, pid_t pid);
65struct machine *machines__findnew(struct machines *machines, pid_t pid);
66
67void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size);
68char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
69
70int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
71void machine__exit(struct machine *machine);
72void machine__delete_dead_threads(struct machine *machine);
73void machine__delete_threads(struct machine *machine);
74void machine__delete(struct machine *machine);
75
76struct branch_info *machine__resolve_bstack(struct machine *machine,
77 struct thread *thread,
78 struct branch_stack *bs);
79int machine__resolve_callchain(struct machine *machine,
80 struct perf_evsel *evsel,
81 struct thread *thread,
82 struct perf_sample *sample,
83 struct symbol **parent);
84
85/*
86 * Default guest kernel is defined by parameter --guestkallsyms
87 * and --guestmodules
88 */
89static inline bool machine__is_default_guest(struct machine *machine)
90{
91 return machine ? machine->pid == DEFAULT_GUEST_KERNEL_ID : false;
92}
93
94static inline bool machine__is_host(struct machine *machine)
95{
96 return machine ? machine->pid == HOST_KERNEL_ID : false;
97}
98
99struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
100void machine__remove_thread(struct machine *machine, struct thread *th);
101
102size_t machine__fprintf(struct machine *machine, FILE *fp);
103
104static inline
105struct symbol *machine__find_kernel_symbol(struct machine *machine,
106 enum map_type type, u64 addr,
107 struct map **mapp,
108 symbol_filter_t filter)
109{
110 return map_groups__find_symbol(&machine->kmaps, type, addr,
111 mapp, filter);
112}
113
114static inline
115struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr,
116 struct map **mapp,
117 symbol_filter_t filter)
118{
119 return machine__find_kernel_symbol(machine, MAP__FUNCTION, addr,
120 mapp, filter);
121}
122
123static inline
124struct symbol *machine__find_kernel_function_by_name(struct machine *machine,
125 const char *name,
126 struct map **mapp,
127 symbol_filter_t filter)
128{
129 return map_groups__find_function_by_name(&machine->kmaps, name, mapp,
130 filter);
131}
132
133struct map *machine__new_module(struct machine *machine, u64 start,
134 const char *filename);
135
136int machine__load_kallsyms(struct machine *machine, const char *filename,
137 enum map_type type, symbol_filter_t filter);
138int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
139 symbol_filter_t filter);
140
141size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
142 bool (skip)(struct dso *dso, int parm), int parm);
143size_t machines__fprintf_dsos(struct machines *machines, FILE *fp);
144size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp,
145 bool (skip)(struct dso *dso, int parm), int parm);
146
147void machine__destroy_kernel_maps(struct machine *machine);
148int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
149int machine__create_kernel_maps(struct machine *machine);
150
151int machines__create_kernel_maps(struct machines *machines, pid_t pid);
152int machines__create_guest_kernel_maps(struct machines *machines);
153void machines__destroy_kernel_maps(struct machines *machines);
154
155size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
156
157#endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 6109fa4d14cd..6fcb9de62340 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -10,6 +10,8 @@
10#include "thread.h" 10#include "thread.h"
11#include "strlist.h" 11#include "strlist.h"
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h"
14#include <linux/string.h>
13 15
14const char *map_type__name[MAP__NR_TYPES] = { 16const char *map_type__name[MAP__NR_TYPES] = {
15 [MAP__FUNCTION] = "Functions", 17 [MAP__FUNCTION] = "Functions",
@@ -18,38 +20,39 @@ const char *map_type__name[MAP__NR_TYPES] = {
18 20
19static inline int is_anon_memory(const char *filename) 21static inline int is_anon_memory(const char *filename)
20{ 22{
21 return strcmp(filename, "//anon") == 0; 23 return !strcmp(filename, "//anon") ||
24 !strcmp(filename, "/anon_hugepage (deleted)");
22} 25}
23 26
24static inline int is_no_dso_memory(const char *filename) 27static inline int is_no_dso_memory(const char *filename)
25{ 28{
26 return !strcmp(filename, "[stack]") || 29 return !strncmp(filename, "[stack", 6) ||
27 !strcmp(filename, "[heap]"); 30 !strcmp(filename, "[heap]");
28} 31}
29 32
30void map__init(struct map *self, enum map_type type, 33void map__init(struct map *map, enum map_type type,
31 u64 start, u64 end, u64 pgoff, struct dso *dso) 34 u64 start, u64 end, u64 pgoff, struct dso *dso)
32{ 35{
33 self->type = type; 36 map->type = type;
34 self->start = start; 37 map->start = start;
35 self->end = end; 38 map->end = end;
36 self->pgoff = pgoff; 39 map->pgoff = pgoff;
37 self->dso = dso; 40 map->dso = dso;
38 self->map_ip = map__map_ip; 41 map->map_ip = map__map_ip;
39 self->unmap_ip = map__unmap_ip; 42 map->unmap_ip = map__unmap_ip;
40 RB_CLEAR_NODE(&self->rb_node); 43 RB_CLEAR_NODE(&map->rb_node);
41 self->groups = NULL; 44 map->groups = NULL;
42 self->referenced = false; 45 map->referenced = false;
43 self->erange_warned = false; 46 map->erange_warned = false;
44} 47}
45 48
46struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 49struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
47 u64 pgoff, u32 pid, char *filename, 50 u64 pgoff, u32 pid, char *filename,
48 enum map_type type) 51 enum map_type type)
49{ 52{
50 struct map *self = malloc(sizeof(*self)); 53 struct map *map = malloc(sizeof(*map));
51 54
52 if (self != NULL) { 55 if (map != NULL) {
53 char newfilename[PATH_MAX]; 56 char newfilename[PATH_MAX];
54 struct dso *dso; 57 struct dso *dso;
55 int anon, no_dso, vdso; 58 int anon, no_dso, vdso;
@@ -72,10 +75,10 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
72 if (dso == NULL) 75 if (dso == NULL)
73 goto out_delete; 76 goto out_delete;
74 77
75 map__init(self, type, start, start + len, pgoff, dso); 78 map__init(map, type, start, start + len, pgoff, dso);
76 79
77 if (anon || no_dso) { 80 if (anon || no_dso) {
78 self->map_ip = self->unmap_ip = identity__map_ip; 81 map->map_ip = map->unmap_ip = identity__map_ip;
79 82
80 /* 83 /*
81 * Set memory without DSO as loaded. All map__find_* 84 * Set memory without DSO as loaded. All map__find_*
@@ -83,12 +86,12 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
83 * unnecessary map__load warning. 86 * unnecessary map__load warning.
84 */ 87 */
85 if (no_dso) 88 if (no_dso)
86 dso__set_loaded(dso, self->type); 89 dso__set_loaded(dso, map->type);
87 } 90 }
88 } 91 }
89 return self; 92 return map;
90out_delete: 93out_delete:
91 free(self); 94 free(map);
92 return NULL; 95 return NULL;
93} 96}
94 97
@@ -111,48 +114,48 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
111 return map; 114 return map;
112} 115}
113 116
114void map__delete(struct map *self) 117void map__delete(struct map *map)
115{ 118{
116 free(self); 119 free(map);
117} 120}
118 121
119void map__fixup_start(struct map *self) 122void map__fixup_start(struct map *map)
120{ 123{
121 struct rb_root *symbols = &self->dso->symbols[self->type]; 124 struct rb_root *symbols = &map->dso->symbols[map->type];
122 struct rb_node *nd = rb_first(symbols); 125 struct rb_node *nd = rb_first(symbols);
123 if (nd != NULL) { 126 if (nd != NULL) {
124 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 127 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
125 self->start = sym->start; 128 map->start = sym->start;
126 } 129 }
127} 130}
128 131
129void map__fixup_end(struct map *self) 132void map__fixup_end(struct map *map)
130{ 133{
131 struct rb_root *symbols = &self->dso->symbols[self->type]; 134 struct rb_root *symbols = &map->dso->symbols[map->type];
132 struct rb_node *nd = rb_last(symbols); 135 struct rb_node *nd = rb_last(symbols);
133 if (nd != NULL) { 136 if (nd != NULL) {
134 struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 137 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
135 self->end = sym->end; 138 map->end = sym->end;
136 } 139 }
137} 140}
138 141
139#define DSO__DELETED "(deleted)" 142#define DSO__DELETED "(deleted)"
140 143
141int map__load(struct map *self, symbol_filter_t filter) 144int map__load(struct map *map, symbol_filter_t filter)
142{ 145{
143 const char *name = self->dso->long_name; 146 const char *name = map->dso->long_name;
144 int nr; 147 int nr;
145 148
146 if (dso__loaded(self->dso, self->type)) 149 if (dso__loaded(map->dso, map->type))
147 return 0; 150 return 0;
148 151
149 nr = dso__load(self->dso, self, filter); 152 nr = dso__load(map->dso, map, filter);
150 if (nr < 0) { 153 if (nr < 0) {
151 if (self->dso->has_build_id) { 154 if (map->dso->has_build_id) {
152 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 155 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
153 156
154 build_id__sprintf(self->dso->build_id, 157 build_id__sprintf(map->dso->build_id,
155 sizeof(self->dso->build_id), 158 sizeof(map->dso->build_id),
156 sbuild_id); 159 sbuild_id);
157 pr_warning("%s with build id %s not found", 160 pr_warning("%s with build id %s not found",
158 name, sbuild_id); 161 name, sbuild_id);
@@ -182,43 +185,36 @@ int map__load(struct map *self, symbol_filter_t filter)
182 * Only applies to the kernel, as its symtabs aren't relative like the 185 * Only applies to the kernel, as its symtabs aren't relative like the
183 * module ones. 186 * module ones.
184 */ 187 */
185 if (self->dso->kernel) 188 if (map->dso->kernel)
186 map__reloc_vmlinux(self); 189 map__reloc_vmlinux(map);
187 190
188 return 0; 191 return 0;
189} 192}
190 193
191struct symbol *map__find_symbol(struct map *self, u64 addr, 194struct symbol *map__find_symbol(struct map *map, u64 addr,
192 symbol_filter_t filter) 195 symbol_filter_t filter)
193{ 196{
194 if (map__load(self, filter) < 0) 197 if (map__load(map, filter) < 0)
195 return NULL; 198 return NULL;
196 199
197 return dso__find_symbol(self->dso, self->type, addr); 200 return dso__find_symbol(map->dso, map->type, addr);
198} 201}
199 202
200struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 203struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
201 symbol_filter_t filter) 204 symbol_filter_t filter)
202{ 205{
203 if (map__load(self, filter) < 0) 206 if (map__load(map, filter) < 0)
204 return NULL; 207 return NULL;
205 208
206 if (!dso__sorted_by_name(self->dso, self->type)) 209 if (!dso__sorted_by_name(map->dso, map->type))
207 dso__sort_by_name(self->dso, self->type); 210 dso__sort_by_name(map->dso, map->type);
208 211
209 return dso__find_symbol_by_name(self->dso, self->type, name); 212 return dso__find_symbol_by_name(map->dso, map->type, name);
210} 213}
211 214
212struct map *map__clone(struct map *self) 215struct map *map__clone(struct map *map)
213{ 216{
214 struct map *map = malloc(sizeof(*self)); 217 return memdup(map, sizeof(*map));
215
216 if (!map)
217 return NULL;
218
219 memcpy(map, self, sizeof(*self));
220
221 return map;
222} 218}
223 219
224int map__overlap(struct map *l, struct map *r) 220int map__overlap(struct map *l, struct map *r)
@@ -235,10 +231,10 @@ int map__overlap(struct map *l, struct map *r)
235 return 0; 231 return 0;
236} 232}
237 233
238size_t map__fprintf(struct map *self, FILE *fp) 234size_t map__fprintf(struct map *map, FILE *fp)
239{ 235{
240 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 236 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
241 self->start, self->end, self->pgoff, self->dso->name); 237 map->start, map->end, map->pgoff, map->dso->name);
242} 238}
243 239
244size_t map__fprintf_dsoname(struct map *map, FILE *fp) 240size_t map__fprintf_dsoname(struct map *map, FILE *fp)
@@ -526,9 +522,9 @@ static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
526 return ip - (s64)map->pgoff; 522 return ip - (s64)map->pgoff;
527} 523}
528 524
529void map__reloc_vmlinux(struct map *self) 525void map__reloc_vmlinux(struct map *map)
530{ 526{
531 struct kmap *kmap = map__kmap(self); 527 struct kmap *kmap = map__kmap(map);
532 s64 reloc; 528 s64 reloc;
533 529
534 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr) 530 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
@@ -540,9 +536,9 @@ void map__reloc_vmlinux(struct map *self)
540 if (!reloc) 536 if (!reloc)
541 return; 537 return;
542 538
543 self->map_ip = map__reloc_map_ip; 539 map->map_ip = map__reloc_map_ip;
544 self->unmap_ip = map__reloc_unmap_ip; 540 map->unmap_ip = map__reloc_unmap_ip;
545 self->pgoff = reloc; 541 map->pgoff = reloc;
546} 542}
547 543
548void maps__insert(struct rb_root *maps, struct map *map) 544void maps__insert(struct rb_root *maps, struct map *map)
@@ -565,9 +561,9 @@ void maps__insert(struct rb_root *maps, struct map *map)
565 rb_insert_color(&map->rb_node, maps); 561 rb_insert_color(&map->rb_node, maps);
566} 562}
567 563
568void maps__remove(struct rb_root *self, struct map *map) 564void maps__remove(struct rb_root *maps, struct map *map)
569{ 565{
570 rb_erase(&map->rb_node, self); 566 rb_erase(&map->rb_node, maps);
571} 567}
572 568
573struct map *maps__find(struct rb_root *maps, u64 ip) 569struct map *maps__find(struct rb_root *maps, u64 ip)
@@ -589,182 +585,3 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
589 585
590 return NULL; 586 return NULL;
591} 587}
592
593int machine__init(struct machine *self, const char *root_dir, pid_t pid)
594{
595 map_groups__init(&self->kmaps);
596 RB_CLEAR_NODE(&self->rb_node);
597 INIT_LIST_HEAD(&self->user_dsos);
598 INIT_LIST_HEAD(&self->kernel_dsos);
599
600 self->threads = RB_ROOT;
601 INIT_LIST_HEAD(&self->dead_threads);
602 self->last_match = NULL;
603
604 self->kmaps.machine = self;
605 self->pid = pid;
606 self->root_dir = strdup(root_dir);
607 if (self->root_dir == NULL)
608 return -ENOMEM;
609
610 if (pid != HOST_KERNEL_ID) {
611 struct thread *thread = machine__findnew_thread(self, pid);
612 char comm[64];
613
614 if (thread == NULL)
615 return -ENOMEM;
616
617 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
618 thread__set_comm(thread, comm);
619 }
620
621 return 0;
622}
623
624static void dsos__delete(struct list_head *self)
625{
626 struct dso *pos, *n;
627
628 list_for_each_entry_safe(pos, n, self, node) {
629 list_del(&pos->node);
630 dso__delete(pos);
631 }
632}
633
634void machine__exit(struct machine *self)
635{
636 map_groups__exit(&self->kmaps);
637 dsos__delete(&self->user_dsos);
638 dsos__delete(&self->kernel_dsos);
639 free(self->root_dir);
640 self->root_dir = NULL;
641}
642
643void machine__delete(struct machine *self)
644{
645 machine__exit(self);
646 free(self);
647}
648
649struct machine *machines__add(struct rb_root *self, pid_t pid,
650 const char *root_dir)
651{
652 struct rb_node **p = &self->rb_node;
653 struct rb_node *parent = NULL;
654 struct machine *pos, *machine = malloc(sizeof(*machine));
655
656 if (!machine)
657 return NULL;
658
659 if (machine__init(machine, root_dir, pid) != 0) {
660 free(machine);
661 return NULL;
662 }
663
664 while (*p != NULL) {
665 parent = *p;
666 pos = rb_entry(parent, struct machine, rb_node);
667 if (pid < pos->pid)
668 p = &(*p)->rb_left;
669 else
670 p = &(*p)->rb_right;
671 }
672
673 rb_link_node(&machine->rb_node, parent, p);
674 rb_insert_color(&machine->rb_node, self);
675
676 return machine;
677}
678
679struct machine *machines__find(struct rb_root *self, pid_t pid)
680{
681 struct rb_node **p = &self->rb_node;
682 struct rb_node *parent = NULL;
683 struct machine *machine;
684 struct machine *default_machine = NULL;
685
686 while (*p != NULL) {
687 parent = *p;
688 machine = rb_entry(parent, struct machine, rb_node);
689 if (pid < machine->pid)
690 p = &(*p)->rb_left;
691 else if (pid > machine->pid)
692 p = &(*p)->rb_right;
693 else
694 return machine;
695 if (!machine->pid)
696 default_machine = machine;
697 }
698
699 return default_machine;
700}
701
702struct machine *machines__findnew(struct rb_root *self, pid_t pid)
703{
704 char path[PATH_MAX];
705 const char *root_dir = "";
706 struct machine *machine = machines__find(self, pid);
707
708 if (machine && (machine->pid == pid))
709 goto out;
710
711 if ((pid != HOST_KERNEL_ID) &&
712 (pid != DEFAULT_GUEST_KERNEL_ID) &&
713 (symbol_conf.guestmount)) {
714 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
715 if (access(path, R_OK)) {
716 static struct strlist *seen;
717
718 if (!seen)
719 seen = strlist__new(true, NULL);
720
721 if (!strlist__has_entry(seen, path)) {
722 pr_err("Can't access file %s\n", path);
723 strlist__add(seen, path);
724 }
725 machine = NULL;
726 goto out;
727 }
728 root_dir = path;
729 }
730
731 machine = machines__add(self, pid, root_dir);
732
733out:
734 return machine;
735}
736
737void machines__process(struct rb_root *self, machine__process_t process, void *data)
738{
739 struct rb_node *nd;
740
741 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
742 struct machine *pos = rb_entry(nd, struct machine, rb_node);
743 process(pos, data);
744 }
745}
746
747char *machine__mmap_name(struct machine *self, char *bf, size_t size)
748{
749 if (machine__is_host(self))
750 snprintf(bf, size, "[%s]", "kernel.kallsyms");
751 else if (machine__is_default_guest(self))
752 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
753 else
754 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid);
755
756 return bf;
757}
758
759void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size)
760{
761 struct rb_node *node;
762 struct machine *machine;
763
764 for (node = rb_first(machines); node; node = rb_next(node)) {
765 machine = rb_entry(node, struct machine, rb_node);
766 machine->id_hdr_size = id_hdr_size;
767 }
768
769 return;
770}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index d2250fc97e25..a887f2c9dfbb 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -57,33 +57,9 @@ struct map_groups {
57 struct machine *machine; 57 struct machine *machine;
58}; 58};
59 59
60/* Native host kernel uses -1 as pid index in machine */ 60static inline struct kmap *map__kmap(struct map *map)
61#define HOST_KERNEL_ID (-1)
62#define DEFAULT_GUEST_KERNEL_ID (0)
63
64struct machine {
65 struct rb_node rb_node;
66 pid_t pid;
67 u16 id_hdr_size;
68 char *root_dir;
69 struct rb_root threads;
70 struct list_head dead_threads;
71 struct thread *last_match;
72 struct list_head user_dsos;
73 struct list_head kernel_dsos;
74 struct map_groups kmaps;
75 struct map *vmlinux_maps[MAP__NR_TYPES];
76};
77
78static inline
79struct map *machine__kernel_map(struct machine *self, enum map_type type)
80{
81 return self->vmlinux_maps[type];
82}
83
84static inline struct kmap *map__kmap(struct map *self)
85{ 61{
86 return (struct kmap *)(self + 1); 62 return (struct kmap *)(map + 1);
87} 63}
88 64
89static inline u64 map__map_ip(struct map *map, u64 ip) 65static inline u64 map__map_ip(struct map *map, u64 ip)
@@ -109,27 +85,27 @@ struct symbol;
109 85
110typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 86typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
111 87
112void map__init(struct map *self, enum map_type type, 88void map__init(struct map *map, enum map_type type,
113 u64 start, u64 end, u64 pgoff, struct dso *dso); 89 u64 start, u64 end, u64 pgoff, struct dso *dso);
114struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 90struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
115 u64 pgoff, u32 pid, char *filename, 91 u64 pgoff, u32 pid, char *filename,
116 enum map_type type); 92 enum map_type type);
117struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 93struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
118void map__delete(struct map *self); 94void map__delete(struct map *map);
119struct map *map__clone(struct map *self); 95struct map *map__clone(struct map *map);
120int map__overlap(struct map *l, struct map *r); 96int map__overlap(struct map *l, struct map *r);
121size_t map__fprintf(struct map *self, FILE *fp); 97size_t map__fprintf(struct map *map, FILE *fp);
122size_t map__fprintf_dsoname(struct map *map, FILE *fp); 98size_t map__fprintf_dsoname(struct map *map, FILE *fp);
123 99
124int map__load(struct map *self, symbol_filter_t filter); 100int map__load(struct map *map, symbol_filter_t filter);
125struct symbol *map__find_symbol(struct map *self, 101struct symbol *map__find_symbol(struct map *map,
126 u64 addr, symbol_filter_t filter); 102 u64 addr, symbol_filter_t filter);
127struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 103struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
128 symbol_filter_t filter); 104 symbol_filter_t filter);
129void map__fixup_start(struct map *self); 105void map__fixup_start(struct map *map);
130void map__fixup_end(struct map *self); 106void map__fixup_end(struct map *map);
131 107
132void map__reloc_vmlinux(struct map *self); 108void map__reloc_vmlinux(struct map *map);
133 109
134size_t __map_groups__fprintf_maps(struct map_groups *mg, 110size_t __map_groups__fprintf_maps(struct map_groups *mg,
135 enum map_type type, int verbose, FILE *fp); 111 enum map_type type, int verbose, FILE *fp);
@@ -143,44 +119,9 @@ int map_groups__clone(struct map_groups *mg,
143size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); 119size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp);
144size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp); 120size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
145 121
146typedef void (*machine__process_t)(struct machine *self, void *data);
147
148void machines__process(struct rb_root *self, machine__process_t process, void *data);
149struct machine *machines__add(struct rb_root *self, pid_t pid,
150 const char *root_dir);
151struct machine *machines__find_host(struct rb_root *self);
152struct machine *machines__find(struct rb_root *self, pid_t pid);
153struct machine *machines__findnew(struct rb_root *self, pid_t pid);
154void machines__set_id_hdr_size(struct rb_root *self, u16 id_hdr_size);
155char *machine__mmap_name(struct machine *self, char *bf, size_t size);
156int machine__init(struct machine *self, const char *root_dir, pid_t pid);
157void machine__exit(struct machine *self);
158void machine__delete(struct machine *self);
159
160struct perf_evsel;
161struct perf_sample;
162int machine__resolve_callchain(struct machine *machine,
163 struct perf_evsel *evsel,
164 struct thread *thread,
165 struct perf_sample *sample,
166 struct symbol **parent);
167int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 122int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
168 u64 addr); 123 u64 addr);
169 124
170/*
171 * Default guest kernel is defined by parameter --guestkallsyms
172 * and --guestmodules
173 */
174static inline bool machine__is_default_guest(struct machine *self)
175{
176 return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false;
177}
178
179static inline bool machine__is_host(struct machine *self)
180{
181 return self ? self->pid == HOST_KERNEL_ID : false;
182}
183
184static inline void map_groups__insert(struct map_groups *mg, struct map *map) 125static inline void map_groups__insert(struct map_groups *mg, struct map *map)
185{ 126{
186 maps__insert(&mg->maps[map->type], map); 127 maps__insert(&mg->maps[map->type], map);
@@ -209,29 +150,6 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
209 struct map **mapp, 150 struct map **mapp,
210 symbol_filter_t filter); 151 symbol_filter_t filter);
211 152
212
213struct thread *machine__findnew_thread(struct machine *machine, pid_t pid);
214void machine__remove_thread(struct machine *machine, struct thread *th);
215
216size_t machine__fprintf(struct machine *machine, FILE *fp);
217
218static inline
219struct symbol *machine__find_kernel_symbol(struct machine *self,
220 enum map_type type, u64 addr,
221 struct map **mapp,
222 symbol_filter_t filter)
223{
224 return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter);
225}
226
227static inline
228struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
229 struct map **mapp,
230 symbol_filter_t filter)
231{
232 return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter);
233}
234
235static inline 153static inline
236struct symbol *map_groups__find_function_by_name(struct map_groups *mg, 154struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
237 const char *name, struct map **mapp, 155 const char *name, struct map **mapp,
@@ -240,22 +158,11 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
240 return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter); 158 return map_groups__find_symbol_by_name(mg, MAP__FUNCTION, name, mapp, filter);
241} 159}
242 160
243static inline
244struct symbol *machine__find_kernel_function_by_name(struct machine *self,
245 const char *name,
246 struct map **mapp,
247 symbol_filter_t filter)
248{
249 return map_groups__find_function_by_name(&self->kmaps, name, mapp,
250 filter);
251}
252
253int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 161int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
254 int verbose, FILE *fp); 162 int verbose, FILE *fp);
255 163
256struct map *map_groups__find_by_name(struct map_groups *mg, 164struct map *map_groups__find_by_name(struct map_groups *mg,
257 enum map_type type, const char *name); 165 enum map_type type, const char *name);
258struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
259 166
260void map_groups__flush(struct map_groups *mg); 167void map_groups__flush(struct map_groups *mg);
261 168
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 75c7b0fca6d9..c84f48cf9678 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,4 +1,4 @@
1#include "../../../include/linux/hw_breakpoint.h" 1#include <linux/hw_breakpoint.h>
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "evlist.h" 4#include "evlist.h"
@@ -380,8 +380,8 @@ static int add_tracepoint(struct list_head **listp, int *idx,
380 return 0; 380 return 0;
381} 381}
382 382
383static int add_tracepoint_multi(struct list_head **list, int *idx, 383static int add_tracepoint_multi_event(struct list_head **list, int *idx,
384 char *sys_name, char *evt_name) 384 char *sys_name, char *evt_name)
385{ 385{
386 char evt_path[MAXPATHLEN]; 386 char evt_path[MAXPATHLEN];
387 struct dirent *evt_ent; 387 struct dirent *evt_ent;
@@ -408,6 +408,47 @@ static int add_tracepoint_multi(struct list_head **list, int *idx,
408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); 408 ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name);
409 } 409 }
410 410
411 closedir(evt_dir);
412 return ret;
413}
414
415static int add_tracepoint_event(struct list_head **list, int *idx,
416 char *sys_name, char *evt_name)
417{
418 return strpbrk(evt_name, "*?") ?
419 add_tracepoint_multi_event(list, idx, sys_name, evt_name) :
420 add_tracepoint(list, idx, sys_name, evt_name);
421}
422
423static int add_tracepoint_multi_sys(struct list_head **list, int *idx,
424 char *sys_name, char *evt_name)
425{
426 struct dirent *events_ent;
427 DIR *events_dir;
428 int ret = 0;
429
430 events_dir = opendir(tracing_events_path);
431 if (!events_dir) {
432 perror("Can't open event dir");
433 return -1;
434 }
435
436 while (!ret && (events_ent = readdir(events_dir))) {
437 if (!strcmp(events_ent->d_name, ".")
438 || !strcmp(events_ent->d_name, "..")
439 || !strcmp(events_ent->d_name, "enable")
440 || !strcmp(events_ent->d_name, "header_event")
441 || !strcmp(events_ent->d_name, "header_page"))
442 continue;
443
444 if (!strglobmatch(events_ent->d_name, sys_name))
445 continue;
446
447 ret = add_tracepoint_event(list, idx, events_ent->d_name,
448 evt_name);
449 }
450
451 closedir(events_dir);
411 return ret; 452 return ret;
412} 453}
413 454
@@ -420,9 +461,10 @@ int parse_events_add_tracepoint(struct list_head **list, int *idx,
420 if (ret) 461 if (ret)
421 return ret; 462 return ret;
422 463
423 return strpbrk(event, "*?") ? 464 if (strpbrk(sys, "*?"))
424 add_tracepoint_multi(list, idx, sys, event) : 465 return add_tracepoint_multi_sys(list, idx, sys, event);
425 add_tracepoint(list, idx, sys, event); 466 else
467 return add_tracepoint_event(list, idx, sys, event);
426} 468}
427 469
428static int 470static int
@@ -492,7 +534,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
492} 534}
493 535
494static int config_term(struct perf_event_attr *attr, 536static int config_term(struct perf_event_attr *attr,
495 struct parse_events__term *term) 537 struct parse_events_term *term)
496{ 538{
497#define CHECK_TYPE_VAL(type) \ 539#define CHECK_TYPE_VAL(type) \
498do { \ 540do { \
@@ -537,7 +579,7 @@ do { \
537static int config_attr(struct perf_event_attr *attr, 579static int config_attr(struct perf_event_attr *attr,
538 struct list_head *head, int fail) 580 struct list_head *head, int fail)
539{ 581{
540 struct parse_events__term *term; 582 struct parse_events_term *term;
541 583
542 list_for_each_entry(term, head, list) 584 list_for_each_entry(term, head, list)
543 if (config_term(attr, term) && fail) 585 if (config_term(attr, term) && fail)
@@ -563,14 +605,14 @@ int parse_events_add_numeric(struct list_head **list, int *idx,
563 return add_event(list, idx, &attr, NULL); 605 return add_event(list, idx, &attr, NULL);
564} 606}
565 607
566static int parse_events__is_name_term(struct parse_events__term *term) 608static int parse_events__is_name_term(struct parse_events_term *term)
567{ 609{
568 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; 610 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
569} 611}
570 612
571static char *pmu_event_name(struct list_head *head_terms) 613static char *pmu_event_name(struct list_head *head_terms)
572{ 614{
573 struct parse_events__term *term; 615 struct parse_events_term *term;
574 616
575 list_for_each_entry(term, head_terms, list) 617 list_for_each_entry(term, head_terms, list)
576 if (parse_events__is_name_term(term)) 618 if (parse_events__is_name_term(term))
@@ -657,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
657 int exclude = eu | ek | eh; 699 int exclude = eu | ek | eh;
658 int exclude_GH = evsel ? evsel->exclude_GH : 0; 700 int exclude_GH = evsel ? evsel->exclude_GH : 0;
659 701
660 /*
661 * We are here for group and 'GH' was not set as event
662 * modifier and whatever event/group modifier override
663 * default 'GH' setup.
664 */
665 if (evsel && !exclude_GH)
666 eH = eG = 0;
667
668 memset(mod, 0, sizeof(*mod)); 702 memset(mod, 0, sizeof(*mod));
669 703
670 while (*str) { 704 while (*str) {
@@ -722,6 +756,27 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
722 return 0; 756 return 0;
723} 757}
724 758
759/*
760 * Basic modifier sanity check to validate it contains only one
761 * instance of any modifier (apart from 'p') present.
762 */
763static int check_modifier(char *str)
764{
765 char *p = str;
766
767 /* The sizeof includes 0 byte as well. */
768 if (strlen(str) > (sizeof("ukhGHppp") - 1))
769 return -1;
770
771 while (*p) {
772 if (*p != 'p' && strchr(p + 1, *p))
773 return -1;
774 p++;
775 }
776
777 return 0;
778}
779
725int parse_events__modifier_event(struct list_head *list, char *str, bool add) 780int parse_events__modifier_event(struct list_head *list, char *str, bool add)
726{ 781{
727 struct perf_evsel *evsel; 782 struct perf_evsel *evsel;
@@ -730,6 +785,9 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add)
730 if (str == NULL) 785 if (str == NULL)
731 return 0; 786 return 0;
732 787
788 if (check_modifier(str))
789 return -EINVAL;
790
733 if (!add && get_event_modifier(&mod, str, NULL)) 791 if (!add && get_event_modifier(&mod, str, NULL))
734 return -EINVAL; 792 return -EINVAL;
735 793
@@ -790,7 +848,7 @@ static int parse_events__scanner(const char *str, void *data, int start_token)
790 */ 848 */
791int parse_events_terms(struct list_head *terms, const char *str) 849int parse_events_terms(struct list_head *terms, const char *str)
792{ 850{
793 struct parse_events_data__terms data = { 851 struct parse_events_terms data = {
794 .terms = NULL, 852 .terms = NULL,
795 }; 853 };
796 int ret; 854 int ret;
@@ -806,10 +864,9 @@ int parse_events_terms(struct list_head *terms, const char *str)
806 return ret; 864 return ret;
807} 865}
808 866
809int parse_events(struct perf_evlist *evlist, const char *str, 867int parse_events(struct perf_evlist *evlist, const char *str)
810 int unset __maybe_unused)
811{ 868{
812 struct parse_events_data__events data = { 869 struct parse_events_evlist data = {
813 .list = LIST_HEAD_INIT(data.list), 870 .list = LIST_HEAD_INIT(data.list),
814 .idx = evlist->nr_entries, 871 .idx = evlist->nr_entries,
815 }; 872 };
@@ -819,6 +876,7 @@ int parse_events(struct perf_evlist *evlist, const char *str,
819 if (!ret) { 876 if (!ret) {
820 int entries = data.idx - evlist->nr_entries; 877 int entries = data.idx - evlist->nr_entries;
821 perf_evlist__splice_list_tail(evlist, &data.list, entries); 878 perf_evlist__splice_list_tail(evlist, &data.list, entries);
879 evlist->nr_groups += data.nr_groups;
822 return 0; 880 return 0;
823 } 881 }
824 882
@@ -827,8 +885,6 @@ int parse_events(struct perf_evlist *evlist, const char *str,
827 * Both call perf_evlist__delete in case of error, so we dont 885 * Both call perf_evlist__delete in case of error, so we dont
828 * need to bother. 886 * need to bother.
829 */ 887 */
830 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
831 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
832 return ret; 888 return ret;
833} 889}
834 890
@@ -836,7 +892,13 @@ int parse_events_option(const struct option *opt, const char *str,
836 int unset __maybe_unused) 892 int unset __maybe_unused)
837{ 893{
838 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; 894 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
839 return parse_events(evlist, str, unset); 895 int ret = parse_events(evlist, str);
896
897 if (ret) {
898 fprintf(stderr, "invalid or unsupported event: '%s'\n", str);
899 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
900 }
901 return ret;
840} 902}
841 903
842int parse_filter(const struct option *opt, const char *str, 904int parse_filter(const struct option *opt, const char *str,
@@ -1081,7 +1143,7 @@ void print_events(const char *event_glob, bool name_only)
1081 printf(" %-50s [%s]\n", 1143 printf(" %-50s [%s]\n",
1082 "cpu/t1=v1[,t2=v2,t3 ...]/modifier", 1144 "cpu/t1=v1[,t2=v2,t3 ...]/modifier",
1083 event_type_descriptors[PERF_TYPE_RAW]); 1145 event_type_descriptors[PERF_TYPE_RAW]);
1084 printf(" (see 'perf list --help' on how to encode it)\n"); 1146 printf(" (see 'man perf-list' on how to encode it)\n");
1085 printf("\n"); 1147 printf("\n");
1086 1148
1087 printf(" %-50s [%s]\n", 1149 printf(" %-50s [%s]\n",
@@ -1093,16 +1155,16 @@ void print_events(const char *event_glob, bool name_only)
1093 print_tracepoint_events(NULL, NULL, name_only); 1155 print_tracepoint_events(NULL, NULL, name_only);
1094} 1156}
1095 1157
1096int parse_events__is_hardcoded_term(struct parse_events__term *term) 1158int parse_events__is_hardcoded_term(struct parse_events_term *term)
1097{ 1159{
1098 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER; 1160 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1099} 1161}
1100 1162
1101static int new_term(struct parse_events__term **_term, int type_val, 1163static int new_term(struct parse_events_term **_term, int type_val,
1102 int type_term, char *config, 1164 int type_term, char *config,
1103 char *str, u64 num) 1165 char *str, u64 num)
1104{ 1166{
1105 struct parse_events__term *term; 1167 struct parse_events_term *term;
1106 1168
1107 term = zalloc(sizeof(*term)); 1169 term = zalloc(sizeof(*term));
1108 if (!term) 1170 if (!term)
@@ -1128,22 +1190,40 @@ static int new_term(struct parse_events__term **_term, int type_val,
1128 return 0; 1190 return 0;
1129} 1191}
1130 1192
1131int parse_events__term_num(struct parse_events__term **term, 1193int parse_events_term__num(struct parse_events_term **term,
1132 int type_term, char *config, u64 num) 1194 int type_term, char *config, u64 num)
1133{ 1195{
1134 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term, 1196 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1135 config, NULL, num); 1197 config, NULL, num);
1136} 1198}
1137 1199
1138int parse_events__term_str(struct parse_events__term **term, 1200int parse_events_term__str(struct parse_events_term **term,
1139 int type_term, char *config, char *str) 1201 int type_term, char *config, char *str)
1140{ 1202{
1141 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term, 1203 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1142 config, str, 0); 1204 config, str, 0);
1143} 1205}
1144 1206
1145int parse_events__term_clone(struct parse_events__term **new, 1207int parse_events_term__sym_hw(struct parse_events_term **term,
1146 struct parse_events__term *term) 1208 char *config, unsigned idx)
1209{
1210 struct event_symbol *sym;
1211
1212 BUG_ON(idx >= PERF_COUNT_HW_MAX);
1213 sym = &event_symbols_hw[idx];
1214
1215 if (config)
1216 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR,
1217 PARSE_EVENTS__TERM_TYPE_USER, config,
1218 (char *) sym->symbol, 0);
1219 else
1220 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR,
1221 PARSE_EVENTS__TERM_TYPE_USER,
1222 (char *) "event", (char *) sym->symbol, 0);
1223}
1224
1225int parse_events_term__clone(struct parse_events_term **new,
1226 struct parse_events_term *term)
1147{ 1227{
1148 return new_term(new, term->type_val, term->type_term, term->config, 1228 return new_term(new, term->type_val, term->type_term, term->config,
1149 term->val.str, term->val.num); 1229 term->val.str, term->val.num);
@@ -1151,7 +1231,7 @@ int parse_events__term_clone(struct parse_events__term **new,
1151 1231
1152void parse_events__free_terms(struct list_head *terms) 1232void parse_events__free_terms(struct list_head *terms)
1153{ 1233{
1154 struct parse_events__term *term, *h; 1234 struct parse_events_term *term, *h;
1155 1235
1156 list_for_each_entry_safe(term, h, terms, list) 1236 list_for_each_entry_safe(term, h, terms, list)
1157 free(term); 1237 free(term);
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 839230ceb18b..8a4859315fd9 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -7,7 +7,7 @@
7#include <linux/list.h> 7#include <linux/list.h>
8#include <stdbool.h> 8#include <stdbool.h>
9#include "types.h" 9#include "types.h"
10#include "../../../include/uapi/linux/perf_event.h" 10#include <linux/perf_event.h>
11#include "types.h" 11#include "types.h"
12 12
13struct list_head; 13struct list_head;
@@ -29,8 +29,7 @@ const char *event_type(int type);
29 29
30extern int parse_events_option(const struct option *opt, const char *str, 30extern int parse_events_option(const struct option *opt, const char *str,
31 int unset); 31 int unset);
32extern int parse_events(struct perf_evlist *evlist, const char *str, 32extern int parse_events(struct perf_evlist *evlist, const char *str);
33 int unset);
34extern int parse_events_terms(struct list_head *terms, const char *str); 33extern int parse_events_terms(struct list_head *terms, const char *str);
35extern int parse_filter(const struct option *opt, const char *str, int unset); 34extern int parse_filter(const struct option *opt, const char *str, int unset);
36 35
@@ -51,7 +50,7 @@ enum {
51 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 50 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
52}; 51};
53 52
54struct parse_events__term { 53struct parse_events_term {
55 char *config; 54 char *config;
56 union { 55 union {
57 char *str; 56 char *str;
@@ -62,22 +61,25 @@ struct parse_events__term {
62 struct list_head list; 61 struct list_head list;
63}; 62};
64 63
65struct parse_events_data__events { 64struct parse_events_evlist {
66 struct list_head list; 65 struct list_head list;
67 int idx; 66 int idx;
67 int nr_groups;
68}; 68};
69 69
70struct parse_events_data__terms { 70struct parse_events_terms {
71 struct list_head *terms; 71 struct list_head *terms;
72}; 72};
73 73
74int parse_events__is_hardcoded_term(struct parse_events__term *term); 74int parse_events__is_hardcoded_term(struct parse_events_term *term);
75int parse_events__term_num(struct parse_events__term **_term, 75int parse_events_term__num(struct parse_events_term **_term,
76 int type_term, char *config, u64 num); 76 int type_term, char *config, u64 num);
77int parse_events__term_str(struct parse_events__term **_term, 77int parse_events_term__str(struct parse_events_term **_term,
78 int type_term, char *config, char *str); 78 int type_term, char *config, char *str);
79int parse_events__term_clone(struct parse_events__term **new, 79int parse_events_term__sym_hw(struct parse_events_term **term,
80 struct parse_events__term *term); 80 char *config, unsigned idx);
81int parse_events_term__clone(struct parse_events_term **new,
82 struct parse_events_term *term);
81void parse_events__free_terms(struct list_head *terms); 83void parse_events__free_terms(struct list_head *terms);
82int parse_events__modifier_event(struct list_head *list, char *str, bool add); 84int parse_events__modifier_event(struct list_head *list, char *str, bool add);
83int parse_events__modifier_group(struct list_head *list, char *event_mod); 85int parse_events__modifier_group(struct list_head *list, char *event_mod);
@@ -97,7 +99,6 @@ void parse_events__set_leader(char *name, struct list_head *list);
97void parse_events_update_lists(struct list_head *list_event, 99void parse_events_update_lists(struct list_head *list_event,
98 struct list_head *list_all); 100 struct list_head *list_all);
99void parse_events_error(void *data, void *scanner, char const *msg); 101void parse_events_error(void *data, void *scanner, char const *msg);
100int parse_events__test(void);
101 102
102void print_events(const char *event_glob, bool name_only); 103void print_events(const char *event_glob, bool name_only);
103void print_events_type(u8 type); 104void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index c87efc12579d..e9d1134c2c68 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -81,7 +81,8 @@ num_dec [0-9]+
81num_hex 0x[a-fA-F0-9]+ 81num_hex 0x[a-fA-F0-9]+
82num_raw_hex [a-fA-F0-9]+ 82num_raw_hex [a-fA-F0-9]+
83name [a-zA-Z_*?][a-zA-Z0-9_*?]* 83name [a-zA-Z_*?][a-zA-Z0-9_*?]*
84modifier_event [ukhpGH]{1,8} 84name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]*
85modifier_event [ukhpGH]+
85modifier_bp [rwx]{1,3} 86modifier_bp [rwx]{1,3}
86 87
87%% 88%%
@@ -168,6 +169,7 @@ period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
168branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } 169branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
169, { return ','; } 170, { return ','; }
170"/" { BEGIN(INITIAL); return '/'; } 171"/" { BEGIN(INITIAL); return '/'; }
172{name_minus} { return str(yyscanner, PE_NAME); }
171} 173}
172 174
173mem: { BEGIN(mem); return PE_PREFIX_MEM; } 175mem: { BEGIN(mem); return PE_PREFIX_MEM; }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index cd88209e3c58..afc44c18dfe1 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,5 +1,4 @@
1%pure-parser 1%pure-parser
2%name-prefix "parse_events_"
3%parse-param {void *_data} 2%parse-param {void *_data}
4%parse-param {void *scanner} 3%parse-param {void *scanner}
5%lex-param {void* scanner} 4%lex-param {void* scanner}
@@ -23,6 +22,14 @@ do { \
23 YYABORT; \ 22 YYABORT; \
24} while (0) 23} while (0)
25 24
25static inc_group_count(struct list_head *list,
26 struct parse_events_evlist *data)
27{
28 /* Count groups only have more than 1 members */
29 if (!list_is_last(list->next, list))
30 data->nr_groups++;
31}
32
26%} 33%}
27 34
28%token PE_START_EVENTS PE_START_TERMS 35%token PE_START_EVENTS PE_START_TERMS
@@ -68,7 +75,7 @@ do { \
68 char *str; 75 char *str;
69 u64 num; 76 u64 num;
70 struct list_head *head; 77 struct list_head *head;
71 struct parse_events__term *term; 78 struct parse_events_term *term;
72} 79}
73%% 80%%
74 81
@@ -79,7 +86,7 @@ PE_START_TERMS start_terms
79 86
80start_events: groups 87start_events: groups
81{ 88{
82 struct parse_events_data__events *data = _data; 89 struct parse_events_evlist *data = _data;
83 90
84 parse_events_update_lists($1, &data->list); 91 parse_events_update_lists($1, &data->list);
85} 92}
@@ -123,6 +130,7 @@ PE_NAME '{' events '}'
123{ 130{
124 struct list_head *list = $3; 131 struct list_head *list = $3;
125 132
133 inc_group_count(list, _data);
126 parse_events__set_leader($1, list); 134 parse_events__set_leader($1, list);
127 $$ = list; 135 $$ = list;
128} 136}
@@ -131,6 +139,7 @@ PE_NAME '{' events '}'
131{ 139{
132 struct list_head *list = $2; 140 struct list_head *list = $2;
133 141
142 inc_group_count(list, _data);
134 parse_events__set_leader(NULL, list); 143 parse_events__set_leader(NULL, list);
135 $$ = list; 144 $$ = list;
136} 145}
@@ -186,7 +195,7 @@ event_def: event_pmu |
186event_pmu: 195event_pmu:
187PE_NAME '/' event_config '/' 196PE_NAME '/' event_config '/'
188{ 197{
189 struct parse_events_data__events *data = _data; 198 struct parse_events_evlist *data = _data;
190 struct list_head *list = NULL; 199 struct list_head *list = NULL;
191 200
192 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); 201 ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3));
@@ -202,7 +211,7 @@ PE_VALUE_SYM_SW
202event_legacy_symbol: 211event_legacy_symbol:
203value_sym '/' event_config '/' 212value_sym '/' event_config '/'
204{ 213{
205 struct parse_events_data__events *data = _data; 214 struct parse_events_evlist *data = _data;
206 struct list_head *list = NULL; 215 struct list_head *list = NULL;
207 int type = $1 >> 16; 216 int type = $1 >> 16;
208 int config = $1 & 255; 217 int config = $1 & 255;
@@ -215,7 +224,7 @@ value_sym '/' event_config '/'
215| 224|
216value_sym sep_slash_dc 225value_sym sep_slash_dc
217{ 226{
218 struct parse_events_data__events *data = _data; 227 struct parse_events_evlist *data = _data;
219 struct list_head *list = NULL; 228 struct list_head *list = NULL;
220 int type = $1 >> 16; 229 int type = $1 >> 16;
221 int config = $1 & 255; 230 int config = $1 & 255;
@@ -228,7 +237,7 @@ value_sym sep_slash_dc
228event_legacy_cache: 237event_legacy_cache:
229PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
230{ 239{
231 struct parse_events_data__events *data = _data; 240 struct parse_events_evlist *data = _data;
232 struct list_head *list = NULL; 241 struct list_head *list = NULL;
233 242
234 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); 243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5));
@@ -237,7 +246,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
237| 246|
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 247PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
239{ 248{
240 struct parse_events_data__events *data = _data; 249 struct parse_events_evlist *data = _data;
241 struct list_head *list = NULL; 250 struct list_head *list = NULL;
242 251
243 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); 252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL));
@@ -246,7 +255,7 @@ PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
246| 255|
247PE_NAME_CACHE_TYPE 256PE_NAME_CACHE_TYPE
248{ 257{
249 struct parse_events_data__events *data = _data; 258 struct parse_events_evlist *data = _data;
250 struct list_head *list = NULL; 259 struct list_head *list = NULL;
251 260
252 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); 261 ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL));
@@ -256,7 +265,7 @@ PE_NAME_CACHE_TYPE
256event_legacy_mem: 265event_legacy_mem:
257PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 266PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
258{ 267{
259 struct parse_events_data__events *data = _data; 268 struct parse_events_evlist *data = _data;
260 struct list_head *list = NULL; 269 struct list_head *list = NULL;
261 270
262 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 271 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -266,7 +275,7 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
266| 275|
267PE_PREFIX_MEM PE_VALUE sep_dc 276PE_PREFIX_MEM PE_VALUE sep_dc
268{ 277{
269 struct parse_events_data__events *data = _data; 278 struct parse_events_evlist *data = _data;
270 struct list_head *list = NULL; 279 struct list_head *list = NULL;
271 280
272 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, 281 ABORT_ON(parse_events_add_breakpoint(&list, &data->idx,
@@ -277,7 +286,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
277event_legacy_tracepoint: 286event_legacy_tracepoint:
278PE_NAME ':' PE_NAME 287PE_NAME ':' PE_NAME
279{ 288{
280 struct parse_events_data__events *data = _data; 289 struct parse_events_evlist *data = _data;
281 struct list_head *list = NULL; 290 struct list_head *list = NULL;
282 291
283 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); 292 ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3));
@@ -287,7 +296,7 @@ PE_NAME ':' PE_NAME
287event_legacy_numeric: 296event_legacy_numeric:
288PE_VALUE ':' PE_VALUE 297PE_VALUE ':' PE_VALUE
289{ 298{
290 struct parse_events_data__events *data = _data; 299 struct parse_events_evlist *data = _data;
291 struct list_head *list = NULL; 300 struct list_head *list = NULL;
292 301
293 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); 302 ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL));
@@ -297,7 +306,7 @@ PE_VALUE ':' PE_VALUE
297event_legacy_raw: 306event_legacy_raw:
298PE_RAW 307PE_RAW
299{ 308{
300 struct parse_events_data__events *data = _data; 309 struct parse_events_evlist *data = _data;
301 struct list_head *list = NULL; 310 struct list_head *list = NULL;
302 311
303 ABORT_ON(parse_events_add_numeric(&list, &data->idx, 312 ABORT_ON(parse_events_add_numeric(&list, &data->idx,
@@ -307,7 +316,7 @@ PE_RAW
307 316
308start_terms: event_config 317start_terms: event_config
309{ 318{
310 struct parse_events_data__terms *data = _data; 319 struct parse_events_terms *data = _data;
311 data->terms = $1; 320 data->terms = $1;
312} 321}
313 322
@@ -315,7 +324,7 @@ event_config:
315event_config ',' event_term 324event_config ',' event_term
316{ 325{
317 struct list_head *head = $1; 326 struct list_head *head = $1;
318 struct parse_events__term *term = $3; 327 struct parse_events_term *term = $3;
319 328
320 ABORT_ON(!head); 329 ABORT_ON(!head);
321 list_add_tail(&term->list, head); 330 list_add_tail(&term->list, head);
@@ -325,7 +334,7 @@ event_config ',' event_term
325event_term 334event_term
326{ 335{
327 struct list_head *head = malloc(sizeof(*head)); 336 struct list_head *head = malloc(sizeof(*head));
328 struct parse_events__term *term = $1; 337 struct parse_events_term *term = $1;
329 338
330 ABORT_ON(!head); 339 ABORT_ON(!head);
331 INIT_LIST_HEAD(head); 340 INIT_LIST_HEAD(head);
@@ -336,52 +345,70 @@ event_term
336event_term: 345event_term:
337PE_NAME '=' PE_NAME 346PE_NAME '=' PE_NAME
338{ 347{
339 struct parse_events__term *term; 348 struct parse_events_term *term;
340 349
341 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER, 350 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
342 $1, $3)); 351 $1, $3));
343 $$ = term; 352 $$ = term;
344} 353}
345| 354|
346PE_NAME '=' PE_VALUE 355PE_NAME '=' PE_VALUE
347{ 356{
348 struct parse_events__term *term; 357 struct parse_events_term *term;
349 358
350 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 359 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
351 $1, $3)); 360 $1, $3));
352 $$ = term; 361 $$ = term;
353} 362}
354| 363|
364PE_NAME '=' PE_VALUE_SYM_HW
365{
366 struct parse_events_term *term;
367 int config = $3 & 255;
368
369 ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
370 $$ = term;
371}
372|
355PE_NAME 373PE_NAME
356{ 374{
357 struct parse_events__term *term; 375 struct parse_events_term *term;
358 376
359 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER, 377 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
360 $1, 1)); 378 $1, 1));
361 $$ = term; 379 $$ = term;
362} 380}
363| 381|
382PE_VALUE_SYM_HW
383{
384 struct parse_events_term *term;
385 int config = $1 & 255;
386
387 ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
388 $$ = term;
389}
390|
364PE_TERM '=' PE_NAME 391PE_TERM '=' PE_NAME
365{ 392{
366 struct parse_events__term *term; 393 struct parse_events_term *term;
367 394
368 ABORT_ON(parse_events__term_str(&term, (int)$1, NULL, $3)); 395 ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3));
369 $$ = term; 396 $$ = term;
370} 397}
371| 398|
372PE_TERM '=' PE_VALUE 399PE_TERM '=' PE_VALUE
373{ 400{
374 struct parse_events__term *term; 401 struct parse_events_term *term;
375 402
376 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, $3)); 403 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3));
377 $$ = term; 404 $$ = term;
378} 405}
379| 406|
380PE_TERM 407PE_TERM
381{ 408{
382 struct parse_events__term *term; 409 struct parse_events_term *term;
383 410
384 ABORT_ON(parse_events__term_num(&term, (int)$1, NULL, 1)); 411 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1));
385 $$ = term; 412 $$ = term;
386} 413}
387 414
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 8a2229da594f..4c6f9c490a8d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -1,4 +1,3 @@
1
2#include <linux/list.h> 1#include <linux/list.h>
3#include <sys/types.h> 2#include <sys/types.h>
4#include <sys/stat.h> 3#include <sys/stat.h>
@@ -11,6 +10,19 @@
11#include "parse-events.h" 10#include "parse-events.h"
12#include "cpumap.h" 11#include "cpumap.h"
13 12
13struct perf_pmu_alias {
14 char *name;
15 struct list_head terms;
16 struct list_head list;
17};
18
19struct perf_pmu_format {
20 char *name;
21 int value;
22 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
23 struct list_head list;
24};
25
14#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" 26#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
15 27
16int perf_pmu_parse(struct list_head *list, char *name); 28int perf_pmu_parse(struct list_head *list, char *name);
@@ -22,7 +34,7 @@ static LIST_HEAD(pmus);
22 * Parse & process all the sysfs attributes located under 34 * Parse & process all the sysfs attributes located under
23 * the directory specified in 'dir' parameter. 35 * the directory specified in 'dir' parameter.
24 */ 36 */
25static int pmu_format_parse(char *dir, struct list_head *head) 37int perf_pmu__format_parse(char *dir, struct list_head *head)
26{ 38{
27 struct dirent *evt_ent; 39 struct dirent *evt_ent;
28 DIR *format_dir; 40 DIR *format_dir;
@@ -77,7 +89,7 @@ static int pmu_format(char *name, struct list_head *format)
77 if (stat(path, &st) < 0) 89 if (stat(path, &st) < 0)
78 return 0; /* no error if format does not exist */ 90 return 0; /* no error if format does not exist */
79 91
80 if (pmu_format_parse(path, format)) 92 if (perf_pmu__format_parse(path, format))
81 return -1; 93 return -1;
82 94
83 return 0; 95 return 0;
@@ -85,7 +97,7 @@ static int pmu_format(char *name, struct list_head *format)
85 97
86static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) 98static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
87{ 99{
88 struct perf_pmu__alias *alias; 100 struct perf_pmu_alias *alias;
89 char buf[256]; 101 char buf[256];
90 int ret; 102 int ret;
91 103
@@ -164,7 +176,7 @@ static int pmu_aliases(char *name, struct list_head *head)
164 "%s/bus/event_source/devices/%s/events", sysfs, name); 176 "%s/bus/event_source/devices/%s/events", sysfs, name);
165 177
166 if (stat(path, &st) < 0) 178 if (stat(path, &st) < 0)
167 return -1; 179 return 0; /* no error if 'events' does not exist */
168 180
169 if (pmu_aliases_parse(path, head)) 181 if (pmu_aliases_parse(path, head))
170 return -1; 182 return -1;
@@ -172,15 +184,15 @@ static int pmu_aliases(char *name, struct list_head *head)
172 return 0; 184 return 0;
173} 185}
174 186
175static int pmu_alias_terms(struct perf_pmu__alias *alias, 187static int pmu_alias_terms(struct perf_pmu_alias *alias,
176 struct list_head *terms) 188 struct list_head *terms)
177{ 189{
178 struct parse_events__term *term, *clone; 190 struct parse_events_term *term, *clone;
179 LIST_HEAD(list); 191 LIST_HEAD(list);
180 int ret; 192 int ret;
181 193
182 list_for_each_entry(term, &alias->terms, list) { 194 list_for_each_entry(term, &alias->terms, list) {
183 ret = parse_events__term_clone(&clone, term); 195 ret = parse_events_term__clone(&clone, term);
184 if (ret) { 196 if (ret) {
185 parse_events__free_terms(&list); 197 parse_events__free_terms(&list);
186 return ret; 198 return ret;
@@ -296,6 +308,9 @@ static struct perf_pmu *pmu_lookup(char *name)
296 if (pmu_format(name, &format)) 308 if (pmu_format(name, &format))
297 return NULL; 309 return NULL;
298 310
311 if (pmu_aliases(name, &aliases))
312 return NULL;
313
299 if (pmu_type(name, &type)) 314 if (pmu_type(name, &type))
300 return NULL; 315 return NULL;
301 316
@@ -305,8 +320,6 @@ static struct perf_pmu *pmu_lookup(char *name)
305 320
306 pmu->cpus = pmu_cpumask(name); 321 pmu->cpus = pmu_cpumask(name);
307 322
308 pmu_aliases(name, &aliases);
309
310 INIT_LIST_HEAD(&pmu->format); 323 INIT_LIST_HEAD(&pmu->format);
311 INIT_LIST_HEAD(&pmu->aliases); 324 INIT_LIST_HEAD(&pmu->aliases);
312 list_splice(&format, &pmu->format); 325 list_splice(&format, &pmu->format);
@@ -359,10 +372,10 @@ struct perf_pmu *perf_pmu__find(char *name)
359 return pmu_lookup(name); 372 return pmu_lookup(name);
360} 373}
361 374
362static struct perf_pmu__format* 375static struct perf_pmu_format *
363pmu_find_format(struct list_head *formats, char *name) 376pmu_find_format(struct list_head *formats, char *name)
364{ 377{
365 struct perf_pmu__format *format; 378 struct perf_pmu_format *format;
366 379
367 list_for_each_entry(format, formats, list) 380 list_for_each_entry(format, formats, list)
368 if (!strcmp(format->name, name)) 381 if (!strcmp(format->name, name))
@@ -402,9 +415,9 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value)
402 */ 415 */
403static int pmu_config_term(struct list_head *formats, 416static int pmu_config_term(struct list_head *formats,
404 struct perf_event_attr *attr, 417 struct perf_event_attr *attr,
405 struct parse_events__term *term) 418 struct parse_events_term *term)
406{ 419{
407 struct perf_pmu__format *format; 420 struct perf_pmu_format *format;
408 __u64 *vp; 421 __u64 *vp;
409 422
410 /* 423 /*
@@ -445,10 +458,11 @@ static int pmu_config_term(struct list_head *formats,
445 return 0; 458 return 0;
446} 459}
447 460
448static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, 461int perf_pmu__config_terms(struct list_head *formats,
449 struct list_head *head_terms) 462 struct perf_event_attr *attr,
463 struct list_head *head_terms)
450{ 464{
451 struct parse_events__term *term; 465 struct parse_events_term *term;
452 466
453 list_for_each_entry(term, head_terms, list) 467 list_for_each_entry(term, head_terms, list)
454 if (pmu_config_term(formats, attr, term)) 468 if (pmu_config_term(formats, attr, term))
@@ -466,13 +480,13 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
466 struct list_head *head_terms) 480 struct list_head *head_terms)
467{ 481{
468 attr->type = pmu->type; 482 attr->type = pmu->type;
469 return pmu_config(&pmu->format, attr, head_terms); 483 return perf_pmu__config_terms(&pmu->format, attr, head_terms);
470} 484}
471 485
472static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu, 486static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
473 struct parse_events__term *term) 487 struct parse_events_term *term)
474{ 488{
475 struct perf_pmu__alias *alias; 489 struct perf_pmu_alias *alias;
476 char *name; 490 char *name;
477 491
478 if (parse_events__is_hardcoded_term(term)) 492 if (parse_events__is_hardcoded_term(term))
@@ -505,8 +519,8 @@ static struct perf_pmu__alias *pmu_find_alias(struct perf_pmu *pmu,
505 */ 519 */
506int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) 520int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
507{ 521{
508 struct parse_events__term *term, *h; 522 struct parse_events_term *term, *h;
509 struct perf_pmu__alias *alias; 523 struct perf_pmu_alias *alias;
510 int ret; 524 int ret;
511 525
512 list_for_each_entry_safe(term, h, head_terms, list) { 526 list_for_each_entry_safe(term, h, head_terms, list) {
@@ -525,7 +539,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms)
525int perf_pmu__new_format(struct list_head *list, char *name, 539int perf_pmu__new_format(struct list_head *list, char *name,
526 int config, unsigned long *bits) 540 int config, unsigned long *bits)
527{ 541{
528 struct perf_pmu__format *format; 542 struct perf_pmu_format *format;
529 543
530 format = zalloc(sizeof(*format)); 544 format = zalloc(sizeof(*format));
531 if (!format) 545 if (!format)
@@ -546,181 +560,7 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to)
546 if (!to) 560 if (!to)
547 to = from; 561 to = from;
548 562
549 memset(bits, 0, BITS_TO_LONGS(PERF_PMU_FORMAT_BITS)); 563 memset(bits, 0, BITS_TO_BYTES(PERF_PMU_FORMAT_BITS));
550 for (b = from; b <= to; b++) 564 for (b = from; b <= to; b++)
551 set_bit(b, bits); 565 set_bit(b, bits);
552} 566}
553
554/* Simulated format definitions. */
555static struct test_format {
556 const char *name;
557 const char *value;
558} test_formats[] = {
559 { "krava01", "config:0-1,62-63\n", },
560 { "krava02", "config:10-17\n", },
561 { "krava03", "config:5\n", },
562 { "krava11", "config1:0,2,4,6,8,20-28\n", },
563 { "krava12", "config1:63\n", },
564 { "krava13", "config1:45-47\n", },
565 { "krava21", "config2:0-3,10-13,20-23,30-33,40-43,50-53,60-63\n", },
566 { "krava22", "config2:8,18,48,58\n", },
567 { "krava23", "config2:28-29,38\n", },
568};
569
570#define TEST_FORMATS_CNT (sizeof(test_formats) / sizeof(struct test_format))
571
572/* Simulated users input. */
573static struct parse_events__term test_terms[] = {
574 {
575 .config = (char *) "krava01",
576 .val.num = 15,
577 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
578 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
579 },
580 {
581 .config = (char *) "krava02",
582 .val.num = 170,
583 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
584 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
585 },
586 {
587 .config = (char *) "krava03",
588 .val.num = 1,
589 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
590 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
591 },
592 {
593 .config = (char *) "krava11",
594 .val.num = 27,
595 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
596 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
597 },
598 {
599 .config = (char *) "krava12",
600 .val.num = 1,
601 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
602 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
603 },
604 {
605 .config = (char *) "krava13",
606 .val.num = 2,
607 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
608 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
609 },
610 {
611 .config = (char *) "krava21",
612 .val.num = 119,
613 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
614 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
615 },
616 {
617 .config = (char *) "krava22",
618 .val.num = 11,
619 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
620 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
621 },
622 {
623 .config = (char *) "krava23",
624 .val.num = 2,
625 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
626 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
627 },
628};
629#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
630
631/*
632 * Prepare format directory data, exported by kernel
633 * at /sys/bus/event_source/devices/<dev>/format.
634 */
635static char *test_format_dir_get(void)
636{
637 static char dir[PATH_MAX];
638 unsigned int i;
639
640 snprintf(dir, PATH_MAX, "/tmp/perf-pmu-test-format-XXXXXX");
641 if (!mkdtemp(dir))
642 return NULL;
643
644 for (i = 0; i < TEST_FORMATS_CNT; i++) {
645 static char name[PATH_MAX];
646 struct test_format *format = &test_formats[i];
647 FILE *file;
648
649 snprintf(name, PATH_MAX, "%s/%s", dir, format->name);
650
651 file = fopen(name, "w");
652 if (!file)
653 return NULL;
654
655 if (1 != fwrite(format->value, strlen(format->value), 1, file))
656 break;
657
658 fclose(file);
659 }
660
661 return dir;
662}
663
664/* Cleanup format directory. */
665static int test_format_dir_put(char *dir)
666{
667 char buf[PATH_MAX];
668 snprintf(buf, PATH_MAX, "rm -f %s/*\n", dir);
669 if (system(buf))
670 return -1;
671
672 snprintf(buf, PATH_MAX, "rmdir %s\n", dir);
673 return system(buf);
674}
675
676static struct list_head *test_terms_list(void)
677{
678 static LIST_HEAD(terms);
679 unsigned int i;
680
681 for (i = 0; i < TERMS_CNT; i++)
682 list_add_tail(&test_terms[i].list, &terms);
683
684 return &terms;
685}
686
687#undef TERMS_CNT
688
689int perf_pmu__test(void)
690{
691 char *format = test_format_dir_get();
692 LIST_HEAD(formats);
693 struct list_head *terms = test_terms_list();
694 int ret;
695
696 if (!format)
697 return -EINVAL;
698
699 do {
700 struct perf_event_attr attr;
701
702 memset(&attr, 0, sizeof(attr));
703
704 ret = pmu_format_parse(format, &formats);
705 if (ret)
706 break;
707
708 ret = pmu_config(&formats, &attr, terms);
709 if (ret)
710 break;
711
712 ret = -EINVAL;
713
714 if (attr.config != 0xc00000000002a823)
715 break;
716 if (attr.config1 != 0x8000400000000145)
717 break;
718 if (attr.config2 != 0x0400000020041d07)
719 break;
720
721 ret = 0;
722 } while (0);
723
724 test_format_dir_put(format);
725 return ret;
726}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 39f3abac7744..32fe55b659fa 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -2,7 +2,7 @@
2#define __PMU_H 2#define __PMU_H
3 3
4#include <linux/bitops.h> 4#include <linux/bitops.h>
5#include "../../../include/uapi/linux/perf_event.h" 5#include <linux/perf_event.h>
6 6
7enum { 7enum {
8 PERF_PMU_FORMAT_VALUE_CONFIG, 8 PERF_PMU_FORMAT_VALUE_CONFIG,
@@ -12,19 +12,6 @@ enum {
12 12
13#define PERF_PMU_FORMAT_BITS 64 13#define PERF_PMU_FORMAT_BITS 64
14 14
15struct perf_pmu__format {
16 char *name;
17 int value;
18 DECLARE_BITMAP(bits, PERF_PMU_FORMAT_BITS);
19 struct list_head list;
20};
21
22struct perf_pmu__alias {
23 char *name;
24 struct list_head terms;
25 struct list_head list;
26};
27
28struct perf_pmu { 15struct perf_pmu {
29 char *name; 16 char *name;
30 __u32 type; 17 __u32 type;
@@ -37,15 +24,19 @@ struct perf_pmu {
37struct perf_pmu *perf_pmu__find(char *name); 24struct perf_pmu *perf_pmu__find(char *name);
38int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 25int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
39 struct list_head *head_terms); 26 struct list_head *head_terms);
27int perf_pmu__config_terms(struct list_head *formats,
28 struct perf_event_attr *attr,
29 struct list_head *head_terms);
40int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); 30int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms);
41struct list_head *perf_pmu__alias(struct perf_pmu *pmu, 31struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
42 struct list_head *head_terms); 32 struct list_head *head_terms);
43int perf_pmu_wrap(void); 33int perf_pmu_wrap(void);
44void perf_pmu_error(struct list_head *list, char *name, char const *msg); 34void perf_pmu_error(struct list_head *list, char *name, char const *msg);
45 35
46int perf_pmu__new_format(struct list_head *list, char *name, 36int perf_pmu__new_format(struct list_head *list, char *name,
47 int config, unsigned long *bits); 37 int config, unsigned long *bits);
48void perf_pmu__set_format(unsigned long *bits, long from, long to); 38void perf_pmu__set_format(unsigned long *bits, long from, long to);
39int perf_pmu__format_parse(char *dir, struct list_head *head);
49 40
50struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 41struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
51 42
diff --git a/tools/perf/util/pmu.y b/tools/perf/util/pmu.y
index ec898047ebb9..bfd7e8509869 100644
--- a/tools/perf/util/pmu.y
+++ b/tools/perf/util/pmu.y
@@ -1,5 +1,4 @@
1 1
2%name-prefix "perf_pmu_"
3%parse-param {struct list_head *format} 2%parse-param {struct list_head *format}
4%parse-param {char *name} 3%parse-param {char *name}
5 4
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 1daf5c14e751..be0329394d56 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -413,12 +413,12 @@ static int convert_variable_type(Dwarf_Die *vr_die,
413 dwarf_diename(vr_die), dwarf_diename(&type)); 413 dwarf_diename(vr_die), dwarf_diename(&type));
414 return -EINVAL; 414 return -EINVAL;
415 } 415 }
416 if (die_get_real_type(&type, &type) == NULL) {
417 pr_warning("Failed to get a type"
418 " information.\n");
419 return -ENOENT;
420 }
416 if (ret == DW_TAG_pointer_type) { 421 if (ret == DW_TAG_pointer_type) {
417 if (die_get_real_type(&type, &type) == NULL) {
418 pr_warning("Failed to get a type"
419 " information.\n");
420 return -ENOENT;
421 }
422 while (*ref_ptr) 422 while (*ref_ptr)
423 ref_ptr = &(*ref_ptr)->next; 423 ref_ptr = &(*ref_ptr)->next;
424 /* Add new reference with offset +0 */ 424 /* Add new reference with offset +0 */
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
index 13d36faf64eb..daa17aeb6c63 100644
--- a/tools/perf/util/pstack.c
+++ b/tools/perf/util/pstack.c
@@ -17,59 +17,59 @@ struct pstack {
17 17
18struct pstack *pstack__new(unsigned short max_nr_entries) 18struct pstack *pstack__new(unsigned short max_nr_entries)
19{ 19{
20 struct pstack *self = zalloc((sizeof(*self) + 20 struct pstack *pstack = zalloc((sizeof(*pstack) +
21 max_nr_entries * sizeof(void *))); 21 max_nr_entries * sizeof(void *)));
22 if (self != NULL) 22 if (pstack != NULL)
23 self->max_nr_entries = max_nr_entries; 23 pstack->max_nr_entries = max_nr_entries;
24 return self; 24 return pstack;
25} 25}
26 26
27void pstack__delete(struct pstack *self) 27void pstack__delete(struct pstack *pstack)
28{ 28{
29 free(self); 29 free(pstack);
30} 30}
31 31
32bool pstack__empty(const struct pstack *self) 32bool pstack__empty(const struct pstack *pstack)
33{ 33{
34 return self->top == 0; 34 return pstack->top == 0;
35} 35}
36 36
37void pstack__remove(struct pstack *self, void *key) 37void pstack__remove(struct pstack *pstack, void *key)
38{ 38{
39 unsigned short i = self->top, last_index = self->top - 1; 39 unsigned short i = pstack->top, last_index = pstack->top - 1;
40 40
41 while (i-- != 0) { 41 while (i-- != 0) {
42 if (self->entries[i] == key) { 42 if (pstack->entries[i] == key) {
43 if (i < last_index) 43 if (i < last_index)
44 memmove(self->entries + i, 44 memmove(pstack->entries + i,
45 self->entries + i + 1, 45 pstack->entries + i + 1,
46 (last_index - i) * sizeof(void *)); 46 (last_index - i) * sizeof(void *));
47 --self->top; 47 --pstack->top;
48 return; 48 return;
49 } 49 }
50 } 50 }
51 pr_err("%s: %p not on the pstack!\n", __func__, key); 51 pr_err("%s: %p not on the pstack!\n", __func__, key);
52} 52}
53 53
54void pstack__push(struct pstack *self, void *key) 54void pstack__push(struct pstack *pstack, void *key)
55{ 55{
56 if (self->top == self->max_nr_entries) { 56 if (pstack->top == pstack->max_nr_entries) {
57 pr_err("%s: top=%d, overflow!\n", __func__, self->top); 57 pr_err("%s: top=%d, overflow!\n", __func__, pstack->top);
58 return; 58 return;
59 } 59 }
60 self->entries[self->top++] = key; 60 pstack->entries[pstack->top++] = key;
61} 61}
62 62
63void *pstack__pop(struct pstack *self) 63void *pstack__pop(struct pstack *pstack)
64{ 64{
65 void *ret; 65 void *ret;
66 66
67 if (self->top == 0) { 67 if (pstack->top == 0) {
68 pr_err("%s: underflow!\n", __func__); 68 pr_err("%s: underflow!\n", __func__);
69 return NULL; 69 return NULL;
70 } 70 }
71 71
72 ret = self->entries[--self->top]; 72 ret = pstack->entries[--pstack->top];
73 self->entries[self->top] = NULL; 73 pstack->entries[pstack->top] = NULL;
74 return ret; 74 return ret;
75} 75}
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index c40c2d33199e..64536a993f4a 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -18,4 +18,5 @@ util/cgroup.c
18util/debugfs.c 18util/debugfs.c
19util/rblist.c 19util/rblist.c
20util/strlist.c 20util/strlist.c
21util/sysfs.c
21../../lib/rbtree.c 22../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9181bf212fb9..925e0c3e6d91 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -1015,6 +1015,8 @@ PyMODINIT_FUNC initperf(void)
1015 pyrf_cpu_map__setup_types() < 0) 1015 pyrf_cpu_map__setup_types() < 0)
1016 return; 1016 return;
1017 1017
1018 page_size = sysconf(_SC_PAGE_SIZE);
1019
1018 Py_INCREF(&pyrf_evlist__type); 1020 Py_INCREF(&pyrf_evlist__type);
1019 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type); 1021 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
1020 1022
@@ -1043,3 +1045,12 @@ error:
1043 if (PyErr_Occurred()) 1045 if (PyErr_Occurred())
1044 PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); 1046 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
1045} 1047}
1048
1049/*
1050 * Dummy, to avoid dragging all the test_attr infrastructure in the python
1051 * binding.
1052 */
1053void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
1054 int fd, int group_fd, unsigned long flags)
1055{
1056}
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c
index 0171fb611004..a16cdd2625ad 100644
--- a/tools/perf/util/rblist.c
+++ b/tools/perf/util/rblist.c
@@ -44,6 +44,7 @@ int rblist__add_node(struct rblist *rblist, const void *new_entry)
44void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node) 44void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
45{ 45{
46 rb_erase(rb_node, &rblist->entries); 46 rb_erase(rb_node, &rblist->entries);
47 --rblist->nr_entries;
47 rblist->node_delete(rblist, rb_node); 48 rblist->node_delete(rblist, rb_node);
48} 49}
49 50
@@ -87,8 +88,7 @@ void rblist__delete(struct rblist *rblist)
87 while (next) { 88 while (next) {
88 pos = next; 89 pos = next;
89 next = rb_next(pos); 90 next = rb_next(pos);
90 rb_erase(pos, &rblist->entries); 91 rblist__remove_node(rblist, pos);
91 rblist->node_delete(rblist, pos);
92 } 92 }
93 free(rblist); 93 free(rblist);
94 } 94 }
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index f80605eb1855..eacec859f299 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -292,6 +292,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
292 ns = nsecs - s * NSECS_PER_SEC; 292 ns = nsecs - s * NSECS_PER_SEC;
293 293
294 scripting_context->event_data = data; 294 scripting_context->event_data = data;
295 scripting_context->pevent = evsel->tp_format->pevent;
295 296
296 ENTER; 297 ENTER;
297 SAVETMPS; 298 SAVETMPS;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 730c6630cba5..e87aa5d9696b 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -32,7 +32,6 @@
32#include "../event.h" 32#include "../event.h"
33#include "../thread.h" 33#include "../thread.h"
34#include "../trace-event.h" 34#include "../trace-event.h"
35#include "../evsel.h"
36 35
37PyMODINIT_FUNC initperf_trace_context(void); 36PyMODINIT_FUNC initperf_trace_context(void);
38 37
@@ -266,6 +265,7 @@ static void python_process_tracepoint(union perf_event *perf_event
266 ns = nsecs - s * NSECS_PER_SEC; 265 ns = nsecs - s * NSECS_PER_SEC;
267 266
268 scripting_context->event_data = data; 267 scripting_context->event_data = data;
268 scripting_context->pevent = evsel->tp_format->pevent;
269 269
270 context = PyCObject_FromVoidPtr(scripting_context, NULL); 270 context = PyCObject_FromVoidPtr(scripting_context, NULL);
271 271
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 8cdd23239c90..bd85280bb6e8 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -16,7 +16,6 @@
16#include "cpumap.h" 16#include "cpumap.h"
17#include "event-parse.h" 17#include "event-parse.h"
18#include "perf_regs.h" 18#include "perf_regs.h"
19#include "unwind.h"
20#include "vdso.h" 19#include "vdso.h"
21 20
22static int perf_session__open(struct perf_session *self, bool force) 21static int perf_session__open(struct perf_session *self, bool force)
@@ -87,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
87{ 86{
88 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); 87 u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist);
89 88
90 session->host_machine.id_hdr_size = id_hdr_size;
91 machines__set_id_hdr_size(&session->machines, id_hdr_size); 89 machines__set_id_hdr_size(&session->machines, id_hdr_size);
92} 90}
93 91
94int perf_session__create_kernel_maps(struct perf_session *self) 92int perf_session__create_kernel_maps(struct perf_session *self)
95{ 93{
96 int ret = machine__create_kernel_maps(&self->host_machine); 94 int ret = machine__create_kernel_maps(&self->machines.host);
97 95
98 if (ret >= 0) 96 if (ret >= 0)
99 ret = machines__create_guest_kernel_maps(&self->machines); 97 ret = machines__create_guest_kernel_maps(&self->machines);
@@ -102,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self)
102 100
103static void perf_session__destroy_kernel_maps(struct perf_session *self) 101static void perf_session__destroy_kernel_maps(struct perf_session *self)
104{ 102{
105 machine__destroy_kernel_maps(&self->host_machine); 103 machines__destroy_kernel_maps(&self->machines);
106 machines__destroy_guest_kernel_maps(&self->machines);
107} 104}
108 105
109struct perf_session *perf_session__new(const char *filename, int mode, 106struct perf_session *perf_session__new(const char *filename, int mode,
@@ -128,22 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode,
128 goto out; 125 goto out;
129 126
130 memcpy(self->filename, filename, len); 127 memcpy(self->filename, filename, len);
131 /*
132 * On 64bit we can mmap the data file in one go. No need for tiny mmap
133 * slices. On 32bit we use 32MB.
134 */
135#if BITS_PER_LONG == 64
136 self->mmap_window = ULLONG_MAX;
137#else
138 self->mmap_window = 32 * 1024 * 1024ULL;
139#endif
140 self->machines = RB_ROOT;
141 self->repipe = repipe; 128 self->repipe = repipe;
142 INIT_LIST_HEAD(&self->ordered_samples.samples); 129 INIT_LIST_HEAD(&self->ordered_samples.samples);
143 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 130 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
144 INIT_LIST_HEAD(&self->ordered_samples.to_free); 131 INIT_LIST_HEAD(&self->ordered_samples.to_free);
145 machine__init(&self->host_machine, "", HOST_KERNEL_ID); 132 machines__init(&self->machines);
146 hists__init(&self->hists);
147 133
148 if (mode == O_RDONLY) { 134 if (mode == O_RDONLY) {
149 if (perf_session__open(self, force) < 0) 135 if (perf_session__open(self, force) < 0)
@@ -171,37 +157,30 @@ out_delete:
171 return NULL; 157 return NULL;
172} 158}
173 159
174static void machine__delete_dead_threads(struct machine *machine)
175{
176 struct thread *n, *t;
177
178 list_for_each_entry_safe(t, n, &machine->dead_threads, node) {
179 list_del(&t->node);
180 thread__delete(t);
181 }
182}
183
184static void perf_session__delete_dead_threads(struct perf_session *session) 160static void perf_session__delete_dead_threads(struct perf_session *session)
185{ 161{
186 machine__delete_dead_threads(&session->host_machine); 162 machine__delete_dead_threads(&session->machines.host);
187} 163}
188 164
189static void machine__delete_threads(struct machine *self) 165static void perf_session__delete_threads(struct perf_session *session)
190{ 166{
191 struct rb_node *nd = rb_first(&self->threads); 167 machine__delete_threads(&session->machines.host);
192
193 while (nd) {
194 struct thread *t = rb_entry(nd, struct thread, rb_node);
195
196 rb_erase(&t->rb_node, &self->threads);
197 nd = rb_next(nd);
198 thread__delete(t);
199 }
200} 168}
201 169
202static void perf_session__delete_threads(struct perf_session *session) 170static void perf_session_env__delete(struct perf_session_env *env)
203{ 171{
204 machine__delete_threads(&session->host_machine); 172 free(env->hostname);
173 free(env->os_release);
174 free(env->version);
175 free(env->arch);
176 free(env->cpu_desc);
177 free(env->cpuid);
178
179 free(env->cmdline);
180 free(env->sibling_cores);
181 free(env->sibling_threads);
182 free(env->numa_nodes);
183 free(env->pmu_mappings);
205} 184}
206 185
207void perf_session__delete(struct perf_session *self) 186void perf_session__delete(struct perf_session *self)
@@ -209,198 +188,13 @@ void perf_session__delete(struct perf_session *self)
209 perf_session__destroy_kernel_maps(self); 188 perf_session__destroy_kernel_maps(self);
210 perf_session__delete_dead_threads(self); 189 perf_session__delete_dead_threads(self);
211 perf_session__delete_threads(self); 190 perf_session__delete_threads(self);
212 machine__exit(&self->host_machine); 191 perf_session_env__delete(&self->header.env);
192 machines__exit(&self->machines);
213 close(self->fd); 193 close(self->fd);
214 free(self); 194 free(self);
215 vdso__exit(); 195 vdso__exit();
216} 196}
217 197
218void machine__remove_thread(struct machine *self, struct thread *th)
219{
220 self->last_match = NULL;
221 rb_erase(&th->rb_node, &self->threads);
222 /*
223 * We may have references to this thread, for instance in some hist_entry
224 * instances, so just move them to a separate list.
225 */
226 list_add_tail(&th->node, &self->dead_threads);
227}
228
229static bool symbol__match_parent_regex(struct symbol *sym)
230{
231 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
232 return 1;
233
234 return 0;
235}
236
237static const u8 cpumodes[] = {
238 PERF_RECORD_MISC_USER,
239 PERF_RECORD_MISC_KERNEL,
240 PERF_RECORD_MISC_GUEST_USER,
241 PERF_RECORD_MISC_GUEST_KERNEL
242};
243#define NCPUMODES (sizeof(cpumodes)/sizeof(u8))
244
245static void ip__resolve_ams(struct machine *self, struct thread *thread,
246 struct addr_map_symbol *ams,
247 u64 ip)
248{
249 struct addr_location al;
250 size_t i;
251 u8 m;
252
253 memset(&al, 0, sizeof(al));
254
255 for (i = 0; i < NCPUMODES; i++) {
256 m = cpumodes[i];
257 /*
258 * We cannot use the header.misc hint to determine whether a
259 * branch stack address is user, kernel, guest, hypervisor.
260 * Branches may straddle the kernel/user/hypervisor boundaries.
261 * Thus, we have to try consecutively until we find a match
262 * or else, the symbol is unknown
263 */
264 thread__find_addr_location(thread, self, m, MAP__FUNCTION,
265 ip, &al, NULL);
266 if (al.sym)
267 goto found;
268 }
269found:
270 ams->addr = ip;
271 ams->al_addr = al.addr;
272 ams->sym = al.sym;
273 ams->map = al.map;
274}
275
276struct branch_info *machine__resolve_bstack(struct machine *self,
277 struct thread *thr,
278 struct branch_stack *bs)
279{
280 struct branch_info *bi;
281 unsigned int i;
282
283 bi = calloc(bs->nr, sizeof(struct branch_info));
284 if (!bi)
285 return NULL;
286
287 for (i = 0; i < bs->nr; i++) {
288 ip__resolve_ams(self, thr, &bi[i].to, bs->entries[i].to);
289 ip__resolve_ams(self, thr, &bi[i].from, bs->entries[i].from);
290 bi[i].flags = bs->entries[i].flags;
291 }
292 return bi;
293}
294
295static int machine__resolve_callchain_sample(struct machine *machine,
296 struct thread *thread,
297 struct ip_callchain *chain,
298 struct symbol **parent)
299
300{
301 u8 cpumode = PERF_RECORD_MISC_USER;
302 unsigned int i;
303 int err;
304
305 callchain_cursor_reset(&callchain_cursor);
306
307 if (chain->nr > PERF_MAX_STACK_DEPTH) {
308 pr_warning("corrupted callchain. skipping...\n");
309 return 0;
310 }
311
312 for (i = 0; i < chain->nr; i++) {
313 u64 ip;
314 struct addr_location al;
315
316 if (callchain_param.order == ORDER_CALLEE)
317 ip = chain->ips[i];
318 else
319 ip = chain->ips[chain->nr - i - 1];
320
321 if (ip >= PERF_CONTEXT_MAX) {
322 switch (ip) {
323 case PERF_CONTEXT_HV:
324 cpumode = PERF_RECORD_MISC_HYPERVISOR;
325 break;
326 case PERF_CONTEXT_KERNEL:
327 cpumode = PERF_RECORD_MISC_KERNEL;
328 break;
329 case PERF_CONTEXT_USER:
330 cpumode = PERF_RECORD_MISC_USER;
331 break;
332 default:
333 pr_debug("invalid callchain context: "
334 "%"PRId64"\n", (s64) ip);
335 /*
336 * It seems the callchain is corrupted.
337 * Discard all.
338 */
339 callchain_cursor_reset(&callchain_cursor);
340 return 0;
341 }
342 continue;
343 }
344
345 al.filtered = false;
346 thread__find_addr_location(thread, machine, cpumode,
347 MAP__FUNCTION, ip, &al, NULL);
348 if (al.sym != NULL) {
349 if (sort__has_parent && !*parent &&
350 symbol__match_parent_regex(al.sym))
351 *parent = al.sym;
352 if (!symbol_conf.use_callchain)
353 break;
354 }
355
356 err = callchain_cursor_append(&callchain_cursor,
357 ip, al.map, al.sym);
358 if (err)
359 return err;
360 }
361
362 return 0;
363}
364
365static int unwind_entry(struct unwind_entry *entry, void *arg)
366{
367 struct callchain_cursor *cursor = arg;
368 return callchain_cursor_append(cursor, entry->ip,
369 entry->map, entry->sym);
370}
371
372int machine__resolve_callchain(struct machine *machine,
373 struct perf_evsel *evsel,
374 struct thread *thread,
375 struct perf_sample *sample,
376 struct symbol **parent)
377
378{
379 int ret;
380
381 callchain_cursor_reset(&callchain_cursor);
382
383 ret = machine__resolve_callchain_sample(machine, thread,
384 sample->callchain, parent);
385 if (ret)
386 return ret;
387
388 /* Can we do dwarf post unwind? */
389 if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) &&
390 (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER)))
391 return 0;
392
393 /* Bail out if nothing was captured. */
394 if ((!sample->user_regs.regs) ||
395 (!sample->user_stack.size))
396 return 0;
397
398 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
399 thread, evsel->attr.sample_regs_user,
400 sample);
401
402}
403
404static int process_event_synth_tracing_data_stub(union perf_event *event 198static int process_event_synth_tracing_data_stub(union perf_event *event
405 __maybe_unused, 199 __maybe_unused,
406 struct perf_session *session 200 struct perf_session *session
@@ -1027,7 +821,7 @@ static struct machine *
1027 return perf_session__findnew_machine(session, pid); 821 return perf_session__findnew_machine(session, pid);
1028 } 822 }
1029 823
1030 return perf_session__find_host_machine(session); 824 return &session->machines.host;
1031} 825}
1032 826
1033static int perf_session_deliver_event(struct perf_session *session, 827static int perf_session_deliver_event(struct perf_session *session,
@@ -1065,11 +859,11 @@ static int perf_session_deliver_event(struct perf_session *session,
1065 case PERF_RECORD_SAMPLE: 859 case PERF_RECORD_SAMPLE:
1066 dump_sample(evsel, event, sample); 860 dump_sample(evsel, event, sample);
1067 if (evsel == NULL) { 861 if (evsel == NULL) {
1068 ++session->hists.stats.nr_unknown_id; 862 ++session->stats.nr_unknown_id;
1069 return 0; 863 return 0;
1070 } 864 }
1071 if (machine == NULL) { 865 if (machine == NULL) {
1072 ++session->hists.stats.nr_unprocessable_samples; 866 ++session->stats.nr_unprocessable_samples;
1073 return 0; 867 return 0;
1074 } 868 }
1075 return tool->sample(tool, event, sample, evsel, machine); 869 return tool->sample(tool, event, sample, evsel, machine);
@@ -1083,7 +877,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1083 return tool->exit(tool, event, sample, machine); 877 return tool->exit(tool, event, sample, machine);
1084 case PERF_RECORD_LOST: 878 case PERF_RECORD_LOST:
1085 if (tool->lost == perf_event__process_lost) 879 if (tool->lost == perf_event__process_lost)
1086 session->hists.stats.total_lost += event->lost.lost; 880 session->stats.total_lost += event->lost.lost;
1087 return tool->lost(tool, event, sample, machine); 881 return tool->lost(tool, event, sample, machine);
1088 case PERF_RECORD_READ: 882 case PERF_RECORD_READ:
1089 return tool->read(tool, event, sample, evsel, machine); 883 return tool->read(tool, event, sample, evsel, machine);
@@ -1092,7 +886,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1092 case PERF_RECORD_UNTHROTTLE: 886 case PERF_RECORD_UNTHROTTLE:
1093 return tool->unthrottle(tool, event, sample, machine); 887 return tool->unthrottle(tool, event, sample, machine);
1094 default: 888 default:
1095 ++session->hists.stats.nr_unknown_events; 889 ++session->stats.nr_unknown_events;
1096 return -1; 890 return -1;
1097 } 891 }
1098} 892}
@@ -1106,8 +900,8 @@ static int perf_session__preprocess_sample(struct perf_session *session,
1106 900
1107 if (!ip_callchain__valid(sample->callchain, event)) { 901 if (!ip_callchain__valid(sample->callchain, event)) {
1108 pr_debug("call-chain problem with event, skipping it.\n"); 902 pr_debug("call-chain problem with event, skipping it.\n");
1109 ++session->hists.stats.nr_invalid_chains; 903 ++session->stats.nr_invalid_chains;
1110 session->hists.stats.total_invalid_chains += sample->period; 904 session->stats.total_invalid_chains += sample->period;
1111 return -EINVAL; 905 return -EINVAL;
1112 } 906 }
1113 return 0; 907 return 0;
@@ -1165,7 +959,7 @@ static int perf_session__process_event(struct perf_session *session,
1165 if (event->header.type >= PERF_RECORD_HEADER_MAX) 959 if (event->header.type >= PERF_RECORD_HEADER_MAX)
1166 return -EINVAL; 960 return -EINVAL;
1167 961
1168 hists__inc_nr_events(&session->hists, event->header.type); 962 events_stats__inc(&session->stats, event->header.type);
1169 963
1170 if (event->header.type >= PERF_RECORD_USER_TYPE_START) 964 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
1171 return perf_session__process_user_event(session, event, tool, file_offset); 965 return perf_session__process_user_event(session, event, tool, file_offset);
@@ -1201,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self)
1201 995
1202struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 996struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1203{ 997{
1204 return machine__findnew_thread(&session->host_machine, pid); 998 return machine__findnew_thread(&session->machines.host, pid);
1205} 999}
1206 1000
1207static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1001static struct thread *perf_session__register_idle_thread(struct perf_session *self)
@@ -1220,39 +1014,39 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1220 const struct perf_tool *tool) 1014 const struct perf_tool *tool)
1221{ 1015{
1222 if (tool->lost == perf_event__process_lost && 1016 if (tool->lost == perf_event__process_lost &&
1223 session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { 1017 session->stats.nr_events[PERF_RECORD_LOST] != 0) {
1224 ui__warning("Processed %d events and lost %d chunks!\n\n" 1018 ui__warning("Processed %d events and lost %d chunks!\n\n"
1225 "Check IO/CPU overload!\n\n", 1019 "Check IO/CPU overload!\n\n",
1226 session->hists.stats.nr_events[0], 1020 session->stats.nr_events[0],
1227 session->hists.stats.nr_events[PERF_RECORD_LOST]); 1021 session->stats.nr_events[PERF_RECORD_LOST]);
1228 } 1022 }
1229 1023
1230 if (session->hists.stats.nr_unknown_events != 0) { 1024 if (session->stats.nr_unknown_events != 0) {
1231 ui__warning("Found %u unknown events!\n\n" 1025 ui__warning("Found %u unknown events!\n\n"
1232 "Is this an older tool processing a perf.data " 1026 "Is this an older tool processing a perf.data "
1233 "file generated by a more recent tool?\n\n" 1027 "file generated by a more recent tool?\n\n"
1234 "If that is not the case, consider " 1028 "If that is not the case, consider "
1235 "reporting to linux-kernel@vger.kernel.org.\n\n", 1029 "reporting to linux-kernel@vger.kernel.org.\n\n",
1236 session->hists.stats.nr_unknown_events); 1030 session->stats.nr_unknown_events);
1237 } 1031 }
1238 1032
1239 if (session->hists.stats.nr_unknown_id != 0) { 1033 if (session->stats.nr_unknown_id != 0) {
1240 ui__warning("%u samples with id not present in the header\n", 1034 ui__warning("%u samples with id not present in the header\n",
1241 session->hists.stats.nr_unknown_id); 1035 session->stats.nr_unknown_id);
1242 } 1036 }
1243 1037
1244 if (session->hists.stats.nr_invalid_chains != 0) { 1038 if (session->stats.nr_invalid_chains != 0) {
1245 ui__warning("Found invalid callchains!\n\n" 1039 ui__warning("Found invalid callchains!\n\n"
1246 "%u out of %u events were discarded for this reason.\n\n" 1040 "%u out of %u events were discarded for this reason.\n\n"
1247 "Consider reporting to linux-kernel@vger.kernel.org.\n\n", 1041 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
1248 session->hists.stats.nr_invalid_chains, 1042 session->stats.nr_invalid_chains,
1249 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]); 1043 session->stats.nr_events[PERF_RECORD_SAMPLE]);
1250 } 1044 }
1251 1045
1252 if (session->hists.stats.nr_unprocessable_samples != 0) { 1046 if (session->stats.nr_unprocessable_samples != 0) {
1253 ui__warning("%u unprocessable samples recorded.\n" 1047 ui__warning("%u unprocessable samples recorded.\n"
1254 "Do you have a KVM guest running and not using 'perf kvm'?\n", 1048 "Do you have a KVM guest running and not using 'perf kvm'?\n",
1255 session->hists.stats.nr_unprocessable_samples); 1049 session->stats.nr_unprocessable_samples);
1256 } 1050 }
1257} 1051}
1258 1052
@@ -1369,21 +1163,31 @@ fetch_mmaped_event(struct perf_session *session,
1369 return event; 1163 return event;
1370} 1164}
1371 1165
1166/*
1167 * On 64bit we can mmap the data file in one go. No need for tiny mmap
1168 * slices. On 32bit we use 32MB.
1169 */
1170#if BITS_PER_LONG == 64
1171#define MMAP_SIZE ULLONG_MAX
1172#define NUM_MMAPS 1
1173#else
1174#define MMAP_SIZE (32 * 1024 * 1024ULL)
1175#define NUM_MMAPS 128
1176#endif
1177
1372int __perf_session__process_events(struct perf_session *session, 1178int __perf_session__process_events(struct perf_session *session,
1373 u64 data_offset, u64 data_size, 1179 u64 data_offset, u64 data_size,
1374 u64 file_size, struct perf_tool *tool) 1180 u64 file_size, struct perf_tool *tool)
1375{ 1181{
1376 u64 head, page_offset, file_offset, file_pos, progress_next; 1182 u64 head, page_offset, file_offset, file_pos, progress_next;
1377 int err, mmap_prot, mmap_flags, map_idx = 0; 1183 int err, mmap_prot, mmap_flags, map_idx = 0;
1378 size_t page_size, mmap_size; 1184 size_t mmap_size;
1379 char *buf, *mmaps[8]; 1185 char *buf, *mmaps[NUM_MMAPS];
1380 union perf_event *event; 1186 union perf_event *event;
1381 uint32_t size; 1187 uint32_t size;
1382 1188
1383 perf_tool__fill_defaults(tool); 1189 perf_tool__fill_defaults(tool);
1384 1190
1385 page_size = sysconf(_SC_PAGESIZE);
1386
1387 page_offset = page_size * (data_offset / page_size); 1191 page_offset = page_size * (data_offset / page_size);
1388 file_offset = page_offset; 1192 file_offset = page_offset;
1389 head = data_offset - page_offset; 1193 head = data_offset - page_offset;
@@ -1393,7 +1197,7 @@ int __perf_session__process_events(struct perf_session *session,
1393 1197
1394 progress_next = file_size / 16; 1198 progress_next = file_size / 16;
1395 1199
1396 mmap_size = session->mmap_window; 1200 mmap_size = MMAP_SIZE;
1397 if (mmap_size > file_size) 1201 if (mmap_size > file_size)
1398 mmap_size = file_size; 1202 mmap_size = file_size;
1399 1203
@@ -1460,6 +1264,7 @@ more:
1460 session->ordered_samples.next_flush = ULLONG_MAX; 1264 session->ordered_samples.next_flush = ULLONG_MAX;
1461 err = flush_sample_queue(session, tool); 1265 err = flush_sample_queue(session, tool);
1462out_err: 1266out_err:
1267 ui_progress__finish();
1463 perf_session__warn_about_errors(session, tool); 1268 perf_session__warn_about_errors(session, tool);
1464 perf_session_free_sample_buffers(session); 1269 perf_session_free_sample_buffers(session);
1465 return err; 1270 return err;
@@ -1527,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1527 1332
1528size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) 1333size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
1529{ 1334{
1530 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + 1335 return machines__fprintf_dsos(&self->machines, fp);
1531 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
1532 machines__fprintf_dsos(&self->machines, fp);
1533} 1336}
1534 1337
1535size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, 1338size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1536 bool with_hits) 1339 bool (skip)(struct dso *dso, int parm), int parm)
1537{ 1340{
1538 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits); 1341 return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm);
1539 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1540} 1342}
1541 1343
1542size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) 1344size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1544,11 +1346,11 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1544 struct perf_evsel *pos; 1346 struct perf_evsel *pos;
1545 size_t ret = fprintf(fp, "Aggregated stats:\n"); 1347 size_t ret = fprintf(fp, "Aggregated stats:\n");
1546 1348
1547 ret += hists__fprintf_nr_events(&session->hists, fp); 1349 ret += events_stats__fprintf(&session->stats, fp);
1548 1350
1549 list_for_each_entry(pos, &session->evlist->entries, node) { 1351 list_for_each_entry(pos, &session->evlist->entries, node) {
1550 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); 1352 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1551 ret += hists__fprintf_nr_events(&pos->hists, fp); 1353 ret += events_stats__fprintf(&pos->hists.stats, fp);
1552 } 1354 }
1553 1355
1554 return ret; 1356 return ret;
@@ -1560,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp)
1560 * FIXME: Here we have to actually print all the machines in this 1362 * FIXME: Here we have to actually print all the machines in this
1561 * session, not just the host... 1363 * session, not just the host...
1562 */ 1364 */
1563 return machine__fprintf(&session->host_machine, fp); 1365 return machine__fprintf(&session->machines.host, fp);
1564} 1366}
1565 1367
1566void perf_session__remove_thread(struct perf_session *session, 1368void perf_session__remove_thread(struct perf_session *session,
@@ -1569,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session,
1569 /* 1371 /*
1570 * FIXME: This one makes no sense, we need to remove the thread from 1372 * FIXME: This one makes no sense, we need to remove the thread from
1571 * the machine it belongs to, perf_session can have many machines, so 1373 * the machine it belongs to, perf_session can have many machines, so
1572 * doing it always on ->host_machine is wrong. Fix when auditing all 1374 * doing it always on ->machines.host is wrong. Fix when auditing all
1573 * the 'perf kvm' code. 1375 * the 'perf kvm' code.
1574 */ 1376 */
1575 machine__remove_thread(&session->host_machine, th); 1377 machine__remove_thread(&session->machines.host, th);
1576} 1378}
1577 1379
1578struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 1380struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index dd6426163ba6..b5c0847edfa9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -4,10 +4,11 @@
4#include "hist.h" 4#include "hist.h"
5#include "event.h" 5#include "event.h"
6#include "header.h" 6#include "header.h"
7#include "machine.h"
7#include "symbol.h" 8#include "symbol.h"
8#include "thread.h" 9#include "thread.h"
9#include <linux/rbtree.h> 10#include <linux/rbtree.h>
10#include "../../../include/uapi/linux/perf_event.h" 11#include <linux/perf_event.h>
11 12
12struct sample_queue; 13struct sample_queue;
13struct ip_callchain; 14struct ip_callchain;
@@ -29,16 +30,10 @@ struct ordered_samples {
29struct perf_session { 30struct perf_session {
30 struct perf_header header; 31 struct perf_header header;
31 unsigned long size; 32 unsigned long size;
32 unsigned long mmap_window; 33 struct machines machines;
33 struct machine host_machine;
34 struct rb_root machines;
35 struct perf_evlist *evlist; 34 struct perf_evlist *evlist;
36 struct pevent *pevent; 35 struct pevent *pevent;
37 /* 36 struct events_stats stats;
38 * FIXME: Need to split this up further, we need global
39 * stats + per event stats.
40 */
41 struct hists hists;
42 int fd; 37 int fd;
43 bool fd_pipe; 38 bool fd_pipe;
44 bool repipe; 39 bool repipe;
@@ -53,7 +48,7 @@ struct perf_tool;
53struct perf_session *perf_session__new(const char *filename, int mode, 48struct perf_session *perf_session__new(const char *filename, int mode,
54 bool force, bool repipe, 49 bool force, bool repipe,
55 struct perf_tool *tool); 50 struct perf_tool *tool);
56void perf_session__delete(struct perf_session *self); 51void perf_session__delete(struct perf_session *session);
57 52
58void perf_event_header__bswap(struct perf_event_header *self); 53void perf_event_header__bswap(struct perf_event_header *self);
59 54
@@ -68,10 +63,6 @@ int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel
68 struct ip_callchain *chain, 63 struct ip_callchain *chain,
69 struct symbol **parent); 64 struct symbol **parent);
70 65
71struct branch_info *machine__resolve_bstack(struct machine *self,
72 struct thread *thread,
73 struct branch_stack *bs);
74
75bool perf_session__has_traces(struct perf_session *self, const char *msg); 66bool perf_session__has_traces(struct perf_session *self, const char *msg);
76 67
77void mem_bswap_64(void *src, int byte_size); 68void mem_bswap_64(void *src, int byte_size);
@@ -84,43 +75,24 @@ void perf_session__set_id_hdr_size(struct perf_session *session);
84void perf_session__remove_thread(struct perf_session *self, struct thread *th); 75void perf_session__remove_thread(struct perf_session *self, struct thread *th);
85 76
86static inline 77static inline
87struct machine *perf_session__find_host_machine(struct perf_session *self)
88{
89 return &self->host_machine;
90}
91
92static inline
93struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) 78struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
94{ 79{
95 if (pid == HOST_KERNEL_ID)
96 return &self->host_machine;
97 return machines__find(&self->machines, pid); 80 return machines__find(&self->machines, pid);
98} 81}
99 82
100static inline 83static inline
101struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) 84struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
102{ 85{
103 if (pid == HOST_KERNEL_ID)
104 return &self->host_machine;
105 return machines__findnew(&self->machines, pid); 86 return machines__findnew(&self->machines, pid);
106} 87}
107 88
108static inline
109void perf_session__process_machines(struct perf_session *self,
110 struct perf_tool *tool,
111 machine__process_t process)
112{
113 process(&self->host_machine, tool);
114 return machines__process(&self->machines, process, tool);
115}
116
117struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 89struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
118size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 90size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
119 91
120size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 92size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
121 93
122size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, 94size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
123 FILE *fp, bool with_hits); 95 bool (fn)(struct dso *dso, int parm), int parm);
124 96
125size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); 97size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
126 98
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cfd1c0feb32d..d41926cb9e3f 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -60,7 +60,7 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
60static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 60static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
61 size_t size, unsigned int width) 61 size_t size, unsigned int width)
62{ 62{
63 return repsep_snprintf(bf, size, "%*s:%5d", width, 63 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
64 self->thread->comm ?: "", self->thread->pid); 64 self->thread->comm ?: "", self->thread->pid);
65} 65}
66 66
@@ -97,6 +97,16 @@ static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 97 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
98} 98}
99 99
100struct sort_entry sort_comm = {
101 .se_header = "Command",
102 .se_cmp = sort__comm_cmp,
103 .se_collapse = sort__comm_collapse,
104 .se_snprintf = hist_entry__comm_snprintf,
105 .se_width_idx = HISTC_COMM,
106};
107
108/* --sort dso */
109
100static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) 110static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
101{ 111{
102 struct dso *dso_l = map_l ? map_l->dso : NULL; 112 struct dso *dso_l = map_l ? map_l->dso : NULL;
@@ -117,40 +127,12 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
117 return strcmp(dso_name_l, dso_name_r); 127 return strcmp(dso_name_l, dso_name_r);
118} 128}
119 129
120struct sort_entry sort_comm = {
121 .se_header = "Command",
122 .se_cmp = sort__comm_cmp,
123 .se_collapse = sort__comm_collapse,
124 .se_snprintf = hist_entry__comm_snprintf,
125 .se_width_idx = HISTC_COMM,
126};
127
128/* --sort dso */
129
130static int64_t 130static int64_t
131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
132{ 132{
133 return _sort__dso_cmp(left->ms.map, right->ms.map); 133 return _sort__dso_cmp(left->ms.map, right->ms.map);
134} 134}
135 135
136
137static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
138 u64 ip_l, u64 ip_r)
139{
140 if (!sym_l || !sym_r)
141 return cmp_null(sym_l, sym_r);
142
143 if (sym_l == sym_r)
144 return 0;
145
146 if (sym_l)
147 ip_l = sym_l->start;
148 if (sym_r)
149 ip_r = sym_r->start;
150
151 return (int64_t)(ip_r - ip_l);
152}
153
154static int _hist_entry__dso_snprintf(struct map *map, char *bf, 136static int _hist_entry__dso_snprintf(struct map *map, char *bf,
155 size_t size, unsigned int width) 137 size_t size, unsigned int width)
156{ 138{
@@ -169,9 +151,43 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
169 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); 151 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
170} 152}
171 153
154struct sort_entry sort_dso = {
155 .se_header = "Shared Object",
156 .se_cmp = sort__dso_cmp,
157 .se_snprintf = hist_entry__dso_snprintf,
158 .se_width_idx = HISTC_DSO,
159};
160
161/* --sort symbol */
162
163static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
164{
165 u64 ip_l, ip_r;
166
167 if (!sym_l || !sym_r)
168 return cmp_null(sym_l, sym_r);
169
170 if (sym_l == sym_r)
171 return 0;
172
173 ip_l = sym_l->start;
174 ip_r = sym_r->start;
175
176 return (int64_t)(ip_r - ip_l);
177}
178
179static int64_t
180sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
181{
182 if (!left->ms.sym && !right->ms.sym)
183 return right->level - left->level;
184
185 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
186}
187
172static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 188static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
173 u64 ip, char level, char *bf, size_t size, 189 u64 ip, char level, char *bf, size_t size,
174 unsigned int width __maybe_unused) 190 unsigned int width)
175{ 191{
176 size_t ret = 0; 192 size_t ret = 0;
177 193
@@ -197,43 +213,13 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
197 return ret; 213 return ret;
198} 214}
199 215
200
201struct sort_entry sort_dso = {
202 .se_header = "Shared Object",
203 .se_cmp = sort__dso_cmp,
204 .se_snprintf = hist_entry__dso_snprintf,
205 .se_width_idx = HISTC_DSO,
206};
207
208static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, 216static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
209 size_t size, 217 size_t size, unsigned int width)
210 unsigned int width __maybe_unused)
211{ 218{
212 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, 219 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
213 self->level, bf, size, width); 220 self->level, bf, size, width);
214} 221}
215 222
216/* --sort symbol */
217static int64_t
218sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
219{
220 u64 ip_l, ip_r;
221
222 if (!left->ms.sym && !right->ms.sym)
223 return right->level - left->level;
224
225 if (!left->ms.sym || !right->ms.sym)
226 return cmp_null(left->ms.sym, right->ms.sym);
227
228 if (left->ms.sym == right->ms.sym)
229 return 0;
230
231 ip_l = left->ms.sym->start;
232 ip_r = right->ms.sym->start;
233
234 return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
235}
236
237struct sort_entry sort_sym = { 223struct sort_entry sort_sym = {
238 .se_header = "Symbol", 224 .se_header = "Symbol",
239 .se_cmp = sort__sym_cmp, 225 .se_cmp = sort__sym_cmp,
@@ -253,7 +239,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
253 size_t size, 239 size_t size,
254 unsigned int width __maybe_unused) 240 unsigned int width __maybe_unused)
255{ 241{
256 FILE *fp; 242 FILE *fp = NULL;
257 char cmd[PATH_MAX + 2], *path = self->srcline, *nl; 243 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
258 size_t line_len; 244 size_t line_len;
259 245
@@ -274,7 +260,6 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
274 260
275 if (getline(&path, &line_len, fp) < 0 || !line_len) 261 if (getline(&path, &line_len, fp) < 0 || !line_len)
276 goto out_ip; 262 goto out_ip;
277 fclose(fp);
278 self->srcline = strdup(path); 263 self->srcline = strdup(path);
279 if (self->srcline == NULL) 264 if (self->srcline == NULL)
280 goto out_ip; 265 goto out_ip;
@@ -284,8 +269,12 @@ static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
284 *nl = '\0'; 269 *nl = '\0';
285 path = self->srcline; 270 path = self->srcline;
286out_path: 271out_path:
272 if (fp)
273 pclose(fp);
287 return repsep_snprintf(bf, size, "%s", path); 274 return repsep_snprintf(bf, size, "%s", path);
288out_ip: 275out_ip:
276 if (fp)
277 pclose(fp);
289 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip); 278 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
290} 279}
291 280
@@ -335,7 +324,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
335static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, 324static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
336 size_t size, unsigned int width) 325 size_t size, unsigned int width)
337{ 326{
338 return repsep_snprintf(bf, size, "%-*d", width, self->cpu); 327 return repsep_snprintf(bf, size, "%*d", width, self->cpu);
339} 328}
340 329
341struct sort_entry sort_cpu = { 330struct sort_entry sort_cpu = {
@@ -345,6 +334,8 @@ struct sort_entry sort_cpu = {
345 .se_width_idx = HISTC_CPU, 334 .se_width_idx = HISTC_CPU,
346}; 335};
347 336
337/* sort keys for branch stacks */
338
348static int64_t 339static int64_t
349sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) 340sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
350{ 341{
@@ -359,13 +350,6 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
359 bf, size, width); 350 bf, size, width);
360} 351}
361 352
362struct sort_entry sort_dso_from = {
363 .se_header = "Source Shared Object",
364 .se_cmp = sort__dso_from_cmp,
365 .se_snprintf = hist_entry__dso_from_snprintf,
366 .se_width_idx = HISTC_DSO_FROM,
367};
368
369static int64_t 353static int64_t
370sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 354sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
371{ 355{
@@ -389,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
389 if (!from_l->sym && !from_r->sym) 373 if (!from_l->sym && !from_r->sym)
390 return right->level - left->level; 374 return right->level - left->level;
391 375
392 return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr, 376 return _sort__sym_cmp(from_l->sym, from_r->sym);
393 from_r->addr);
394} 377}
395 378
396static int64_t 379static int64_t
@@ -402,12 +385,11 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
402 if (!to_l->sym && !to_r->sym) 385 if (!to_l->sym && !to_r->sym)
403 return right->level - left->level; 386 return right->level - left->level;
404 387
405 return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr); 388 return _sort__sym_cmp(to_l->sym, to_r->sym);
406} 389}
407 390
408static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, 391static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
409 size_t size, 392 size_t size, unsigned int width)
410 unsigned int width __maybe_unused)
411{ 393{
412 struct addr_map_symbol *from = &self->branch_info->from; 394 struct addr_map_symbol *from = &self->branch_info->from;
413 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 395 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
@@ -416,8 +398,7 @@ static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
416} 398}
417 399
418static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, 400static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
419 size_t size, 401 size_t size, unsigned int width)
420 unsigned int width __maybe_unused)
421{ 402{
422 struct addr_map_symbol *to = &self->branch_info->to; 403 struct addr_map_symbol *to = &self->branch_info->to;
423 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 404 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
@@ -425,6 +406,13 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
425 406
426} 407}
427 408
409struct sort_entry sort_dso_from = {
410 .se_header = "Source Shared Object",
411 .se_cmp = sort__dso_from_cmp,
412 .se_snprintf = hist_entry__dso_from_snprintf,
413 .se_width_idx = HISTC_DSO_FROM,
414};
415
428struct sort_entry sort_dso_to = { 416struct sort_entry sort_dso_to = {
429 .se_header = "Target Shared Object", 417 .se_header = "Target Shared Object",
430 .se_cmp = sort__dso_to_cmp, 418 .se_cmp = sort__dso_to_cmp,
@@ -484,30 +472,40 @@ struct sort_dimension {
484 472
485#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 473#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
486 474
487static struct sort_dimension sort_dimensions[] = { 475static struct sort_dimension common_sort_dimensions[] = {
488 DIM(SORT_PID, "pid", sort_thread), 476 DIM(SORT_PID, "pid", sort_thread),
489 DIM(SORT_COMM, "comm", sort_comm), 477 DIM(SORT_COMM, "comm", sort_comm),
490 DIM(SORT_DSO, "dso", sort_dso), 478 DIM(SORT_DSO, "dso", sort_dso),
491 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
492 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
493 DIM(SORT_SYM, "symbol", sort_sym), 479 DIM(SORT_SYM, "symbol", sort_sym),
494 DIM(SORT_SYM_TO, "symbol_from", sort_sym_from),
495 DIM(SORT_SYM_FROM, "symbol_to", sort_sym_to),
496 DIM(SORT_PARENT, "parent", sort_parent), 480 DIM(SORT_PARENT, "parent", sort_parent),
497 DIM(SORT_CPU, "cpu", sort_cpu), 481 DIM(SORT_CPU, "cpu", sort_cpu),
498 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
499 DIM(SORT_SRCLINE, "srcline", sort_srcline), 482 DIM(SORT_SRCLINE, "srcline", sort_srcline),
500}; 483};
501 484
485#undef DIM
486
487#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
488
489static struct sort_dimension bstack_sort_dimensions[] = {
490 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
491 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
492 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
493 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
494 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
495};
496
497#undef DIM
498
502int sort_dimension__add(const char *tok) 499int sort_dimension__add(const char *tok)
503{ 500{
504 unsigned int i; 501 unsigned int i;
505 502
506 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) { 503 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
507 struct sort_dimension *sd = &sort_dimensions[i]; 504 struct sort_dimension *sd = &common_sort_dimensions[i];
508 505
509 if (strncasecmp(tok, sd->name, strlen(tok))) 506 if (strncasecmp(tok, sd->name, strlen(tok)))
510 continue; 507 continue;
508
511 if (sd->entry == &sort_parent) { 509 if (sd->entry == &sort_parent) {
512 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 510 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
513 if (ret) { 511 if (ret) {
@@ -518,9 +516,7 @@ int sort_dimension__add(const char *tok)
518 return -EINVAL; 516 return -EINVAL;
519 } 517 }
520 sort__has_parent = 1; 518 sort__has_parent = 1;
521 } else if (sd->entry == &sort_sym || 519 } else if (sd->entry == &sort_sym) {
522 sd->entry == &sort_sym_from ||
523 sd->entry == &sort_sym_to) {
524 sort__has_sym = 1; 520 sort__has_sym = 1;
525 } 521 }
526 522
@@ -530,52 +526,69 @@ int sort_dimension__add(const char *tok)
530 if (sd->entry->se_collapse) 526 if (sd->entry->se_collapse)
531 sort__need_collapse = 1; 527 sort__need_collapse = 1;
532 528
533 if (list_empty(&hist_entry__sort_list)) { 529 if (list_empty(&hist_entry__sort_list))
534 if (!strcmp(sd->name, "pid")) 530 sort__first_dimension = i;
535 sort__first_dimension = SORT_PID;
536 else if (!strcmp(sd->name, "comm"))
537 sort__first_dimension = SORT_COMM;
538 else if (!strcmp(sd->name, "dso"))
539 sort__first_dimension = SORT_DSO;
540 else if (!strcmp(sd->name, "symbol"))
541 sort__first_dimension = SORT_SYM;
542 else if (!strcmp(sd->name, "parent"))
543 sort__first_dimension = SORT_PARENT;
544 else if (!strcmp(sd->name, "cpu"))
545 sort__first_dimension = SORT_CPU;
546 else if (!strcmp(sd->name, "symbol_from"))
547 sort__first_dimension = SORT_SYM_FROM;
548 else if (!strcmp(sd->name, "symbol_to"))
549 sort__first_dimension = SORT_SYM_TO;
550 else if (!strcmp(sd->name, "dso_from"))
551 sort__first_dimension = SORT_DSO_FROM;
552 else if (!strcmp(sd->name, "dso_to"))
553 sort__first_dimension = SORT_DSO_TO;
554 else if (!strcmp(sd->name, "mispredict"))
555 sort__first_dimension = SORT_MISPREDICT;
556 }
557 531
558 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 532 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
559 sd->taken = 1; 533 sd->taken = 1;
560 534
561 return 0; 535 return 0;
562 } 536 }
537
538 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
539 struct sort_dimension *sd = &bstack_sort_dimensions[i];
540
541 if (strncasecmp(tok, sd->name, strlen(tok)))
542 continue;
543
544 if (sort__branch_mode != 1)
545 return -EINVAL;
546
547 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
548 sort__has_sym = 1;
549
550 if (sd->taken)
551 return 0;
552
553 if (sd->entry->se_collapse)
554 sort__need_collapse = 1;
555
556 if (list_empty(&hist_entry__sort_list))
557 sort__first_dimension = i + __SORT_BRANCH_STACK;
558
559 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
560 sd->taken = 1;
561
562 return 0;
563 }
564
563 return -ESRCH; 565 return -ESRCH;
564} 566}
565 567
566void setup_sorting(const char * const usagestr[], const struct option *opts) 568int setup_sorting(void)
567{ 569{
568 char *tmp, *tok, *str = strdup(sort_order); 570 char *tmp, *tok, *str = strdup(sort_order);
571 int ret = 0;
572
573 if (str == NULL) {
574 error("Not enough memory to setup sort keys");
575 return -ENOMEM;
576 }
569 577
570 for (tok = strtok_r(str, ", ", &tmp); 578 for (tok = strtok_r(str, ", ", &tmp);
571 tok; tok = strtok_r(NULL, ", ", &tmp)) { 579 tok; tok = strtok_r(NULL, ", ", &tmp)) {
572 if (sort_dimension__add(tok) < 0) { 580 ret = sort_dimension__add(tok);
581 if (ret == -EINVAL) {
582 error("Invalid --sort key: `%s'", tok);
583 break;
584 } else if (ret == -ESRCH) {
573 error("Unknown --sort key: `%s'", tok); 585 error("Unknown --sort key: `%s'", tok);
574 usage_with_options(usagestr, opts); 586 break;
575 } 587 }
576 } 588 }
577 589
578 free(str); 590 free(str);
591 return ret;
579} 592}
580 593
581void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 594void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 5786f323b597..b13e56f6ccbe 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -52,6 +52,19 @@ struct he_stat {
52 u32 nr_events; 52 u32 nr_events;
53}; 53};
54 54
55struct hist_entry_diff {
56 bool computed;
57
58 /* PERF_HPP__DELTA */
59 double period_ratio_delta;
60
61 /* PERF_HPP__RATIO */
62 double period_ratio;
63
64 /* HISTC_WEIGHTED_DIFF */
65 s64 wdiff;
66};
67
55/** 68/**
56 * struct hist_entry - histogram entry 69 * struct hist_entry - histogram entry
57 * 70 *
@@ -61,12 +74,18 @@ struct he_stat {
61struct hist_entry { 74struct hist_entry {
62 struct rb_node rb_node_in; 75 struct rb_node rb_node_in;
63 struct rb_node rb_node; 76 struct rb_node rb_node;
77 union {
78 struct list_head node;
79 struct list_head head;
80 } pairs;
64 struct he_stat stat; 81 struct he_stat stat;
65 struct map_symbol ms; 82 struct map_symbol ms;
66 struct thread *thread; 83 struct thread *thread;
67 u64 ip; 84 u64 ip;
68 s32 cpu; 85 s32 cpu;
69 86
87 struct hist_entry_diff diff;
88
70 /* XXX These two should move to some tree widget lib */ 89 /* XXX These two should move to some tree widget lib */
71 u16 row_offset; 90 u16 row_offset;
72 u16 nr_rows; 91 u16 nr_rows;
@@ -78,28 +97,47 @@ struct hist_entry {
78 char *srcline; 97 char *srcline;
79 struct symbol *parent; 98 struct symbol *parent;
80 unsigned long position; 99 unsigned long position;
81 union { 100 struct rb_root sorted_chain;
82 struct hist_entry *pair;
83 struct rb_root sorted_chain;
84 };
85 struct branch_info *branch_info; 101 struct branch_info *branch_info;
86 struct hists *hists; 102 struct hists *hists;
87 struct callchain_root callchain[0]; 103 struct callchain_root callchain[0];
88}; 104};
89 105
106static inline bool hist_entry__has_pairs(struct hist_entry *he)
107{
108 return !list_empty(&he->pairs.node);
109}
110
111static inline struct hist_entry *hist_entry__next_pair(struct hist_entry *he)
112{
113 if (hist_entry__has_pairs(he))
114 return list_entry(he->pairs.node.next, struct hist_entry, pairs.node);
115 return NULL;
116}
117
118static inline void hist_entry__add_pair(struct hist_entry *he,
119 struct hist_entry *pair)
120{
121 list_add_tail(&he->pairs.head, &pair->pairs.node);
122}
123
90enum sort_type { 124enum sort_type {
125 /* common sort keys */
91 SORT_PID, 126 SORT_PID,
92 SORT_COMM, 127 SORT_COMM,
93 SORT_DSO, 128 SORT_DSO,
94 SORT_SYM, 129 SORT_SYM,
95 SORT_PARENT, 130 SORT_PARENT,
96 SORT_CPU, 131 SORT_CPU,
97 SORT_DSO_FROM, 132 SORT_SRCLINE,
133
134 /* branch stack specific sort keys */
135 __SORT_BRANCH_STACK,
136 SORT_DSO_FROM = __SORT_BRANCH_STACK,
98 SORT_DSO_TO, 137 SORT_DSO_TO,
99 SORT_SYM_FROM, 138 SORT_SYM_FROM,
100 SORT_SYM_TO, 139 SORT_SYM_TO,
101 SORT_MISPREDICT, 140 SORT_MISPREDICT,
102 SORT_SRCLINE,
103}; 141};
104 142
105/* 143/*
@@ -122,7 +160,7 @@ struct sort_entry {
122extern struct sort_entry sort_thread; 160extern struct sort_entry sort_thread;
123extern struct list_head hist_entry__sort_list; 161extern struct list_head hist_entry__sort_list;
124 162
125void setup_sorting(const char * const usagestr[], const struct option *opts); 163int setup_sorting(void);
126extern int sort_dimension__add(const char *); 164extern int sort_dimension__add(const char *);
127void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 165void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
128 const char *list_name, FILE *fp); 166 const char *list_name, FILE *fp);
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 2eeb51baf077..cfa906882e2c 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -90,17 +90,17 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
90 if (!strbuf_avail(sb)) 90 if (!strbuf_avail(sb))
91 strbuf_grow(sb, 64); 91 strbuf_grow(sb, 64);
92 va_start(ap, fmt); 92 va_start(ap, fmt);
93 len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 93 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
94 va_end(ap); 94 va_end(ap);
95 if (len < 0) 95 if (len < 0)
96 die("your vscnprintf is broken"); 96 die("your vsnprintf is broken");
97 if (len > strbuf_avail(sb)) { 97 if (len > strbuf_avail(sb)) {
98 strbuf_grow(sb, len); 98 strbuf_grow(sb, len);
99 va_start(ap, fmt); 99 va_start(ap, fmt);
100 len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); 100 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
101 va_end(ap); 101 va_end(ap);
102 if (len > strbuf_avail(sb)) { 102 if (len > strbuf_avail(sb)) {
103 die("this should not happen, your snprintf is broken"); 103 die("this should not happen, your vsnprintf is broken");
104 } 104 }
105 } 105 }
106 strbuf_setlen(sb, sb->len + len); 106 strbuf_setlen(sb, sb->len + len);
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 32170590892d..29c7b2cb2521 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -314,6 +314,42 @@ int strtailcmp(const char *s1, const char *s2)
314} 314}
315 315
316/** 316/**
317 * strxfrchar - Locate and replace character in @s
318 * @s: The string to be searched/changed.
319 * @from: Source character to be replaced.
320 * @to: Destination character.
321 *
322 * Return pointer to the changed string.
323 */
324char *strxfrchar(char *s, char from, char to)
325{
326 char *p = s;
327
328 while ((p = strchr(p, from)) != NULL)
329 *p++ = to;
330
331 return s;
332}
333
334/**
335 * ltrim - Removes leading whitespace from @s.
336 * @s: The string to be stripped.
337 *
338 * Return pointer to the first non-whitespace character in @s.
339 */
340char *ltrim(char *s)
341{
342 int len = strlen(s);
343
344 while (len && isspace(*s)) {
345 len--;
346 s++;
347 }
348
349 return s;
350}
351
352/**
317 * rtrim - Removes trailing whitespace from @s. 353 * rtrim - Removes trailing whitespace from @s.
318 * @s: The string to be stripped. 354 * @s: The string to be stripped.
319 * 355 *
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index 155d8b7078a7..55433aa42c8f 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -35,11 +35,11 @@ out_delete:
35 return NULL; 35 return NULL;
36} 36}
37 37
38static void str_node__delete(struct str_node *self, bool dupstr) 38static void str_node__delete(struct str_node *snode, bool dupstr)
39{ 39{
40 if (dupstr) 40 if (dupstr)
41 free((void *)self->s); 41 free((void *)snode->s);
42 free(self); 42 free(snode);
43} 43}
44 44
45static 45static
@@ -59,12 +59,12 @@ static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
59 return strcmp(snode->s, str); 59 return strcmp(snode->s, str);
60} 60}
61 61
62int strlist__add(struct strlist *self, const char *new_entry) 62int strlist__add(struct strlist *slist, const char *new_entry)
63{ 63{
64 return rblist__add_node(&self->rblist, new_entry); 64 return rblist__add_node(&slist->rblist, new_entry);
65} 65}
66 66
67int strlist__load(struct strlist *self, const char *filename) 67int strlist__load(struct strlist *slist, const char *filename)
68{ 68{
69 char entry[1024]; 69 char entry[1024];
70 int err; 70 int err;
@@ -80,7 +80,7 @@ int strlist__load(struct strlist *self, const char *filename)
80 continue; 80 continue;
81 entry[len - 1] = '\0'; 81 entry[len - 1] = '\0';
82 82
83 err = strlist__add(self, entry); 83 err = strlist__add(slist, entry);
84 if (err != 0) 84 if (err != 0)
85 goto out; 85 goto out;
86 } 86 }
@@ -107,56 +107,56 @@ struct str_node *strlist__find(struct strlist *slist, const char *entry)
107 return snode; 107 return snode;
108} 108}
109 109
110static int strlist__parse_list_entry(struct strlist *self, const char *s) 110static int strlist__parse_list_entry(struct strlist *slist, const char *s)
111{ 111{
112 if (strncmp(s, "file://", 7) == 0) 112 if (strncmp(s, "file://", 7) == 0)
113 return strlist__load(self, s + 7); 113 return strlist__load(slist, s + 7);
114 114
115 return strlist__add(self, s); 115 return strlist__add(slist, s);
116} 116}
117 117
118int strlist__parse_list(struct strlist *self, const char *s) 118int strlist__parse_list(struct strlist *slist, const char *s)
119{ 119{
120 char *sep; 120 char *sep;
121 int err; 121 int err;
122 122
123 while ((sep = strchr(s, ',')) != NULL) { 123 while ((sep = strchr(s, ',')) != NULL) {
124 *sep = '\0'; 124 *sep = '\0';
125 err = strlist__parse_list_entry(self, s); 125 err = strlist__parse_list_entry(slist, s);
126 *sep = ','; 126 *sep = ',';
127 if (err != 0) 127 if (err != 0)
128 return err; 128 return err;
129 s = sep + 1; 129 s = sep + 1;
130 } 130 }
131 131
132 return *s ? strlist__parse_list_entry(self, s) : 0; 132 return *s ? strlist__parse_list_entry(slist, s) : 0;
133} 133}
134 134
135struct strlist *strlist__new(bool dupstr, const char *slist) 135struct strlist *strlist__new(bool dupstr, const char *list)
136{ 136{
137 struct strlist *self = malloc(sizeof(*self)); 137 struct strlist *slist = malloc(sizeof(*slist));
138 138
139 if (self != NULL) { 139 if (slist != NULL) {
140 rblist__init(&self->rblist); 140 rblist__init(&slist->rblist);
141 self->rblist.node_cmp = strlist__node_cmp; 141 slist->rblist.node_cmp = strlist__node_cmp;
142 self->rblist.node_new = strlist__node_new; 142 slist->rblist.node_new = strlist__node_new;
143 self->rblist.node_delete = strlist__node_delete; 143 slist->rblist.node_delete = strlist__node_delete;
144 144
145 self->dupstr = dupstr; 145 slist->dupstr = dupstr;
146 if (slist && strlist__parse_list(self, slist) != 0) 146 if (slist && strlist__parse_list(slist, list) != 0)
147 goto out_error; 147 goto out_error;
148 } 148 }
149 149
150 return self; 150 return slist;
151out_error: 151out_error:
152 free(self); 152 free(slist);
153 return NULL; 153 return NULL;
154} 154}
155 155
156void strlist__delete(struct strlist *self) 156void strlist__delete(struct strlist *slist)
157{ 157{
158 if (self != NULL) 158 if (slist != NULL)
159 rblist__delete(&self->rblist); 159 rblist__delete(&slist->rblist);
160} 160}
161 161
162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx) 162struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index dd9f922ec67c..5c7f87069d9c 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -17,34 +17,34 @@ struct strlist {
17}; 17};
18 18
19struct strlist *strlist__new(bool dupstr, const char *slist); 19struct strlist *strlist__new(bool dupstr, const char *slist);
20void strlist__delete(struct strlist *self); 20void strlist__delete(struct strlist *slist);
21 21
22void strlist__remove(struct strlist *self, struct str_node *sn); 22void strlist__remove(struct strlist *slist, struct str_node *sn);
23int strlist__load(struct strlist *self, const char *filename); 23int strlist__load(struct strlist *slist, const char *filename);
24int strlist__add(struct strlist *self, const char *str); 24int strlist__add(struct strlist *slist, const char *str);
25 25
26struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); 26struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx);
27struct str_node *strlist__find(struct strlist *self, const char *entry); 27struct str_node *strlist__find(struct strlist *slist, const char *entry);
28 28
29static inline bool strlist__has_entry(struct strlist *self, const char *entry) 29static inline bool strlist__has_entry(struct strlist *slist, const char *entry)
30{ 30{
31 return strlist__find(self, entry) != NULL; 31 return strlist__find(slist, entry) != NULL;
32} 32}
33 33
34static inline bool strlist__empty(const struct strlist *self) 34static inline bool strlist__empty(const struct strlist *slist)
35{ 35{
36 return rblist__empty(&self->rblist); 36 return rblist__empty(&slist->rblist);
37} 37}
38 38
39static inline unsigned int strlist__nr_entries(const struct strlist *self) 39static inline unsigned int strlist__nr_entries(const struct strlist *slist)
40{ 40{
41 return rblist__nr_entries(&self->rblist); 41 return rblist__nr_entries(&slist->rblist);
42} 42}
43 43
44/* For strlist iteration */ 44/* For strlist iteration */
45static inline struct str_node *strlist__first(struct strlist *self) 45static inline struct str_node *strlist__first(struct strlist *slist)
46{ 46{
47 struct rb_node *rn = rb_first(&self->rblist.entries); 47 struct rb_node *rn = rb_first(&slist->rblist.entries);
48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL; 48 return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
49} 49}
50static inline struct str_node *strlist__next(struct str_node *sn) 50static inline struct str_node *strlist__next(struct str_node *sn)
@@ -59,21 +59,21 @@ static inline struct str_node *strlist__next(struct str_node *sn)
59/** 59/**
60 * strlist_for_each - iterate over a strlist 60 * strlist_for_each - iterate over a strlist
61 * @pos: the &struct str_node to use as a loop cursor. 61 * @pos: the &struct str_node to use as a loop cursor.
62 * @self: the &struct strlist for loop. 62 * @slist: the &struct strlist for loop.
63 */ 63 */
64#define strlist__for_each(pos, self) \ 64#define strlist__for_each(pos, slist) \
65 for (pos = strlist__first(self); pos; pos = strlist__next(pos)) 65 for (pos = strlist__first(slist); pos; pos = strlist__next(pos))
66 66
67/** 67/**
68 * strlist_for_each_safe - iterate over a strlist safe against removal of 68 * strlist_for_each_safe - iterate over a strlist safe against removal of
69 * str_node 69 * str_node
70 * @pos: the &struct str_node to use as a loop cursor. 70 * @pos: the &struct str_node to use as a loop cursor.
71 * @n: another &struct str_node to use as temporary storage. 71 * @n: another &struct str_node to use as temporary storage.
72 * @self: the &struct strlist for loop. 72 * @slist: the &struct strlist for loop.
73 */ 73 */
74#define strlist__for_each_safe(pos, n, self) \ 74#define strlist__for_each_safe(pos, n, slist) \
75 for (pos = strlist__first(self), n = strlist__next(pos); pos;\ 75 for (pos = strlist__first(slist), n = strlist__next(pos); pos;\
76 pos = n, n = strlist__next(n)) 76 pos = n, n = strlist__next(n))
77 77
78int strlist__parse_list(struct strlist *self, const char *s); 78int strlist__parse_list(struct strlist *slist, const char *s);
79#endif /* __PERF_STRLIST_H */ 79#endif /* __PERF_STRLIST_H */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index db0cc92cf2ea..54efcb5659ac 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1,6 +1,3 @@
1#include <libelf.h>
2#include <gelf.h>
3#include <elf.h>
4#include <fcntl.h> 1#include <fcntl.h>
5#include <stdio.h> 2#include <stdio.h>
6#include <errno.h> 3#include <errno.h>
@@ -718,6 +715,17 @@ int dso__load_sym(struct dso *dso, struct map *map,
718 sym.st_value); 715 sym.st_value);
719 used_opd = true; 716 used_opd = true;
720 } 717 }
718 /*
719 * When loading symbols in a data mapping, ABS symbols (which
720 * has a value of SHN_ABS in its st_shndx) failed at
721 * elf_getscn(). And it marks the loading as a failure so
722 * already loaded symbols cannot be fixed up.
723 *
724 * I'm not sure what should be done. Just ignore them for now.
725 * - Namhyung Kim
726 */
727 if (sym.st_shndx == SHN_ABS)
728 continue;
721 729
722 sec = elf_getscn(runtime_ss->elf, sym.st_shndx); 730 sec = elf_getscn(runtime_ss->elf, sym.st_shndx);
723 if (!sec) 731 if (!sec)
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 259f8f2ea9c9..a7390cde63bc 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -1,6 +1,5 @@
1#include "symbol.h" 1#include "symbol.h"
2 2
3#include <elf.h>
4#include <stdio.h> 3#include <stdio.h>
5#include <fcntl.h> 4#include <fcntl.h>
6#include <string.h> 5#include <string.h>
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e2e8c697cffe..e6432d85b43d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -12,6 +12,7 @@
12#include "build-id.h" 12#include "build-id.h"
13#include "util.h" 13#include "util.h"
14#include "debug.h" 14#include "debug.h"
15#include "machine.h"
15#include "symbol.h" 16#include "symbol.h"
16#include "strlist.h" 17#include "strlist.h"
17 18
@@ -23,13 +24,12 @@
23#define KSYM_NAME_LEN 256 24#define KSYM_NAME_LEN 256
24#endif 25#endif
25 26
26static void dso_cache__free(struct rb_root *root);
27static int dso__load_kernel_sym(struct dso *dso, struct map *map, 27static int dso__load_kernel_sym(struct dso *dso, struct map *map,
28 symbol_filter_t filter); 28 symbol_filter_t filter);
29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
30 symbol_filter_t filter); 30 symbol_filter_t filter);
31static int vmlinux_path__nr_entries; 31int vmlinux_path__nr_entries;
32static char **vmlinux_path; 32char **vmlinux_path;
33 33
34struct symbol_conf symbol_conf = { 34struct symbol_conf symbol_conf = {
35 .exclude_other = true, 35 .exclude_other = true,
@@ -56,39 +56,6 @@ static enum dso_binary_type binary_type_symtab[] = {
56 56
57#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 57#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
58 58
59static enum dso_binary_type binary_type_data[] = {
60 DSO_BINARY_TYPE__BUILD_ID_CACHE,
61 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
62 DSO_BINARY_TYPE__NOT_FOUND,
63};
64
65#define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
66
67int dso__name_len(const struct dso *dso)
68{
69 if (!dso)
70 return strlen("[unknown]");
71 if (verbose)
72 return dso->long_name_len;
73
74 return dso->short_name_len;
75}
76
77bool dso__loaded(const struct dso *dso, enum map_type type)
78{
79 return dso->loaded & (1 << type);
80}
81
82bool dso__sorted_by_name(const struct dso *dso, enum map_type type)
83{
84 return dso->sorted_by_name & (1 << type);
85}
86
87static void dso__set_sorted_by_name(struct dso *dso, enum map_type type)
88{
89 dso->sorted_by_name |= (1 << type);
90}
91
92bool symbol_type__is_a(char symbol_type, enum map_type map_type) 59bool symbol_type__is_a(char symbol_type, enum map_type map_type)
93{ 60{
94 symbol_type = toupper(symbol_type); 61 symbol_type = toupper(symbol_type);
@@ -235,13 +202,6 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
235 curr->end = ~0ULL; 202 curr->end = ~0ULL;
236} 203}
237 204
238static void map_groups__fixup_end(struct map_groups *mg)
239{
240 int i;
241 for (i = 0; i < MAP__NR_TYPES; ++i)
242 __map_groups__fixup_end(mg, i);
243}
244
245struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 205struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
246{ 206{
247 size_t namelen = strlen(name) + 1; 207 size_t namelen = strlen(name) + 1;
@@ -270,7 +230,7 @@ void symbol__delete(struct symbol *sym)
270 free(((void *)sym) - symbol_conf.priv_size); 230 free(((void *)sym) - symbol_conf.priv_size);
271} 231}
272 232
273static size_t symbol__fprintf(struct symbol *sym, FILE *fp) 233size_t symbol__fprintf(struct symbol *sym, FILE *fp)
274{ 234{
275 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 235 return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n",
276 sym->start, sym->end, 236 sym->start, sym->end,
@@ -301,53 +261,7 @@ size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp)
301 return symbol__fprintf_symname_offs(sym, NULL, fp); 261 return symbol__fprintf_symname_offs(sym, NULL, fp);
302} 262}
303 263
304void dso__set_long_name(struct dso *dso, char *name) 264void symbols__delete(struct rb_root *symbols)
305{
306 if (name == NULL)
307 return;
308 dso->long_name = name;
309 dso->long_name_len = strlen(name);
310}
311
312static void dso__set_short_name(struct dso *dso, const char *name)
313{
314 if (name == NULL)
315 return;
316 dso->short_name = name;
317 dso->short_name_len = strlen(name);
318}
319
320static void dso__set_basename(struct dso *dso)
321{
322 dso__set_short_name(dso, basename(dso->long_name));
323}
324
325struct dso *dso__new(const char *name)
326{
327 struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
328
329 if (dso != NULL) {
330 int i;
331 strcpy(dso->name, name);
332 dso__set_long_name(dso, dso->name);
333 dso__set_short_name(dso, dso->name);
334 for (i = 0; i < MAP__NR_TYPES; ++i)
335 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
336 dso->cache = RB_ROOT;
337 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
338 dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
339 dso->loaded = 0;
340 dso->sorted_by_name = 0;
341 dso->has_build_id = 0;
342 dso->kernel = DSO_TYPE_USER;
343 dso->needs_swap = DSO_SWAP__UNSET;
344 INIT_LIST_HEAD(&dso->node);
345 }
346
347 return dso;
348}
349
350static void symbols__delete(struct rb_root *symbols)
351{ 265{
352 struct symbol *pos; 266 struct symbol *pos;
353 struct rb_node *next = rb_first(symbols); 267 struct rb_node *next = rb_first(symbols);
@@ -360,25 +274,6 @@ static void symbols__delete(struct rb_root *symbols)
360 } 274 }
361} 275}
362 276
363void dso__delete(struct dso *dso)
364{
365 int i;
366 for (i = 0; i < MAP__NR_TYPES; ++i)
367 symbols__delete(&dso->symbols[i]);
368 if (dso->sname_alloc)
369 free((char *)dso->short_name);
370 if (dso->lname_alloc)
371 free(dso->long_name);
372 dso_cache__free(&dso->cache);
373 free(dso);
374}
375
376void dso__set_build_id(struct dso *dso, void *build_id)
377{
378 memcpy(dso->build_id, build_id, sizeof(dso->build_id));
379 dso->has_build_id = 1;
380}
381
382void symbols__insert(struct rb_root *symbols, struct symbol *sym) 277void symbols__insert(struct rb_root *symbols, struct symbol *sym)
383{ 278{
384 struct rb_node **p = &symbols->rb_node; 279 struct rb_node **p = &symbols->rb_node;
@@ -504,29 +399,6 @@ void dso__sort_by_name(struct dso *dso, enum map_type type)
504 &dso->symbols[type]); 399 &dso->symbols[type]);
505} 400}
506 401
507int build_id__sprintf(const u8 *build_id, int len, char *bf)
508{
509 char *bid = bf;
510 const u8 *raw = build_id;
511 int i;
512
513 for (i = 0; i < len; ++i) {
514 sprintf(bid, "%02x", *raw);
515 ++raw;
516 bid += 2;
517 }
518
519 return raw - build_id;
520}
521
522size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
523{
524 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
525
526 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
527 return fprintf(fp, "%s", sbuild_id);
528}
529
530size_t dso__fprintf_symbols_by_name(struct dso *dso, 402size_t dso__fprintf_symbols_by_name(struct dso *dso,
531 enum map_type type, FILE *fp) 403 enum map_type type, FILE *fp)
532{ 404{
@@ -542,25 +414,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso,
542 return ret; 414 return ret;
543} 415}
544 416
545size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
546{
547 struct rb_node *nd;
548 size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
549
550 if (dso->short_name != dso->long_name)
551 ret += fprintf(fp, "%s, ", dso->long_name);
552 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
553 dso->loaded ? "" : "NOT ");
554 ret += dso__fprintf_buildid(dso, fp);
555 ret += fprintf(fp, ")\n");
556 for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) {
557 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
558 ret += symbol__fprintf(pos, fp);
559 }
560
561 return ret;
562}
563
564int kallsyms__parse(const char *filename, void *arg, 417int kallsyms__parse(const char *filename, void *arg,
565 int (*process_symbol)(void *arg, const char *name, 418 int (*process_symbol)(void *arg, const char *name,
566 char type, u64 start)) 419 char type, u64 start))
@@ -792,8 +645,8 @@ discard_symbol: rb_erase(&pos->rb_node, root);
792 return count + moved; 645 return count + moved;
793} 646}
794 647
795static bool symbol__restricted_filename(const char *filename, 648bool symbol__restricted_filename(const char *filename,
796 const char *restricted_filename) 649 const char *restricted_filename)
797{ 650{
798 bool restricted = false; 651 bool restricted = false;
799 652
@@ -892,136 +745,6 @@ out_failure:
892 return -1; 745 return -1;
893} 746}
894 747
895bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
896{
897 return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
898}
899
900bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
901{
902 bool have_build_id = false;
903 struct dso *pos;
904
905 list_for_each_entry(pos, head, node) {
906 if (with_hits && !pos->hit)
907 continue;
908 if (pos->has_build_id) {
909 have_build_id = true;
910 continue;
911 }
912 if (filename__read_build_id(pos->long_name, pos->build_id,
913 sizeof(pos->build_id)) > 0) {
914 have_build_id = true;
915 pos->has_build_id = true;
916 }
917 }
918
919 return have_build_id;
920}
921
922char dso__symtab_origin(const struct dso *dso)
923{
924 static const char origin[] = {
925 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
926 [DSO_BINARY_TYPE__VMLINUX] = 'v',
927 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
928 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
929 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
930 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
931 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
932 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
933 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
934 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
935 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
936 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
937 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
938 };
939
940 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
941 return '!';
942 return origin[dso->symtab_type];
943}
944
945int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
946 char *root_dir, char *file, size_t size)
947{
948 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
949 int ret = 0;
950
951 switch (type) {
952 case DSO_BINARY_TYPE__DEBUGLINK: {
953 char *debuglink;
954
955 strncpy(file, dso->long_name, size);
956 debuglink = file + dso->long_name_len;
957 while (debuglink != file && *debuglink != '/')
958 debuglink--;
959 if (*debuglink == '/')
960 debuglink++;
961 filename__read_debuglink(dso->long_name, debuglink,
962 size - (debuglink - file));
963 }
964 break;
965 case DSO_BINARY_TYPE__BUILD_ID_CACHE:
966 /* skip the locally configured cache if a symfs is given */
967 if (symbol_conf.symfs[0] ||
968 (dso__build_id_filename(dso, file, size) == NULL))
969 ret = -1;
970 break;
971
972 case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
973 snprintf(file, size, "%s/usr/lib/debug%s.debug",
974 symbol_conf.symfs, dso->long_name);
975 break;
976
977 case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
978 snprintf(file, size, "%s/usr/lib/debug%s",
979 symbol_conf.symfs, dso->long_name);
980 break;
981
982 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
983 if (!dso->has_build_id) {
984 ret = -1;
985 break;
986 }
987
988 build_id__sprintf(dso->build_id,
989 sizeof(dso->build_id),
990 build_id_hex);
991 snprintf(file, size,
992 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
993 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
994 break;
995
996 case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
997 snprintf(file, size, "%s%s",
998 symbol_conf.symfs, dso->long_name);
999 break;
1000
1001 case DSO_BINARY_TYPE__GUEST_KMODULE:
1002 snprintf(file, size, "%s%s%s", symbol_conf.symfs,
1003 root_dir, dso->long_name);
1004 break;
1005
1006 case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1007 snprintf(file, size, "%s%s", symbol_conf.symfs,
1008 dso->long_name);
1009 break;
1010
1011 default:
1012 case DSO_BINARY_TYPE__KALLSYMS:
1013 case DSO_BINARY_TYPE__VMLINUX:
1014 case DSO_BINARY_TYPE__GUEST_KALLSYMS:
1015 case DSO_BINARY_TYPE__GUEST_VMLINUX:
1016 case DSO_BINARY_TYPE__JAVA_JIT:
1017 case DSO_BINARY_TYPE__NOT_FOUND:
1018 ret = -1;
1019 break;
1020 }
1021
1022 return ret;
1023}
1024
1025int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 748int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1026{ 749{
1027 char *name; 750 char *name;
@@ -1045,10 +768,6 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1045 else 768 else
1046 machine = NULL; 769 machine = NULL;
1047 770
1048 name = malloc(PATH_MAX);
1049 if (!name)
1050 return -1;
1051
1052 dso->adjust_symbols = 0; 771 dso->adjust_symbols = 0;
1053 772
1054 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 773 if (strncmp(dso->name, "/tmp/perf-", 10) == 0) {
@@ -1072,6 +791,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1072 if (machine) 791 if (machine)
1073 root_dir = machine->root_dir; 792 root_dir = machine->root_dir;
1074 793
794 name = malloc(PATH_MAX);
795 if (!name)
796 return -1;
797
1075 /* Iterate over candidate debug images. 798 /* Iterate over candidate debug images.
1076 * Keep track of "interesting" ones (those which have a symtab, dynsym, 799 * Keep track of "interesting" ones (those which have a symtab, dynsym,
1077 * and/or opd section) for processing. 800 * and/or opd section) for processing.
@@ -1157,221 +880,6 @@ struct map *map_groups__find_by_name(struct map_groups *mg,
1157 return NULL; 880 return NULL;
1158} 881}
1159 882
1160static int dso__kernel_module_get_build_id(struct dso *dso,
1161 const char *root_dir)
1162{
1163 char filename[PATH_MAX];
1164 /*
1165 * kernel module short names are of the form "[module]" and
1166 * we need just "module" here.
1167 */
1168 const char *name = dso->short_name + 1;
1169
1170 snprintf(filename, sizeof(filename),
1171 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1172 root_dir, (int)strlen(name) - 1, name);
1173
1174 if (sysfs__read_build_id(filename, dso->build_id,
1175 sizeof(dso->build_id)) == 0)
1176 dso->has_build_id = true;
1177
1178 return 0;
1179}
1180
1181static int map_groups__set_modules_path_dir(struct map_groups *mg,
1182 const char *dir_name)
1183{
1184 struct dirent *dent;
1185 DIR *dir = opendir(dir_name);
1186 int ret = 0;
1187
1188 if (!dir) {
1189 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1190 return -1;
1191 }
1192
1193 while ((dent = readdir(dir)) != NULL) {
1194 char path[PATH_MAX];
1195 struct stat st;
1196
1197 /*sshfs might return bad dent->d_type, so we have to stat*/
1198 snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name);
1199 if (stat(path, &st))
1200 continue;
1201
1202 if (S_ISDIR(st.st_mode)) {
1203 if (!strcmp(dent->d_name, ".") ||
1204 !strcmp(dent->d_name, ".."))
1205 continue;
1206
1207 ret = map_groups__set_modules_path_dir(mg, path);
1208 if (ret < 0)
1209 goto out;
1210 } else {
1211 char *dot = strrchr(dent->d_name, '.'),
1212 dso_name[PATH_MAX];
1213 struct map *map;
1214 char *long_name;
1215
1216 if (dot == NULL || strcmp(dot, ".ko"))
1217 continue;
1218 snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1219 (int)(dot - dent->d_name), dent->d_name);
1220
1221 strxfrchar(dso_name, '-', '_');
1222 map = map_groups__find_by_name(mg, MAP__FUNCTION,
1223 dso_name);
1224 if (map == NULL)
1225 continue;
1226
1227 long_name = strdup(path);
1228 if (long_name == NULL) {
1229 ret = -1;
1230 goto out;
1231 }
1232 dso__set_long_name(map->dso, long_name);
1233 map->dso->lname_alloc = 1;
1234 dso__kernel_module_get_build_id(map->dso, "");
1235 }
1236 }
1237
1238out:
1239 closedir(dir);
1240 return ret;
1241}
1242
1243static char *get_kernel_version(const char *root_dir)
1244{
1245 char version[PATH_MAX];
1246 FILE *file;
1247 char *name, *tmp;
1248 const char *prefix = "Linux version ";
1249
1250 sprintf(version, "%s/proc/version", root_dir);
1251 file = fopen(version, "r");
1252 if (!file)
1253 return NULL;
1254
1255 version[0] = '\0';
1256 tmp = fgets(version, sizeof(version), file);
1257 fclose(file);
1258
1259 name = strstr(version, prefix);
1260 if (!name)
1261 return NULL;
1262 name += strlen(prefix);
1263 tmp = strchr(name, ' ');
1264 if (tmp)
1265 *tmp = '\0';
1266
1267 return strdup(name);
1268}
1269
1270static int machine__set_modules_path(struct machine *machine)
1271{
1272 char *version;
1273 char modules_path[PATH_MAX];
1274
1275 version = get_kernel_version(machine->root_dir);
1276 if (!version)
1277 return -1;
1278
1279 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1280 machine->root_dir, version);
1281 free(version);
1282
1283 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
1284}
1285
1286struct map *machine__new_module(struct machine *machine, u64 start,
1287 const char *filename)
1288{
1289 struct map *map;
1290 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
1291
1292 if (dso == NULL)
1293 return NULL;
1294
1295 map = map__new2(start, dso, MAP__FUNCTION);
1296 if (map == NULL)
1297 return NULL;
1298
1299 if (machine__is_host(machine))
1300 dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
1301 else
1302 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
1303 map_groups__insert(&machine->kmaps, map);
1304 return map;
1305}
1306
1307static int machine__create_modules(struct machine *machine)
1308{
1309 char *line = NULL;
1310 size_t n;
1311 FILE *file;
1312 struct map *map;
1313 const char *modules;
1314 char path[PATH_MAX];
1315
1316 if (machine__is_default_guest(machine))
1317 modules = symbol_conf.default_guest_modules;
1318 else {
1319 sprintf(path, "%s/proc/modules", machine->root_dir);
1320 modules = path;
1321 }
1322
1323 if (symbol__restricted_filename(path, "/proc/modules"))
1324 return -1;
1325
1326 file = fopen(modules, "r");
1327 if (file == NULL)
1328 return -1;
1329
1330 while (!feof(file)) {
1331 char name[PATH_MAX];
1332 u64 start;
1333 char *sep;
1334 int line_len;
1335
1336 line_len = getline(&line, &n, file);
1337 if (line_len < 0)
1338 break;
1339
1340 if (!line)
1341 goto out_failure;
1342
1343 line[--line_len] = '\0'; /* \n */
1344
1345 sep = strrchr(line, 'x');
1346 if (sep == NULL)
1347 continue;
1348
1349 hex2u64(sep + 1, &start);
1350
1351 sep = strchr(line, ' ');
1352 if (sep == NULL)
1353 continue;
1354
1355 *sep = '\0';
1356
1357 snprintf(name, sizeof(name), "[%s]", line);
1358 map = machine__new_module(machine, start, name);
1359 if (map == NULL)
1360 goto out_delete_line;
1361 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
1362 }
1363
1364 free(line);
1365 fclose(file);
1366
1367 return machine__set_modules_path(machine);
1368
1369out_delete_line:
1370 free(line);
1371out_failure:
1372 return -1;
1373}
1374
1375int dso__load_vmlinux(struct dso *dso, struct map *map, 883int dso__load_vmlinux(struct dso *dso, struct map *map,
1376 const char *vmlinux, symbol_filter_t filter) 884 const char *vmlinux, symbol_filter_t filter)
1377{ 885{
@@ -1415,8 +923,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1415 filename = dso__build_id_filename(dso, NULL, 0); 923 filename = dso__build_id_filename(dso, NULL, 0);
1416 if (filename != NULL) { 924 if (filename != NULL) {
1417 err = dso__load_vmlinux(dso, map, filename, filter); 925 err = dso__load_vmlinux(dso, map, filename, filter);
1418 if (err > 0) 926 if (err > 0) {
927 dso->lname_alloc = 1;
1419 goto out; 928 goto out;
929 }
1420 free(filename); 930 free(filename);
1421 } 931 }
1422 932
@@ -1424,6 +934,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
1424 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 934 err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter);
1425 if (err > 0) { 935 if (err > 0) {
1426 dso__set_long_name(dso, strdup(vmlinux_path[i])); 936 dso__set_long_name(dso, strdup(vmlinux_path[i]));
937 dso->lname_alloc = 1;
1427 break; 938 break;
1428 } 939 }
1429 } 940 }
@@ -1463,6 +974,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1463 if (err > 0) { 974 if (err > 0) {
1464 dso__set_long_name(dso, 975 dso__set_long_name(dso,
1465 strdup(symbol_conf.vmlinux_name)); 976 strdup(symbol_conf.vmlinux_name));
977 dso->lname_alloc = 1;
1466 goto out_fixup; 978 goto out_fixup;
1467 } 979 }
1468 return err; 980 return err;
@@ -1591,287 +1103,6 @@ out_try_fixup:
1591 return err; 1103 return err;
1592} 1104}
1593 1105
1594void dsos__add(struct list_head *head, struct dso *dso)
1595{
1596 list_add_tail(&dso->node, head);
1597}
1598
1599struct dso *dsos__find(struct list_head *head, const char *name)
1600{
1601 struct dso *pos;
1602
1603 list_for_each_entry(pos, head, node)
1604 if (strcmp(pos->long_name, name) == 0)
1605 return pos;
1606 return NULL;
1607}
1608
1609struct dso *__dsos__findnew(struct list_head *head, const char *name)
1610{
1611 struct dso *dso = dsos__find(head, name);
1612
1613 if (!dso) {
1614 dso = dso__new(name);
1615 if (dso != NULL) {
1616 dsos__add(head, dso);
1617 dso__set_basename(dso);
1618 }
1619 }
1620
1621 return dso;
1622}
1623
1624size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1625{
1626 struct dso *pos;
1627 size_t ret = 0;
1628
1629 list_for_each_entry(pos, head, node) {
1630 int i;
1631 for (i = 0; i < MAP__NR_TYPES; ++i)
1632 ret += dso__fprintf(pos, i, fp);
1633 }
1634
1635 return ret;
1636}
1637
1638size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp)
1639{
1640 struct rb_node *nd;
1641 size_t ret = 0;
1642
1643 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
1644 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1645 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
1646 ret += __dsos__fprintf(&pos->user_dsos, fp);
1647 }
1648
1649 return ret;
1650}
1651
1652static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1653 bool with_hits)
1654{
1655 struct dso *pos;
1656 size_t ret = 0;
1657
1658 list_for_each_entry(pos, head, node) {
1659 if (with_hits && !pos->hit)
1660 continue;
1661 ret += dso__fprintf_buildid(pos, fp);
1662 ret += fprintf(fp, " %s\n", pos->long_name);
1663 }
1664 return ret;
1665}
1666
1667size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp,
1668 bool with_hits)
1669{
1670 return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) +
1671 __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits);
1672}
1673
1674size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
1675 FILE *fp, bool with_hits)
1676{
1677 struct rb_node *nd;
1678 size_t ret = 0;
1679
1680 for (nd = rb_first(machines); nd; nd = rb_next(nd)) {
1681 struct machine *pos = rb_entry(nd, struct machine, rb_node);
1682 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
1683 }
1684 return ret;
1685}
1686
1687static struct dso*
1688dso__kernel_findnew(struct machine *machine, const char *name,
1689 const char *short_name, int dso_type)
1690{
1691 /*
1692 * The kernel dso could be created by build_id processing.
1693 */
1694 struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name);
1695
1696 /*
1697 * We need to run this in all cases, since during the build_id
1698 * processing we had no idea this was the kernel dso.
1699 */
1700 if (dso != NULL) {
1701 dso__set_short_name(dso, short_name);
1702 dso->kernel = dso_type;
1703 }
1704
1705 return dso;
1706}
1707
1708void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
1709{
1710 char path[PATH_MAX];
1711
1712 if (machine__is_default_guest(machine))
1713 return;
1714 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
1715 if (sysfs__read_build_id(path, dso->build_id,
1716 sizeof(dso->build_id)) == 0)
1717 dso->has_build_id = true;
1718}
1719
1720static struct dso *machine__get_kernel(struct machine *machine)
1721{
1722 const char *vmlinux_name = NULL;
1723 struct dso *kernel;
1724
1725 if (machine__is_host(machine)) {
1726 vmlinux_name = symbol_conf.vmlinux_name;
1727 if (!vmlinux_name)
1728 vmlinux_name = "[kernel.kallsyms]";
1729
1730 kernel = dso__kernel_findnew(machine, vmlinux_name,
1731 "[kernel]",
1732 DSO_TYPE_KERNEL);
1733 } else {
1734 char bf[PATH_MAX];
1735
1736 if (machine__is_default_guest(machine))
1737 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
1738 if (!vmlinux_name)
1739 vmlinux_name = machine__mmap_name(machine, bf,
1740 sizeof(bf));
1741
1742 kernel = dso__kernel_findnew(machine, vmlinux_name,
1743 "[guest.kernel]",
1744 DSO_TYPE_GUEST_KERNEL);
1745 }
1746
1747 if (kernel != NULL && (!kernel->has_build_id))
1748 dso__read_running_kernel_build_id(kernel, machine);
1749
1750 return kernel;
1751}
1752
1753struct process_args {
1754 u64 start;
1755};
1756
1757static int symbol__in_kernel(void *arg, const char *name,
1758 char type __maybe_unused, u64 start)
1759{
1760 struct process_args *args = arg;
1761
1762 if (strchr(name, '['))
1763 return 0;
1764
1765 args->start = start;
1766 return 1;
1767}
1768
1769/* Figure out the start address of kernel map from /proc/kallsyms */
1770static u64 machine__get_kernel_start_addr(struct machine *machine)
1771{
1772 const char *filename;
1773 char path[PATH_MAX];
1774 struct process_args args;
1775
1776 if (machine__is_host(machine)) {
1777 filename = "/proc/kallsyms";
1778 } else {
1779 if (machine__is_default_guest(machine))
1780 filename = (char *)symbol_conf.default_guest_kallsyms;
1781 else {
1782 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1783 filename = path;
1784 }
1785 }
1786
1787 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1788 return 0;
1789
1790 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
1791 return 0;
1792
1793 return args.start;
1794}
1795
1796int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
1797{
1798 enum map_type type;
1799 u64 start = machine__get_kernel_start_addr(machine);
1800
1801 for (type = 0; type < MAP__NR_TYPES; ++type) {
1802 struct kmap *kmap;
1803
1804 machine->vmlinux_maps[type] = map__new2(start, kernel, type);
1805 if (machine->vmlinux_maps[type] == NULL)
1806 return -1;
1807
1808 machine->vmlinux_maps[type]->map_ip =
1809 machine->vmlinux_maps[type]->unmap_ip =
1810 identity__map_ip;
1811 kmap = map__kmap(machine->vmlinux_maps[type]);
1812 kmap->kmaps = &machine->kmaps;
1813 map_groups__insert(&machine->kmaps,
1814 machine->vmlinux_maps[type]);
1815 }
1816
1817 return 0;
1818}
1819
1820void machine__destroy_kernel_maps(struct machine *machine)
1821{
1822 enum map_type type;
1823
1824 for (type = 0; type < MAP__NR_TYPES; ++type) {
1825 struct kmap *kmap;
1826
1827 if (machine->vmlinux_maps[type] == NULL)
1828 continue;
1829
1830 kmap = map__kmap(machine->vmlinux_maps[type]);
1831 map_groups__remove(&machine->kmaps,
1832 machine->vmlinux_maps[type]);
1833 if (kmap->ref_reloc_sym) {
1834 /*
1835 * ref_reloc_sym is shared among all maps, so free just
1836 * on one of them.
1837 */
1838 if (type == MAP__FUNCTION) {
1839 free((char *)kmap->ref_reloc_sym->name);
1840 kmap->ref_reloc_sym->name = NULL;
1841 free(kmap->ref_reloc_sym);
1842 }
1843 kmap->ref_reloc_sym = NULL;
1844 }
1845
1846 map__delete(machine->vmlinux_maps[type]);
1847 machine->vmlinux_maps[type] = NULL;
1848 }
1849}
1850
1851int machine__create_kernel_maps(struct machine *machine)
1852{
1853 struct dso *kernel = machine__get_kernel(machine);
1854
1855 if (kernel == NULL ||
1856 __machine__create_kernel_maps(machine, kernel) < 0)
1857 return -1;
1858
1859 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
1860 if (machine__is_host(machine))
1861 pr_debug("Problems creating module maps, "
1862 "continuing anyway...\n");
1863 else
1864 pr_debug("Problems creating module maps for guest %d, "
1865 "continuing anyway...\n", machine->pid);
1866 }
1867
1868 /*
1869 * Now that we have all the maps created, just set the ->end of them:
1870 */
1871 map_groups__fixup_end(&machine->kmaps);
1872 return 0;
1873}
1874
1875static void vmlinux_path__exit(void) 1106static void vmlinux_path__exit(void)
1876{ 1107{
1877 while (--vmlinux_path__nr_entries >= 0) { 1108 while (--vmlinux_path__nr_entries >= 0) {
@@ -1932,25 +1163,6 @@ out_fail:
1932 return -1; 1163 return -1;
1933} 1164}
1934 1165
1935size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)
1936{
1937 int i;
1938 size_t printed = 0;
1939 struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso;
1940
1941 if (kdso->has_build_id) {
1942 char filename[PATH_MAX];
1943 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
1944 printed += fprintf(fp, "[0] %s\n", filename);
1945 }
1946
1947 for (i = 0; i < vmlinux_path__nr_entries; ++i)
1948 printed += fprintf(fp, "[%d] %s\n",
1949 i + kdso->has_build_id, vmlinux_path[i]);
1950
1951 return printed;
1952}
1953
1954static int setup_list(struct strlist **list, const char *list_str, 1166static int setup_list(struct strlist **list, const char *list_str,
1955 const char *list_name) 1167 const char *list_name)
1956{ 1168{
@@ -2054,377 +1266,3 @@ void symbol__exit(void)
2054 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 1266 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
2055 symbol_conf.initialized = false; 1267 symbol_conf.initialized = false;
2056} 1268}
2057
2058int machines__create_kernel_maps(struct rb_root *machines, pid_t pid)
2059{
2060 struct machine *machine = machines__findnew(machines, pid);
2061
2062 if (machine == NULL)
2063 return -1;
2064
2065 return machine__create_kernel_maps(machine);
2066}
2067
2068static int hex(char ch)
2069{
2070 if ((ch >= '0') && (ch <= '9'))
2071 return ch - '0';
2072 if ((ch >= 'a') && (ch <= 'f'))
2073 return ch - 'a' + 10;
2074 if ((ch >= 'A') && (ch <= 'F'))
2075 return ch - 'A' + 10;
2076 return -1;
2077}
2078
2079/*
2080 * While we find nice hex chars, build a long_val.
2081 * Return number of chars processed.
2082 */
2083int hex2u64(const char *ptr, u64 *long_val)
2084{
2085 const char *p = ptr;
2086 *long_val = 0;
2087
2088 while (*p) {
2089 const int hex_val = hex(*p);
2090
2091 if (hex_val < 0)
2092 break;
2093
2094 *long_val = (*long_val << 4) | hex_val;
2095 p++;
2096 }
2097
2098 return p - ptr;
2099}
2100
2101char *strxfrchar(char *s, char from, char to)
2102{
2103 char *p = s;
2104
2105 while ((p = strchr(p, from)) != NULL)
2106 *p++ = to;
2107
2108 return s;
2109}
2110
2111int machines__create_guest_kernel_maps(struct rb_root *machines)
2112{
2113 int ret = 0;
2114 struct dirent **namelist = NULL;
2115 int i, items = 0;
2116 char path[PATH_MAX];
2117 pid_t pid;
2118 char *endp;
2119
2120 if (symbol_conf.default_guest_vmlinux_name ||
2121 symbol_conf.default_guest_modules ||
2122 symbol_conf.default_guest_kallsyms) {
2123 machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID);
2124 }
2125
2126 if (symbol_conf.guestmount) {
2127 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2128 if (items <= 0)
2129 return -ENOENT;
2130 for (i = 0; i < items; i++) {
2131 if (!isdigit(namelist[i]->d_name[0])) {
2132 /* Filter out . and .. */
2133 continue;
2134 }
2135 pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10);
2136 if ((*endp != '\0') ||
2137 (endp == namelist[i]->d_name) ||
2138 (errno == ERANGE)) {
2139 pr_debug("invalid directory (%s). Skipping.\n",
2140 namelist[i]->d_name);
2141 continue;
2142 }
2143 sprintf(path, "%s/%s/proc/kallsyms",
2144 symbol_conf.guestmount,
2145 namelist[i]->d_name);
2146 ret = access(path, R_OK);
2147 if (ret) {
2148 pr_debug("Can't access file %s\n", path);
2149 goto failure;
2150 }
2151 machines__create_kernel_maps(machines, pid);
2152 }
2153failure:
2154 free(namelist);
2155 }
2156
2157 return ret;
2158}
2159
2160void machines__destroy_guest_kernel_maps(struct rb_root *machines)
2161{
2162 struct rb_node *next = rb_first(machines);
2163
2164 while (next) {
2165 struct machine *pos = rb_entry(next, struct machine, rb_node);
2166
2167 next = rb_next(&pos->rb_node);
2168 rb_erase(&pos->rb_node, machines);
2169 machine__delete(pos);
2170 }
2171}
2172
2173int machine__load_kallsyms(struct machine *machine, const char *filename,
2174 enum map_type type, symbol_filter_t filter)
2175{
2176 struct map *map = machine->vmlinux_maps[type];
2177 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
2178
2179 if (ret > 0) {
2180 dso__set_loaded(map->dso, type);
2181 /*
2182 * Since /proc/kallsyms will have multiple sessions for the
2183 * kernel, with modules between them, fixup the end of all
2184 * sections.
2185 */
2186 __map_groups__fixup_end(&machine->kmaps, type);
2187 }
2188
2189 return ret;
2190}
2191
2192int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
2193 symbol_filter_t filter)
2194{
2195 struct map *map = machine->vmlinux_maps[type];
2196 int ret = dso__load_vmlinux_path(map->dso, map, filter);
2197
2198 if (ret > 0) {
2199 dso__set_loaded(map->dso, type);
2200 map__reloc_vmlinux(map);
2201 }
2202
2203 return ret;
2204}
2205
2206struct map *dso__new_map(const char *name)
2207{
2208 struct map *map = NULL;
2209 struct dso *dso = dso__new(name);
2210
2211 if (dso)
2212 map = map__new2(0, dso, MAP__FUNCTION);
2213
2214 return map;
2215}
2216
2217static int open_dso(struct dso *dso, struct machine *machine)
2218{
2219 char *root_dir = (char *) "";
2220 char *name;
2221 int fd;
2222
2223 name = malloc(PATH_MAX);
2224 if (!name)
2225 return -ENOMEM;
2226
2227 if (machine)
2228 root_dir = machine->root_dir;
2229
2230 if (dso__binary_type_file(dso, dso->data_type,
2231 root_dir, name, PATH_MAX)) {
2232 free(name);
2233 return -EINVAL;
2234 }
2235
2236 fd = open(name, O_RDONLY);
2237 free(name);
2238 return fd;
2239}
2240
2241int dso__data_fd(struct dso *dso, struct machine *machine)
2242{
2243 int i = 0;
2244
2245 if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND)
2246 return open_dso(dso, machine);
2247
2248 do {
2249 int fd;
2250
2251 dso->data_type = binary_type_data[i++];
2252
2253 fd = open_dso(dso, machine);
2254 if (fd >= 0)
2255 return fd;
2256
2257 } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND);
2258
2259 return -EINVAL;
2260}
2261
2262static void
2263dso_cache__free(struct rb_root *root)
2264{
2265 struct rb_node *next = rb_first(root);
2266
2267 while (next) {
2268 struct dso_cache *cache;
2269
2270 cache = rb_entry(next, struct dso_cache, rb_node);
2271 next = rb_next(&cache->rb_node);
2272 rb_erase(&cache->rb_node, root);
2273 free(cache);
2274 }
2275}
2276
2277static struct dso_cache*
2278dso_cache__find(struct rb_root *root, u64 offset)
2279{
2280 struct rb_node **p = &root->rb_node;
2281 struct rb_node *parent = NULL;
2282 struct dso_cache *cache;
2283
2284 while (*p != NULL) {
2285 u64 end;
2286
2287 parent = *p;
2288 cache = rb_entry(parent, struct dso_cache, rb_node);
2289 end = cache->offset + DSO__DATA_CACHE_SIZE;
2290
2291 if (offset < cache->offset)
2292 p = &(*p)->rb_left;
2293 else if (offset >= end)
2294 p = &(*p)->rb_right;
2295 else
2296 return cache;
2297 }
2298 return NULL;
2299}
2300
2301static void
2302dso_cache__insert(struct rb_root *root, struct dso_cache *new)
2303{
2304 struct rb_node **p = &root->rb_node;
2305 struct rb_node *parent = NULL;
2306 struct dso_cache *cache;
2307 u64 offset = new->offset;
2308
2309 while (*p != NULL) {
2310 u64 end;
2311
2312 parent = *p;
2313 cache = rb_entry(parent, struct dso_cache, rb_node);
2314 end = cache->offset + DSO__DATA_CACHE_SIZE;
2315
2316 if (offset < cache->offset)
2317 p = &(*p)->rb_left;
2318 else if (offset >= end)
2319 p = &(*p)->rb_right;
2320 }
2321
2322 rb_link_node(&new->rb_node, parent, p);
2323 rb_insert_color(&new->rb_node, root);
2324}
2325
2326static ssize_t
2327dso_cache__memcpy(struct dso_cache *cache, u64 offset,
2328 u8 *data, u64 size)
2329{
2330 u64 cache_offset = offset - cache->offset;
2331 u64 cache_size = min(cache->size - cache_offset, size);
2332
2333 memcpy(data, cache->data + cache_offset, cache_size);
2334 return cache_size;
2335}
2336
2337static ssize_t
2338dso_cache__read(struct dso *dso, struct machine *machine,
2339 u64 offset, u8 *data, ssize_t size)
2340{
2341 struct dso_cache *cache;
2342 ssize_t ret;
2343 int fd;
2344
2345 fd = dso__data_fd(dso, machine);
2346 if (fd < 0)
2347 return -1;
2348
2349 do {
2350 u64 cache_offset;
2351
2352 ret = -ENOMEM;
2353
2354 cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
2355 if (!cache)
2356 break;
2357
2358 cache_offset = offset & DSO__DATA_CACHE_MASK;
2359 ret = -EINVAL;
2360
2361 if (-1 == lseek(fd, cache_offset, SEEK_SET))
2362 break;
2363
2364 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE);
2365 if (ret <= 0)
2366 break;
2367
2368 cache->offset = cache_offset;
2369 cache->size = ret;
2370 dso_cache__insert(&dso->cache, cache);
2371
2372 ret = dso_cache__memcpy(cache, offset, data, size);
2373
2374 } while (0);
2375
2376 if (ret <= 0)
2377 free(cache);
2378
2379 close(fd);
2380 return ret;
2381}
2382
2383static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
2384 u64 offset, u8 *data, ssize_t size)
2385{
2386 struct dso_cache *cache;
2387
2388 cache = dso_cache__find(&dso->cache, offset);
2389 if (cache)
2390 return dso_cache__memcpy(cache, offset, data, size);
2391 else
2392 return dso_cache__read(dso, machine, offset, data, size);
2393}
2394
2395ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
2396 u64 offset, u8 *data, ssize_t size)
2397{
2398 ssize_t r = 0;
2399 u8 *p = data;
2400
2401 do {
2402 ssize_t ret;
2403
2404 ret = dso_cache_read(dso, machine, offset, p, size);
2405 if (ret < 0)
2406 return ret;
2407
2408 /* Reached EOF, return what we have. */
2409 if (!ret)
2410 break;
2411
2412 BUG_ON(ret > size);
2413
2414 r += ret;
2415 p += ret;
2416 offset += ret;
2417 size -= ret;
2418
2419 } while (size);
2420
2421 return r;
2422}
2423
2424ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
2425 struct machine *machine, u64 addr,
2426 u8 *data, ssize_t size)
2427{
2428 u64 offset = map->map_ip(map, addr);
2429 return dso__data_read_offset(dso, machine, offset, data, size);
2430}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8b6ef7fac745..b62ca37c4b77 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -11,12 +11,15 @@
11#include <stdio.h> 11#include <stdio.h>
12#include <byteswap.h> 12#include <byteswap.h>
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h"
14 15
15#ifdef LIBELF_SUPPORT 16#ifdef LIBELF_SUPPORT
16#include <libelf.h> 17#include <libelf.h>
17#include <gelf.h> 18#include <gelf.h>
18#include <elf.h>
19#endif 19#endif
20#include <elf.h>
21
22#include "dso.h"
20 23
21#ifdef HAVE_CPLUS_DEMANGLE 24#ifdef HAVE_CPLUS_DEMANGLE
22extern char *cplus_demangle(const char *, int); 25extern char *cplus_demangle(const char *, int);
@@ -39,9 +42,6 @@ static inline char *bfd_demangle(void __maybe_unused *v,
39#endif 42#endif
40#endif 43#endif
41 44
42int hex2u64(const char *ptr, u64 *val);
43char *strxfrchar(char *s, char from, char to);
44
45/* 45/*
46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; 46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
47 * for newer versions we can use mmap to reduce memory usage: 47 * for newer versions we can use mmap to reduce memory usage:
@@ -57,8 +57,6 @@ char *strxfrchar(char *s, char from, char to);
57#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 57#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
58#endif 58#endif
59 59
60#define BUILD_ID_SIZE 20
61
62/** struct symbol - symtab entry 60/** struct symbol - symtab entry
63 * 61 *
64 * @ignore - resolvable but tools ignore it (e.g. idle routines) 62 * @ignore - resolvable but tools ignore it (e.g. idle routines)
@@ -74,6 +72,7 @@ struct symbol {
74}; 72};
75 73
76void symbol__delete(struct symbol *sym); 74void symbol__delete(struct symbol *sym);
75void symbols__delete(struct rb_root *symbols);
77 76
78static inline size_t symbol__size(const struct symbol *sym) 77static inline size_t symbol__size(const struct symbol *sym)
79{ 78{
@@ -97,7 +96,8 @@ struct symbol_conf {
97 initialized, 96 initialized,
98 kptr_restrict, 97 kptr_restrict,
99 annotate_asm_raw, 98 annotate_asm_raw,
100 annotate_src; 99 annotate_src,
100 event_group;
101 const char *vmlinux_name, 101 const char *vmlinux_name,
102 *kallsyms_name, 102 *kallsyms_name,
103 *source_prefix, 103 *source_prefix,
@@ -121,6 +121,8 @@ struct symbol_conf {
121}; 121};
122 122
123extern struct symbol_conf symbol_conf; 123extern struct symbol_conf symbol_conf;
124extern int vmlinux_path__nr_entries;
125extern char **vmlinux_path;
124 126
125static inline void *symbol__priv(struct symbol *sym) 127static inline void *symbol__priv(struct symbol *sym)
126{ 128{
@@ -164,70 +166,6 @@ struct addr_location {
164 s32 cpu; 166 s32 cpu;
165}; 167};
166 168
167enum dso_binary_type {
168 DSO_BINARY_TYPE__KALLSYMS = 0,
169 DSO_BINARY_TYPE__GUEST_KALLSYMS,
170 DSO_BINARY_TYPE__VMLINUX,
171 DSO_BINARY_TYPE__GUEST_VMLINUX,
172 DSO_BINARY_TYPE__JAVA_JIT,
173 DSO_BINARY_TYPE__DEBUGLINK,
174 DSO_BINARY_TYPE__BUILD_ID_CACHE,
175 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
176 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
177 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
178 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
179 DSO_BINARY_TYPE__GUEST_KMODULE,
180 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
181 DSO_BINARY_TYPE__NOT_FOUND,
182};
183
184enum dso_kernel_type {
185 DSO_TYPE_USER = 0,
186 DSO_TYPE_KERNEL,
187 DSO_TYPE_GUEST_KERNEL
188};
189
190enum dso_swap_type {
191 DSO_SWAP__UNSET,
192 DSO_SWAP__NO,
193 DSO_SWAP__YES,
194};
195
196#define DSO__DATA_CACHE_SIZE 4096
197#define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1)
198
199struct dso_cache {
200 struct rb_node rb_node;
201 u64 offset;
202 u64 size;
203 char data[0];
204};
205
206struct dso {
207 struct list_head node;
208 struct rb_root symbols[MAP__NR_TYPES];
209 struct rb_root symbol_names[MAP__NR_TYPES];
210 struct rb_root cache;
211 enum dso_kernel_type kernel;
212 enum dso_swap_type needs_swap;
213 enum dso_binary_type symtab_type;
214 enum dso_binary_type data_type;
215 u8 adjust_symbols:1;
216 u8 has_build_id:1;
217 u8 hit:1;
218 u8 annotate_warned:1;
219 u8 sname_alloc:1;
220 u8 lname_alloc:1;
221 u8 sorted_by_name;
222 u8 loaded;
223 u8 build_id[BUILD_ID_SIZE];
224 const char *short_name;
225 char *long_name;
226 u16 long_name_len;
227 u16 short_name_len;
228 char name[0];
229};
230
231struct symsrc { 169struct symsrc {
232 char *name; 170 char *name;
233 int fd; 171 int fd;
@@ -258,47 +196,6 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
258bool symsrc__has_symtab(struct symsrc *ss); 196bool symsrc__has_symtab(struct symsrc *ss);
259bool symsrc__possibly_runtime(struct symsrc *ss); 197bool symsrc__possibly_runtime(struct symsrc *ss);
260 198
261#define DSO__SWAP(dso, type, val) \
262({ \
263 type ____r = val; \
264 BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \
265 if (dso->needs_swap == DSO_SWAP__YES) { \
266 switch (sizeof(____r)) { \
267 case 2: \
268 ____r = bswap_16(val); \
269 break; \
270 case 4: \
271 ____r = bswap_32(val); \
272 break; \
273 case 8: \
274 ____r = bswap_64(val); \
275 break; \
276 default: \
277 BUG_ON(1); \
278 } \
279 } \
280 ____r; \
281})
282
283struct dso *dso__new(const char *name);
284void dso__delete(struct dso *dso);
285
286int dso__name_len(const struct dso *dso);
287
288bool dso__loaded(const struct dso *dso, enum map_type type);
289bool dso__sorted_by_name(const struct dso *dso, enum map_type type);
290
291static inline void dso__set_loaded(struct dso *dso, enum map_type type)
292{
293 dso->loaded |= (1 << type);
294}
295
296void dso__sort_by_name(struct dso *dso, enum map_type type);
297
298void dsos__add(struct list_head *head, struct dso *dso);
299struct dso *dsos__find(struct list_head *head, const char *name);
300struct dso *__dsos__findnew(struct list_head *head, const char *name);
301
302int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); 199int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter);
303int dso__load_vmlinux(struct dso *dso, struct map *map, 200int dso__load_vmlinux(struct dso *dso, struct map *map,
304 const char *vmlinux, symbol_filter_t filter); 201 const char *vmlinux, symbol_filter_t filter);
@@ -306,30 +203,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
306 symbol_filter_t filter); 203 symbol_filter_t filter);
307int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, 204int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map,
308 symbol_filter_t filter); 205 symbol_filter_t filter);
309int machine__load_kallsyms(struct machine *machine, const char *filename, 206
310 enum map_type type, symbol_filter_t filter);
311int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
312 symbol_filter_t filter);
313
314size_t __dsos__fprintf(struct list_head *head, FILE *fp);
315
316size_t machine__fprintf_dsos_buildid(struct machine *machine,
317 FILE *fp, bool with_hits);
318size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp);
319size_t machines__fprintf_dsos_buildid(struct rb_root *machines,
320 FILE *fp, bool with_hits);
321size_t dso__fprintf_buildid(struct dso *dso, FILE *fp);
322size_t dso__fprintf_symbols_by_name(struct dso *dso,
323 enum map_type type, FILE *fp);
324size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp);
325
326char dso__symtab_origin(const struct dso *dso);
327void dso__set_long_name(struct dso *dso, char *name);
328void dso__set_build_id(struct dso *dso, void *build_id);
329bool dso__build_id_equal(const struct dso *dso, u8 *build_id);
330void dso__read_running_kernel_build_id(struct dso *dso,
331 struct machine *machine);
332struct map *dso__new_map(const char *name);
333struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, 207struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
334 u64 addr); 208 u64 addr);
335struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 209struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
@@ -337,22 +211,12 @@ struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
337 211
338int filename__read_build_id(const char *filename, void *bf, size_t size); 212int filename__read_build_id(const char *filename, void *bf, size_t size);
339int sysfs__read_build_id(const char *filename, void *bf, size_t size); 213int sysfs__read_build_id(const char *filename, void *bf, size_t size);
340bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
341int build_id__sprintf(const u8 *build_id, int len, char *bf);
342int kallsyms__parse(const char *filename, void *arg, 214int kallsyms__parse(const char *filename, void *arg,
343 int (*process_symbol)(void *arg, const char *name, 215 int (*process_symbol)(void *arg, const char *name,
344 char type, u64 start)); 216 char type, u64 start));
345int filename__read_debuglink(const char *filename, char *debuglink, 217int filename__read_debuglink(const char *filename, char *debuglink,
346 size_t size); 218 size_t size);
347 219
348void machine__destroy_kernel_maps(struct machine *machine);
349int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel);
350int machine__create_kernel_maps(struct machine *machine);
351
352int machines__create_kernel_maps(struct rb_root *machines, pid_t pid);
353int machines__create_guest_kernel_maps(struct rb_root *machines);
354void machines__destroy_guest_kernel_maps(struct rb_root *machines);
355
356int symbol__init(void); 220int symbol__init(void);
357void symbol__exit(void); 221void symbol__exit(void);
358void symbol__elf_init(void); 222void symbol__elf_init(void);
@@ -360,20 +224,11 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
360size_t symbol__fprintf_symname_offs(const struct symbol *sym, 224size_t symbol__fprintf_symname_offs(const struct symbol *sym,
361 const struct addr_location *al, FILE *fp); 225 const struct addr_location *al, FILE *fp);
362size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); 226size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp);
227size_t symbol__fprintf(struct symbol *sym, FILE *fp);
363bool symbol_type__is_a(char symbol_type, enum map_type map_type); 228bool symbol_type__is_a(char symbol_type, enum map_type map_type);
229bool symbol__restricted_filename(const char *filename,
230 const char *restricted_filename);
364 231
365size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
366
367int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
368 char *root_dir, char *file, size_t size);
369
370int dso__data_fd(struct dso *dso, struct machine *machine);
371ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
372 u64 offset, u8 *data, ssize_t size);
373ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
374 struct machine *machine, u64 addr,
375 u8 *data, ssize_t size);
376int dso__test_data(void);
377int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, 232int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
378 struct symsrc *runtime_ss, symbol_filter_t filter, 233 struct symsrc *runtime_ss, symbol_filter_t filter,
379 int kmodule); 234 int kmodule);
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
index 48c6902e749f..f71e9eafe15a 100644
--- a/tools/perf/util/sysfs.c
+++ b/tools/perf/util/sysfs.c
@@ -8,7 +8,7 @@ static const char * const sysfs_known_mountpoints[] = {
8}; 8};
9 9
10static int sysfs_found; 10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX]; 11char sysfs_mountpoint[PATH_MAX + 1];
12 12
13static int sysfs_valid_mountpoint(const char *sysfs) 13static int sysfs_valid_mountpoint(const char *sysfs)
14{ 14{
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 8b3e5939afb6..632e40e5ceca 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,7 +7,7 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10static struct thread *thread__new(pid_t pid) 10struct thread *thread__new(pid_t pid)
11{ 11{
12 struct thread *self = zalloc(sizeof(*self)); 12 struct thread *self = zalloc(sizeof(*self));
13 13
@@ -54,49 +54,10 @@ int thread__comm_len(struct thread *self)
54 return self->comm_len; 54 return self->comm_len;
55} 55}
56 56
57static size_t thread__fprintf(struct thread *self, FILE *fp) 57size_t thread__fprintf(struct thread *thread, FILE *fp)
58{ 58{
59 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + 59 return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) +
60 map_groups__fprintf(&self->mg, verbose, fp); 60 map_groups__fprintf(&thread->mg, verbose, fp);
61}
62
63struct thread *machine__findnew_thread(struct machine *self, pid_t pid)
64{
65 struct rb_node **p = &self->threads.rb_node;
66 struct rb_node *parent = NULL;
67 struct thread *th;
68
69 /*
70 * Font-end cache - PID lookups come in blocks,
71 * so most of the time we dont have to look up
72 * the full rbtree:
73 */
74 if (self->last_match && self->last_match->pid == pid)
75 return self->last_match;
76
77 while (*p != NULL) {
78 parent = *p;
79 th = rb_entry(parent, struct thread, rb_node);
80
81 if (th->pid == pid) {
82 self->last_match = th;
83 return th;
84 }
85
86 if (pid < th->pid)
87 p = &(*p)->rb_left;
88 else
89 p = &(*p)->rb_right;
90 }
91
92 th = thread__new(pid);
93 if (th != NULL) {
94 rb_link_node(&th->rb_node, parent, p);
95 rb_insert_color(&th->rb_node, &self->threads);
96 self->last_match = th;
97 }
98
99 return th;
100} 61}
101 62
102void thread__insert_map(struct thread *self, struct map *map) 63void thread__insert_map(struct thread *self, struct map *map)
@@ -123,17 +84,3 @@ int thread__fork(struct thread *self, struct thread *parent)
123 return -ENOMEM; 84 return -ENOMEM;
124 return 0; 85 return 0;
125} 86}
126
127size_t machine__fprintf(struct machine *machine, FILE *fp)
128{
129 size_t ret = 0;
130 struct rb_node *nd;
131
132 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
133 struct thread *pos = rb_entry(nd, struct thread, rb_node);
134
135 ret += thread__fprintf(pos, fp);
136 }
137
138 return ret;
139}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index f66610b7bacf..5ad266403098 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <unistd.h> 5#include <unistd.h>
6#include <sys/types.h>
6#include "symbol.h" 7#include "symbol.h"
7 8
8struct thread { 9struct thread {
@@ -22,12 +23,14 @@ struct thread {
22 23
23struct machine; 24struct machine;
24 25
26struct thread *thread__new(pid_t pid);
25void thread__delete(struct thread *self); 27void thread__delete(struct thread *self);
26 28
27int thread__set_comm(struct thread *self, const char *comm); 29int thread__set_comm(struct thread *self, const char *comm);
28int thread__comm_len(struct thread *self); 30int thread__comm_len(struct thread *self);
29void thread__insert_map(struct thread *self, struct map *map); 31void thread__insert_map(struct thread *self, struct map *map);
30int thread__fork(struct thread *self, struct thread *parent); 32int thread__fork(struct thread *self, struct thread *parent);
33size_t thread__fprintf(struct thread *thread, FILE *fp);
31 34
32static inline struct map *thread__find_map(struct thread *self, 35static inline struct map *thread__find_map(struct thread *self,
33 enum map_type type, u64 addr) 36 enum map_type type, u64 addr)
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 884dde9b9bc1..54d37a4753c5 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -26,6 +26,8 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
26 float samples_per_sec = top->samples / top->delay_secs; 26 float samples_per_sec = top->samples / top->delay_secs;
27 float ksamples_per_sec = top->kernel_samples / top->delay_secs; 27 float ksamples_per_sec = top->kernel_samples / top->delay_secs;
28 float esamples_percent = (100.0 * top->exact_samples) / top->samples; 28 float esamples_percent = (100.0 * top->exact_samples) / top->samples;
29 struct perf_record_opts *opts = &top->record_opts;
30 struct perf_target *target = &opts->target;
29 size_t ret = 0; 31 size_t ret = 0;
30 32
31 if (!perf_guest) { 33 if (!perf_guest) {
@@ -61,31 +63,31 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
61 struct perf_evsel *first = perf_evlist__first(top->evlist); 63 struct perf_evsel *first = perf_evlist__first(top->evlist);
62 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", 64 ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ",
63 (uint64_t)first->attr.sample_period, 65 (uint64_t)first->attr.sample_period,
64 top->freq ? "Hz" : ""); 66 opts->freq ? "Hz" : "");
65 } 67 }
66 68
67 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel)); 69 ret += SNPRINTF(bf + ret, size - ret, "%s", perf_evsel__name(top->sym_evsel));
68 70
69 ret += SNPRINTF(bf + ret, size - ret, "], "); 71 ret += SNPRINTF(bf + ret, size - ret, "], ");
70 72
71 if (top->target.pid) 73 if (target->pid)
72 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", 74 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
73 top->target.pid); 75 target->pid);
74 else if (top->target.tid) 76 else if (target->tid)
75 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", 77 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
76 top->target.tid); 78 target->tid);
77 else if (top->target.uid_str != NULL) 79 else if (target->uid_str != NULL)
78 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", 80 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
79 top->target.uid_str); 81 target->uid_str);
80 else 82 else
81 ret += SNPRINTF(bf + ret, size - ret, " (all"); 83 ret += SNPRINTF(bf + ret, size - ret, " (all");
82 84
83 if (top->target.cpu_list) 85 if (target->cpu_list)
84 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 86 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
85 top->evlist->cpus->nr > 1 ? "s" : "", 87 top->evlist->cpus->nr > 1 ? "s" : "",
86 top->target.cpu_list); 88 target->cpu_list);
87 else { 89 else {
88 if (top->target.tid) 90 if (target->tid)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 91 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 92 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 93 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index 86ff1b15059b..7ebf357dc9e1 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -14,7 +14,7 @@ struct perf_session;
14struct perf_top { 14struct perf_top {
15 struct perf_tool tool; 15 struct perf_tool tool;
16 struct perf_evlist *evlist; 16 struct perf_evlist *evlist;
17 struct perf_target target; 17 struct perf_record_opts record_opts;
18 /* 18 /*
19 * Symbols will be added here in perf_event__process_sample and will 19 * Symbols will be added here in perf_event__process_sample and will
20 * get out after decayed. 20 * get out after decayed.
@@ -24,24 +24,16 @@ struct perf_top {
24 u64 exact_samples; 24 u64 exact_samples;
25 u64 guest_us_samples, guest_kernel_samples; 25 u64 guest_us_samples, guest_kernel_samples;
26 int print_entries, count_filter, delay_secs; 26 int print_entries, count_filter, delay_secs;
27 int freq;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool use_tui, use_stdio; 28 bool use_tui, use_stdio;
30 bool sort_has_symbols; 29 bool sort_has_symbols;
31 bool dont_use_callchains;
32 bool kptr_restrict_warned; 30 bool kptr_restrict_warned;
33 bool vmlinux_warned; 31 bool vmlinux_warned;
34 bool inherit;
35 bool group;
36 bool sample_id_all_missing;
37 bool exclude_guest_missing;
38 bool dump_symtab; 32 bool dump_symtab;
39 struct hist_entry *sym_filter_entry; 33 struct hist_entry *sym_filter_entry;
40 struct perf_evsel *sym_evsel; 34 struct perf_evsel *sym_evsel;
41 struct perf_session *session; 35 struct perf_session *session;
42 struct winsize winsize; 36 struct winsize winsize;
43 unsigned int mmap_pages;
44 int default_interval;
45 int realtime_prio; 37 int realtime_prio;
46 int sym_pcnt_filter; 38 int sym_pcnt_filter;
47 const char *sym_filter; 39 const char *sym_filter;
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 719ed74a8565..3741572696af 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -47,8 +47,6 @@ int file_bigendian;
47int host_bigendian; 47int host_bigendian;
48static int long_size; 48static int long_size;
49 49
50static unsigned long page_size;
51
52static ssize_t calc_data_size; 50static ssize_t calc_data_size;
53static bool repipe; 51static bool repipe;
54 52
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 99664598bc1a..805d1f52c5b4 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -10,6 +10,10 @@
10/* 10/*
11 * XXX We need to find a better place for these things... 11 * XXX We need to find a better place for these things...
12 */ 12 */
13unsigned int page_size;
14
15bool test_attr__enabled;
16
13bool perf_host = true; 17bool perf_host = true;
14bool perf_guest = false; 18bool perf_guest = false;
15 19
@@ -164,6 +168,39 @@ size_t hex_width(u64 v)
164 return n; 168 return n;
165} 169}
166 170
171static int hex(char ch)
172{
173 if ((ch >= '0') && (ch <= '9'))
174 return ch - '0';
175 if ((ch >= 'a') && (ch <= 'f'))
176 return ch - 'a' + 10;
177 if ((ch >= 'A') && (ch <= 'F'))
178 return ch - 'A' + 10;
179 return -1;
180}
181
182/*
183 * While we find nice hex chars, build a long_val.
184 * Return number of chars processed.
185 */
186int hex2u64(const char *ptr, u64 *long_val)
187{
188 const char *p = ptr;
189 *long_val = 0;
190
191 while (*p) {
192 const int hex_val = hex(*p);
193
194 if (hex_val < 0)
195 break;
196
197 *long_val = (*long_val << 4) | hex_val;
198 p++;
199 }
200
201 return p - ptr;
202}
203
167/* Obtain a backtrace and print it to stdout. */ 204/* Obtain a backtrace and print it to stdout. */
168#ifdef BACKTRACE_SUPPORT 205#ifdef BACKTRACE_SUPPORT
169void dump_stack(void) 206void dump_stack(void)
@@ -183,3 +220,25 @@ void dump_stack(void)
183#else 220#else
184void dump_stack(void) {} 221void dump_stack(void) {}
185#endif 222#endif
223
224void get_term_dimensions(struct winsize *ws)
225{
226 char *s = getenv("LINES");
227
228 if (s != NULL) {
229 ws->ws_row = atoi(s);
230 s = getenv("COLUMNS");
231 if (s != NULL) {
232 ws->ws_col = atoi(s);
233 if (ws->ws_row && ws->ws_col)
234 return;
235 }
236 }
237#ifdef TIOCGWINSZ
238 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
239 ws->ws_row && ws->ws_col)
240 return;
241#endif
242 ws->ws_row = 25;
243 ws->ws_col = 80;
244}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 70fa70b535b2..09b4c26b71aa 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -198,6 +198,10 @@ static inline int has_extension(const char *filename, const char *ext)
198#undef tolower 198#undef tolower
199#undef toupper 199#undef toupper
200 200
201#ifndef NSEC_PER_MSEC
202#define NSEC_PER_MSEC 1000000L
203#endif
204
201extern unsigned char sane_ctype[256]; 205extern unsigned char sane_ctype[256];
202#define GIT_SPACE 0x01 206#define GIT_SPACE 0x01
203#define GIT_DIGIT 0x02 207#define GIT_DIGIT 0x02
@@ -236,6 +240,7 @@ void argv_free(char **argv);
236bool strglobmatch(const char *str, const char *pat); 240bool strglobmatch(const char *str, const char *pat);
237bool strlazymatch(const char *str, const char *pat); 241bool strlazymatch(const char *str, const char *pat);
238int strtailcmp(const char *s1, const char *s2); 242int strtailcmp(const char *s1, const char *s2);
243char *strxfrchar(char *s, char from, char to);
239unsigned long convert_unit(unsigned long value, char *unit); 244unsigned long convert_unit(unsigned long value, char *unit);
240int readn(int fd, void *buf, size_t size); 245int readn(int fd, void *buf, size_t size);
241 246
@@ -258,9 +263,16 @@ bool is_power_of_2(unsigned long n)
258} 263}
259 264
260size_t hex_width(u64 v); 265size_t hex_width(u64 v);
266int hex2u64(const char *ptr, u64 *val);
261 267
268char *ltrim(char *s);
262char *rtrim(char *s); 269char *rtrim(char *s);
263 270
264void dump_stack(void); 271void dump_stack(void);
265 272
273extern unsigned int page_size;
274
275struct winsize;
276void get_term_dimensions(struct winsize *ws);
277
266#endif 278#endif
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index 6b9cf7a987c7..bafeb8d662a3 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -13,6 +13,6 @@ clean :
13 rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~ 13 rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~
14 14
15install : 15install :
16 install acpidump /usr/bin/acpidump 16 install acpidump /usr/sbin/acpidump
17 install acpidump.8 /usr/share/man/man8 17 install acpidump.8 /usr/share/man/man8
18 18
diff --git a/tools/power/cpupower/.gitignore b/tools/power/cpupower/.gitignore
index 8a83dd2ffc11..d42073f12609 100644
--- a/tools/power/cpupower/.gitignore
+++ b/tools/power/cpupower/.gitignore
@@ -20,3 +20,10 @@ utils/cpufreq-set.o
20utils/cpufreq-aperf.o 20utils/cpufreq-aperf.o
21cpupower 21cpupower
22bench/cpufreq-bench 22bench/cpufreq-bench
23debug/kernel/Module.symvers
24debug/i386/centrino-decode
25debug/i386/dump_psb
26debug/i386/intel_gsic
27debug/i386/powernow-k8-decode
28debug/x86_64/centrino-decode
29debug/x86_64/powernow-k8-decode
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index cf397bd26d0c..d875a74a3bdf 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -253,7 +253,8 @@ clean:
253 | xargs rm -f 253 | xargs rm -f
254 -rm -f $(OUTPUT)cpupower 254 -rm -f $(OUTPUT)cpupower
255 -rm -f $(OUTPUT)libcpupower.so* 255 -rm -f $(OUTPUT)libcpupower.so*
256 -rm -rf $(OUTPUT)po/*.{gmo,pot} 256 -rm -rf $(OUTPUT)po/*.gmo
257 -rm -rf $(OUTPUT)po/*.pot
257 $(MAKE) -C bench O=$(OUTPUT) clean 258 $(MAKE) -C bench O=$(OUTPUT) clean
258 259
259 260
diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile
index 3ba158f0e287..c05cc0ac80c7 100644
--- a/tools/power/cpupower/debug/i386/Makefile
+++ b/tools/power/cpupower/debug/i386/Makefile
@@ -26,7 +26,10 @@ $(OUTPUT)powernow-k8-decode: powernow-k8-decode.c
26all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode 26all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode
27 27
28clean: 28clean:
29 rm -rf $(OUTPUT){centrino-decode,dump_psb,intel_gsic,powernow-k8-decode} 29 rm -rf $(OUTPUT)centrino-decode
30 rm -rf $(OUTPUT)dump_psb
31 rm -rf $(OUTPUT)intel_gsic
32 rm -rf $(OUTPUT)powernow-k8-decode
30 33
31install: 34install:
32 $(INSTALL) -d $(DESTDIR)${bindir} 35 $(INSTALL) -d $(DESTDIR)${bindir}
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1
index 1141c2073719..e01c35d13b6e 100644
--- a/tools/power/cpupower/man/cpupower-monitor.1
+++ b/tools/power/cpupower/man/cpupower-monitor.1
@@ -7,11 +7,11 @@ cpupower\-monitor \- Report processor frequency and idle statistics
7.RB "\-l" 7.RB "\-l"
8 8
9.B cpupower monitor 9.B cpupower monitor
10.RB [ "\-m <mon1>," [ "<mon2>,..." ] ] 10.RB [ -c ] [ "\-m <mon1>," [ "<mon2>,..." ] ]
11.RB [ "\-i seconds" ] 11.RB [ "\-i seconds" ]
12.br 12.br
13.B cpupower monitor 13.B cpupower monitor
14.RB [ "\-m <mon1>," [ "<mon2>,..." ] ] 14.RB [ -c ][ "\-m <mon1>," [ "<mon2>,..." ] ]
15.RB command 15.RB command
16.br 16.br
17.SH DESCRIPTION 17.SH DESCRIPTION
@@ -64,6 +64,17 @@ Only display specific monitors. Use the monitor string(s) provided by \-l option
64Measure intervall. 64Measure intervall.
65.RE 65.RE
66.PP 66.PP
67\-c
68.RS 4
69Schedule the process on every core before starting and ending measuring.
70This could be needed for the Idle_Stats monitor when no other MSR based
71monitor (has to be run on the core that is measured) is run in parallel.
72This is to wake up the processors from deeper sleep states and let the
73kernel re
74-account its cpuidle (C-state) information before reading the
75cpuidle timings from sysfs.
76.RE
77.PP
67command 78command
68.RS 4 79.RS 4
69Measure idle and frequency characteristics of an arbitrary command/workload. 80Measure idle and frequency characteristics of an arbitrary command/workload.
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
index 906895d21cce..93b0aa74ca03 100644
--- a/tools/power/cpupower/utils/helpers/cpuid.c
+++ b/tools/power/cpupower/utils/helpers/cpuid.c
@@ -158,6 +158,8 @@ out:
158 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; 158 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
159 case 0x2A: /* SNB */ 159 case 0x2A: /* SNB */
160 case 0x2D: /* SNB Xeon */ 160 case 0x2D: /* SNB Xeon */
161 case 0x3A: /* IVB */
162 case 0x3E: /* IVB Xeon */
161 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; 163 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
162 cpu_info->caps |= CPUPOWER_CAP_IS_SNB; 164 cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
163 break; 165 break;
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 2eb584cf2f55..aa9e95486a2d 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -92,6 +92,14 @@ extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
92extern struct cpupower_cpu_info cpupower_cpu_info; 92extern struct cpupower_cpu_info cpupower_cpu_info;
93/* cpuid and cpuinfo helpers **************************/ 93/* cpuid and cpuinfo helpers **************************/
94 94
95struct cpuid_core_info {
96 int pkg;
97 int core;
98 int cpu;
99
100 /* flags */
101 unsigned int is_online:1;
102};
95 103
96/* CPU topology/hierarchy parsing ******************/ 104/* CPU topology/hierarchy parsing ******************/
97struct cpupower_topology { 105struct cpupower_topology {
@@ -101,18 +109,12 @@ struct cpupower_topology {
101 unsigned int threads; /* per core */ 109 unsigned int threads; /* per core */
102 110
103 /* Array gets mallocated with cores entries, holding per core info */ 111 /* Array gets mallocated with cores entries, holding per core info */
104 struct { 112 struct cpuid_core_info *core_info;
105 int pkg;
106 int core;
107 int cpu;
108
109 /* flags */
110 unsigned int is_online:1;
111 } *core_info;
112}; 113};
113 114
114extern int get_cpu_topology(struct cpupower_topology *cpu_top); 115extern int get_cpu_topology(struct cpupower_topology *cpu_top);
115extern void cpu_topology_release(struct cpupower_topology cpu_top); 116extern void cpu_topology_release(struct cpupower_topology cpu_top);
117
116/* CPU topology/hierarchy parsing ******************/ 118/* CPU topology/hierarchy parsing ******************/
117 119
118/* X86 ONLY ****************************************/ 120/* X86 ONLY ****************************************/
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 96e28c124b5c..38ab91629463 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -37,25 +37,6 @@ unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
37 return (unsigned int) numread; 37 return (unsigned int) numread;
38} 38}
39 39
40static unsigned int sysfs_write_file(const char *path,
41 const char *value, size_t len)
42{
43 int fd;
44 ssize_t numwrite;
45
46 fd = open(path, O_WRONLY);
47 if (fd == -1)
48 return 0;
49
50 numwrite = write(fd, value, len);
51 if (numwrite < 1) {
52 close(fd);
53 return 0;
54 }
55 close(fd);
56 return (unsigned int) numwrite;
57}
58
59/* 40/*
60 * Detect whether a CPU is online 41 * Detect whether a CPU is online
61 * 42 *
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
index 4eae2c47ba48..c13120af519b 100644
--- a/tools/power/cpupower/utils/helpers/topology.c
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -20,9 +20,8 @@
20#include <helpers/sysfs.h> 20#include <helpers/sysfs.h>
21 21
22/* returns -1 on failure, 0 on success */ 22/* returns -1 on failure, 0 on success */
23int sysfs_topology_read_file(unsigned int cpu, const char *fname) 23static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
24{ 24{
25 unsigned long value;
26 char linebuf[MAX_LINE_LEN]; 25 char linebuf[MAX_LINE_LEN];
27 char *endp; 26 char *endp;
28 char path[SYSFS_PATH_MAX]; 27 char path[SYSFS_PATH_MAX];
@@ -31,20 +30,12 @@ int sysfs_topology_read_file(unsigned int cpu, const char *fname)
31 cpu, fname); 30 cpu, fname);
32 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) 31 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
33 return -1; 32 return -1;
34 value = strtoul(linebuf, &endp, 0); 33 *result = strtol(linebuf, &endp, 0);
35 if (endp == linebuf || errno == ERANGE) 34 if (endp == linebuf || errno == ERANGE)
36 return -1; 35 return -1;
37 return value; 36 return 0;
38} 37}
39 38
40struct cpuid_core_info {
41 unsigned int pkg;
42 unsigned int thread;
43 unsigned int cpu;
44 /* flags */
45 unsigned int is_online:1;
46};
47
48static int __compare(const void *t1, const void *t2) 39static int __compare(const void *t1, const void *t2)
49{ 40{
50 struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; 41 struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
@@ -53,9 +44,9 @@ static int __compare(const void *t1, const void *t2)
53 return -1; 44 return -1;
54 else if (top1->pkg > top2->pkg) 45 else if (top1->pkg > top2->pkg)
55 return 1; 46 return 1;
56 else if (top1->thread < top2->thread) 47 else if (top1->core < top2->core)
57 return -1; 48 return -1;
58 else if (top1->thread > top2->thread) 49 else if (top1->core > top2->core)
59 return 1; 50 return 1;
60 else if (top1->cpu < top2->cpu) 51 else if (top1->cpu < top2->cpu)
61 return -1; 52 return -1;
@@ -73,28 +64,42 @@ static int __compare(const void *t1, const void *t2)
73 */ 64 */
74int get_cpu_topology(struct cpupower_topology *cpu_top) 65int get_cpu_topology(struct cpupower_topology *cpu_top)
75{ 66{
76 int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF); 67 int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
77 68
78 cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus); 69 cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
79 if (cpu_top->core_info == NULL) 70 if (cpu_top->core_info == NULL)
80 return -ENOMEM; 71 return -ENOMEM;
81 cpu_top->pkgs = cpu_top->cores = 0; 72 cpu_top->pkgs = cpu_top->cores = 0;
82 for (cpu = 0; cpu < cpus; cpu++) { 73 for (cpu = 0; cpu < cpus; cpu++) {
83 cpu_top->core_info[cpu].cpu = cpu; 74 cpu_top->core_info[cpu].cpu = cpu;
84 cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); 75 cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
85 cpu_top->core_info[cpu].pkg = 76 if(sysfs_topology_read_file(
86 sysfs_topology_read_file(cpu, "physical_package_id"); 77 cpu,
87 if ((int)cpu_top->core_info[cpu].pkg != -1 && 78 "physical_package_id",
88 cpu_top->core_info[cpu].pkg > cpu_top->pkgs) 79 &(cpu_top->core_info[cpu].pkg)) < 0)
89 cpu_top->pkgs = cpu_top->core_info[cpu].pkg; 80 return -1;
90 cpu_top->core_info[cpu].core = 81 if(sysfs_topology_read_file(
91 sysfs_topology_read_file(cpu, "core_id"); 82 cpu,
83 "core_id",
84 &(cpu_top->core_info[cpu].core)) < 0)
85 return -1;
92 } 86 }
93 cpu_top->pkgs++;
94 87
95 qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), 88 qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
96 __compare); 89 __compare);
97 90
91 /* Count the number of distinct pkgs values. This works
92 because the primary sort of the core_info struct was just
93 done by pkg value. */
94 last_pkg = cpu_top->core_info[0].pkg;
95 for(cpu = 1; cpu < cpus; cpu++) {
96 if(cpu_top->core_info[cpu].pkg != last_pkg) {
97 last_pkg = cpu_top->core_info[cpu].pkg;
98 cpu_top->pkgs++;
99 }
100 }
101 cpu_top->pkgs++;
102
98 /* Intel's cores count is not consecutively numbered, there may 103 /* Intel's cores count is not consecutively numbered, there may
99 * be a core_id of 3, but none of 2. Assume there always is 0 104 * be a core_id of 3, but none of 2. Assume there always is 0
100 * Get amount of cores by counting duplicates in a package 105 * Get amount of cores by counting duplicates in a package
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
index 0d6571e418db..c4bae9203a69 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -39,6 +39,7 @@ static int mode;
39static int interval = 1; 39static int interval = 1;
40static char *show_monitors_param; 40static char *show_monitors_param;
41static struct cpupower_topology cpu_top; 41static struct cpupower_topology cpu_top;
42static unsigned int wake_cpus;
42 43
43/* ToDo: Document this in the manpage */ 44/* ToDo: Document this in the manpage */
44static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; 45static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
@@ -84,7 +85,7 @@ int fill_string_with_spaces(char *s, int n)
84void print_header(int topology_depth) 85void print_header(int topology_depth)
85{ 86{
86 int unsigned mon; 87 int unsigned mon;
87 int state, need_len, pr_mon_len; 88 int state, need_len;
88 cstate_t s; 89 cstate_t s;
89 char buf[128] = ""; 90 char buf[128] = "";
90 int percent_width = 4; 91 int percent_width = 4;
@@ -93,7 +94,6 @@ void print_header(int topology_depth)
93 printf("%s|", buf); 94 printf("%s|", buf);
94 95
95 for (mon = 0; mon < avail_monitors; mon++) { 96 for (mon = 0; mon < avail_monitors; mon++) {
96 pr_mon_len = 0;
97 need_len = monitors[mon]->hw_states_num * (percent_width + 3) 97 need_len = monitors[mon]->hw_states_num * (percent_width + 3)
98 - 1; 98 - 1;
99 if (mon != 0) { 99 if (mon != 0) {
@@ -315,16 +315,28 @@ int fork_it(char **argv)
315int do_interval_measure(int i) 315int do_interval_measure(int i)
316{ 316{
317 unsigned int num; 317 unsigned int num;
318 int cpu;
319
320 if (wake_cpus)
321 for (cpu = 0; cpu < cpu_count; cpu++)
322 bind_cpu(cpu);
318 323
319 for (num = 0; num < avail_monitors; num++) { 324 for (num = 0; num < avail_monitors; num++) {
320 dprint("HW C-state residency monitor: %s - States: %d\n", 325 dprint("HW C-state residency monitor: %s - States: %d\n",
321 monitors[num]->name, monitors[num]->hw_states_num); 326 monitors[num]->name, monitors[num]->hw_states_num);
322 monitors[num]->start(); 327 monitors[num]->start();
323 } 328 }
329
324 sleep(i); 330 sleep(i);
331
332 if (wake_cpus)
333 for (cpu = 0; cpu < cpu_count; cpu++)
334 bind_cpu(cpu);
335
325 for (num = 0; num < avail_monitors; num++) 336 for (num = 0; num < avail_monitors; num++)
326 monitors[num]->stop(); 337 monitors[num]->stop();
327 338
339
328 return 0; 340 return 0;
329} 341}
330 342
@@ -333,7 +345,7 @@ static void cmdline(int argc, char *argv[])
333 int opt; 345 int opt;
334 progname = basename(argv[0]); 346 progname = basename(argv[0]);
335 347
336 while ((opt = getopt(argc, argv, "+li:m:")) != -1) { 348 while ((opt = getopt(argc, argv, "+lci:m:")) != -1) {
337 switch (opt) { 349 switch (opt) {
338 case 'l': 350 case 'l':
339 if (mode) 351 if (mode)
@@ -352,6 +364,9 @@ static void cmdline(int argc, char *argv[])
352 mode = show; 364 mode = show;
353 show_monitors_param = optarg; 365 show_monitors_param = optarg;
354 break; 366 break;
367 case 'c':
368 wake_cpus = 1;
369 break;
355 default: 370 default:
356 print_wrong_arg_exit(); 371 print_wrong_arg_exit();
357 } 372 }
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
index 9312ee1f2dbc..9e43f3371fbc 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
@@ -65,4 +65,21 @@ extern long long timespec_diff_us(struct timespec start, struct timespec end);
65 "could be inaccurate\n"), mes, ov); \ 65 "could be inaccurate\n"), mes, ov); \
66} 66}
67 67
68
69/* Taken over from x86info project sources -> return 0 on success */
70#include <sched.h>
71#include <sys/types.h>
72#include <unistd.h>
73static inline int bind_cpu(int cpu)
74{
75 cpu_set_t set;
76
77 if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) {
78 CPU_ZERO(&set);
79 CPU_SET(cpu, &set);
80 return sched_setaffinity(getpid(), sizeof(set), &set);
81 }
82 return 1;
83}
84
68#endif /* __CPUIDLE_INFO_HW__ */ 85#endif /* __CPUIDLE_INFO_HW__ */
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
index a1bc07cd53e1..a99b43b97d6d 100644
--- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
@@ -150,9 +150,15 @@ static struct cpuidle_monitor *snb_register(void)
150 || cpupower_cpu_info.family != 6) 150 || cpupower_cpu_info.family != 6)
151 return NULL; 151 return NULL;
152 152
153 if (cpupower_cpu_info.model != 0x2A 153 switch (cpupower_cpu_info.model) {
154 && cpupower_cpu_info.model != 0x2D) 154 case 0x2A: /* SNB */
155 case 0x2D: /* SNB Xeon */
156 case 0x3A: /* IVB */
157 case 0x3E: /* IVB Xeon */
158 break;
159 default:
155 return NULL; 160 return NULL;
161 }
156 162
157 is_valid = calloc(cpu_count, sizeof(int)); 163 is_valid = calloc(cpu_count, sizeof(int));
158 for (num = 0; num < SNB_CSTATE_COUNT; num++) { 164 for (num = 0; num < SNB_CSTATE_COUNT; num++) {
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile
index f85649554191..f09641da40d4 100644
--- a/tools/power/x86/turbostat/Makefile
+++ b/tools/power/x86/turbostat/Makefile
@@ -1,9 +1,22 @@
1CC = $(CROSS_COMPILE)gcc
2BUILD_OUTPUT := $(PWD)
3PREFIX := /usr
4DESTDIR :=
5
1turbostat : turbostat.c 6turbostat : turbostat.c
2CFLAGS += -Wall 7CFLAGS += -Wall
8CFLAGS += -I../../../../arch/x86/include/uapi/
9
10%: %.c
11 @mkdir -p $(BUILD_OUTPUT)
12 $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
3 13
14.PHONY : clean
4clean : 15clean :
5 rm -f turbostat 16 @rm -f $(BUILD_OUTPUT)/turbostat
6 17
7install : 18install : turbostat
8 install turbostat /usr/bin/turbostat 19 install -d $(DESTDIR)$(PREFIX)/bin
9 install turbostat.8 /usr/share/man/man8 20 install $(BUILD_OUTPUT)/turbostat $(DESTDIR)$(PREFIX)/bin/turbostat
21 install -d $(DESTDIR)$(PREFIX)/share/man/man8
22 install turbostat.8 $(DESTDIR)$(PREFIX)/share/man/man8
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index e4d0690cccf9..b4ddb748356c 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -11,16 +11,16 @@ turbostat \- Report processor frequency and idle statistics
11.RB [ Options ] 11.RB [ Options ]
12.RB [ "\-i interval_sec" ] 12.RB [ "\-i interval_sec" ]
13.SH DESCRIPTION 13.SH DESCRIPTION
14\fBturbostat \fP reports processor topology, frequency 14\fBturbostat \fP reports processor topology, frequency,
15and idle power state statistics on modern X86 processors. 15idle power-state statistics, temperature and power on modern X86 processors.
16Either \fBcommand\fP is forked and statistics are printed 16Either \fBcommand\fP is forked and statistics are printed
17upon its completion, or statistics are printed periodically. 17upon its completion, or statistics are printed periodically.
18 18
19\fBturbostat \fP 19\fBturbostat \fP
20requires that the processor 20must be run on root, and
21minimally requires that the processor
21supports an "invariant" TSC, plus the APERF and MPERF MSRs. 22supports an "invariant" TSC, plus the APERF and MPERF MSRs.
22\fBturbostat \fP will report idle cpu power state residency 23Additional information is reported depending on hardware counter support.
23on processors that additionally support C-state residency counters.
24 24
25.SS Options 25.SS Options
26The \fB-p\fP option limits output to the 1st thread in 1st core of each package. 26The \fB-p\fP option limits output to the 1st thread in 1st core of each package.
@@ -31,8 +31,6 @@ The \fB-S\fP option limits output to a 1-line System Summary for each interval.
31.PP 31.PP
32The \fB-v\fP option increases verbosity. 32The \fB-v\fP option increases verbosity.
33.PP 33.PP
34The \fB-s\fP option prints the SMI counter, equivalent to "-c 0x34"
35.PP
36The \fB-c MSR#\fP option includes the delta of the specified 32-bit MSR counter. 34The \fB-c MSR#\fP option includes the delta of the specified 32-bit MSR counter.
37.PP 35.PP
38The \fB-C MSR#\fP option includes the delta of the specified 64-bit MSR counter. 36The \fB-C MSR#\fP option includes the delta of the specified 64-bit MSR counter.
@@ -57,7 +55,15 @@ Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading T
57\fBGHz\fP average clock rate while the CPU was in c0 state. 55\fBGHz\fP average clock rate while the CPU was in c0 state.
58\fBTSC\fP average GHz that the TSC ran during the entire interval. 56\fBTSC\fP average GHz that the TSC ran during the entire interval.
59\fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states. 57\fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states.
58\fBCTMP\fP Degrees Celsius reported by the per-core Digital Thermal Sensor.
59\fBPTMP\fP Degrees Celsius reported by the per-package Package Thermal Monitor.
60\fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states. 60\fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states.
61\fBPkg_W\fP Watts consumed by the whole package.
62\fBCor_W\fP Watts consumed by the core part of the package.
63\fBGFX_W\fP Watts consumed by the Graphics part of the package -- available only on client processors.
64\fBRAM_W\fP Watts consumed by the DRAM DIMMS -- available only on server processors.
65\fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package.
66\fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM.
61.fi 67.fi
62.PP 68.PP
63.SH EXAMPLE 69.SH EXAMPLE
@@ -66,50 +72,73 @@ Without any parameters, turbostat prints out counters ever 5 seconds.
66for turbostat to fork). 72for turbostat to fork).
67 73
68The first row of statistics is a summary for the entire system. 74The first row of statistics is a summary for the entire system.
69Note that the summary is a weighted average. 75For residency % columns, the summary is a weighted average.
76For Temperature columns, the summary is the column maximum.
77For Watts columns, the summary is a system total.
70Subsequent rows show per-CPU statistics. 78Subsequent rows show per-CPU statistics.
71 79
72.nf 80.nf
73[root@x980]# ./turbostat 81[root@sandy]# ./turbostat
74cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 82cor CPU %c0 GHz TSC %c1 %c3 %c6 %c7 CTMP PTMP %pc2 %pc3 %pc6 %pc7 Pkg_W Cor_W GFX_W
75 0.09 1.62 3.38 1.83 0.32 97.76 1.26 83.61 83 0.06 0.80 2.29 0.11 0.00 0.00 99.83 47 40 0.26 0.01 0.44 98.78 3.49 0.12 0.14
76 0 0 0.15 1.62 3.38 10.23 0.05 89.56 1.26 83.61 84 0 0 0.07 0.80 2.29 0.07 0.00 0.00 99.86 40 40 0.26 0.01 0.44 98.78 3.49 0.12 0.14
77 0 6 0.05 1.62 3.38 10.34 85 0 4 0.03 0.80 2.29 0.12
78 1 2 0.03 1.62 3.38 0.07 0.05 99.86 86 1 1 0.04 0.80 2.29 0.25 0.01 0.00 99.71 40
79 1 8 0.03 1.62 3.38 0.06 87 1 5 0.16 0.80 2.29 0.13
80 2 4 0.21 1.62 3.38 0.10 1.49 98.21 88 2 2 0.05 0.80 2.29 0.06 0.01 0.00 99.88 40
81 2 10 0.02 1.62 3.38 0.29 89 2 6 0.03 0.80 2.29 0.08
82 8 1 0.04 1.62 3.38 0.04 0.08 99.84 90 3 3 0.05 0.80 2.29 0.08 0.00 0.00 99.87 47
83 8 7 0.01 1.62 3.38 0.06 91 3 7 0.04 0.84 2.29 0.09
84 9 3 0.53 1.62 3.38 0.10 0.20 99.17
85 9 9 0.02 1.62 3.38 0.60
86 10 5 0.01 1.62 3.38 0.02 0.04 99.92
87 10 11 0.02 1.62 3.38 0.02
88.fi 92.fi
89.SH SUMMARY EXAMPLE 93.SH SUMMARY EXAMPLE
90The "-s" option prints the column headers just once, 94The "-s" option prints the column headers just once,
91and then the one line system summary for each sample interval. 95and then the one line system summary for each sample interval.
92 96
93.nf 97.nf
94[root@x980]# ./turbostat -s 98[root@wsm]# turbostat -S
95 %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 99 %c0 GHz TSC %c1 %c3 %c6 CTMP %pc3 %pc6
96 0.23 1.67 3.38 2.00 0.30 97.47 1.07 82.12 100 1.40 2.81 3.38 10.78 43.47 44.35 42 13.67 2.09
97 0.10 1.62 3.38 1.87 2.25 95.77 12.02 72.60 101 1.34 2.90 3.38 11.48 58.96 28.23 41 19.89 0.15
98 0.20 1.64 3.38 1.98 0.11 97.72 0.30 83.36 102 1.55 2.72 3.38 26.73 37.66 34.07 42 2.53 2.80
99 0.11 1.70 3.38 1.86 1.81 96.22 9.71 74.90 103 1.37 2.83 3.38 16.95 60.05 21.63 42 5.76 0.20
100.fi 104.fi
101.SH VERBOSE EXAMPLE 105.SH VERBOSE EXAMPLE
102The "-v" option adds verbosity to the output: 106The "-v" option adds verbosity to the output:
103 107
104.nf 108.nf
105GenuineIntel 11 CPUID levels; family:model:stepping 0x6:2c:2 (6:44:2) 109[root@ivy]# turbostat -v
10612 * 133 = 1600 MHz max efficiency 110turbostat v3.0 November 23, 2012 - Len Brown <lenb@kernel.org>
10725 * 133 = 3333 MHz TSC frequency 111CPUID(0): GenuineIntel 13 CPUID levels; family:model:stepping 0x6:3a:9 (6:58:9)
10826 * 133 = 3467 MHz max turbo 4 active cores 112CPUID(6): APERF, DTS, PTM, EPB
10926 * 133 = 3467 MHz max turbo 3 active cores 113RAPL: 851 sec. Joule Counter Range
11027 * 133 = 3600 MHz max turbo 2 active cores 114cpu0: MSR_NHM_PLATFORM_INFO: 0x81010f0012300
11127 * 133 = 3600 MHz max turbo 1 active cores 11516 * 100 = 1600 MHz max efficiency
112 11635 * 100 = 3500 MHz TSC frequency
117cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x1e008402 (UNdemote-C3, UNdemote-C1, demote-C3, demote-C1, locked: pkg-cstate-limit=2: pc6-noret)
118cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x25262727
11937 * 100 = 3700 MHz max turbo 4 active cores
12038 * 100 = 3800 MHz max turbo 3 active cores
12139 * 100 = 3900 MHz max turbo 2 active cores
12239 * 100 = 3900 MHz max turbo 1 active cores
123cpu0: MSR_IA32_ENERGY_PERF_BIAS: 0x00000006 (balanced)
124cpu0: MSR_RAPL_POWER_UNIT: 0x000a1003 (0.125000 Watts, 0.000015 Joules, 0.000977 sec.)
125cpu0: MSR_PKG_POWER_INFO: 0x01e00268 (77 W TDP, RAPL 60 - 0 W, 0.000000 sec.)
126cpu0: MSR_PKG_POWER_LIMIT: 0x830000148268 (UNlocked)
127cpu0: PKG Limit #1: ENabled (77.000000 Watts, 1.000000 sec, clamp DISabled)
128cpu0: PKG Limit #2: ENabled (96.000000 Watts, 0.000977* sec, clamp DISabled)
129cpu0: MSR_PP0_POLICY: 0
130cpu0: MSR_PP0_POWER_LIMIT: 0x00000000 (UNlocked)
131cpu0: Cores Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled)
132cpu0: MSR_PP1_POLICY: 0
133cpu0: MSR_PP1_POWER_LIMIT: 0x00000000 (UNlocked)
134cpu0: GFX Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled)
135cpu0: MSR_IA32_TEMPERATURE_TARGET: 0x00691400 (105 C)
136cpu0: MSR_IA32_PACKAGE_THERM_STATUS: 0x884e0000 (27 C)
137cpu0: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1)
138cpu1: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1)
139cpu2: MSR_IA32_THERM_STATUS: 0x88540000 (21 C +/- 1)
140cpu3: MSR_IA32_THERM_STATUS: 0x884e0000 (27 C +/- 1)
141 ...
113.fi 142.fi
114The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency 143The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency
115available at the minimum package voltage. The \fBTSC frequency\fP is the nominal 144available at the minimum package voltage. The \fBTSC frequency\fP is the nominal
@@ -142,7 +171,7 @@ cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
142 10 5 1.42 3.43 3.38 2.14 30.99 65.44 171 10 5 1.42 3.43 3.38 2.14 30.99 65.44
143 10 11 0.16 2.88 3.38 3.40 172 10 11 0.16 2.88 3.38 3.40
144.fi 173.fi
145Above the cycle soaker drives cpu7 up its 3.6 Ghz turbo limit 174Above the cycle soaker drives cpu7 up its 3.6 GHz turbo limit
146while the other processors are generally in various states of idle. 175while the other processors are generally in various states of idle.
147 176
148Note that cpu1 and cpu7 are HT siblings within core8. 177Note that cpu1 and cpu7 are HT siblings within core8.
@@ -155,26 +184,24 @@ This is a weighted average, where the weight is %c0. ie. it is the total number
155un-halted cycles elapsed per time divided by the number of CPUs. 184un-halted cycles elapsed per time divided by the number of CPUs.
156.SH SMI COUNTING EXAMPLE 185.SH SMI COUNTING EXAMPLE
157On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter. 186On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter.
158Using the -m option, you can display how many SMIs have fired since reset, or if there 187This counter is shown by default under the "SMI" column.
159are SMIs during the measurement interval, you can display the delta using the -d option.
160.nf 188.nf
161[root@x980 ~]# turbostat -m 0x34 189[root@x980 ~]# turbostat
162cor CPU %c0 GHz TSC MSR 0x034 %c1 %c3 %c6 %pc3 %pc6 190cor CPU %c0 GHz TSC SMI %c1 %c3 %c6 CTMP %pc3 %pc6
163 1.41 1.82 3.38 0x00000000 8.92 37.82 51.85 17.37 0.55 191 0.11 1.91 3.38 0 1.84 0.26 97.79 29 0.82 83.87
164 0 0 3.73 2.03 3.38 0x00000055 1.72 48.25 46.31 17.38 0.55 192 0 0 0.40 1.63 3.38 0 10.27 0.12 89.20 20 0.82 83.88
165 0 6 0.14 1.63 3.38 0x00000056 5.30 193 0 6 0.06 1.63 3.38 0 10.61
166 1 2 2.51 1.80 3.38 0x00000056 15.65 29.33 52.52 194 1 2 0.37 2.63 3.38 0 0.02 0.10 99.51 22
167 1 8 0.10 1.65 3.38 0x00000056 18.05 195 1 8 0.01 1.62 3.38 0 0.39
168 2 4 1.16 1.68 3.38 0x00000056 5.87 24.47 68.50 196 2 4 0.07 1.62 3.38 0 0.04 0.07 99.82 23
169 2 10 0.10 1.63 3.38 0x00000056 6.93 197 2 10 0.02 1.62 3.38 0 0.09
170 8 1 3.84 1.91 3.38 0x00000056 1.36 50.65 44.16 198 8 1 0.23 1.64 3.38 0 0.10 1.07 98.60 24
171 8 7 0.08 1.64 3.38 0x00000056 5.12 199 8 7 0.02 1.64 3.38 0 0.31
172 9 3 1.82 1.73 3.38 0x00000056 7.59 24.21 66.38 200 9 3 0.03 1.62 3.38 0 0.03 0.05 99.89 29
173 9 9 0.09 1.68 3.38 0x00000056 9.32 201 9 9 0.02 1.62 3.38 0 0.05
174 10 5 1.66 1.65 3.38 0x00000056 15.10 50.00 33.23 202 10 5 0.07 1.62 3.38 0 0.08 0.12 99.73 27
175 10 11 1.72 1.65 3.38 0x00000056 15.05 203 10 11 0.03 1.62 3.38 0 0.13
176^C 204^C
177[root@x980 ~]#
178.fi 205.fi
179.SH NOTES 206.SH NOTES
180 207
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 2655ae9a3ad8..6f3214ed4444 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -20,6 +20,7 @@
20 */ 20 */
21 21
22#define _GNU_SOURCE 22#define _GNU_SOURCE
23#include <asm/msr.h>
23#include <stdio.h> 24#include <stdio.h>
24#include <unistd.h> 25#include <unistd.h>
25#include <sys/types.h> 26#include <sys/types.h>
@@ -35,28 +36,18 @@
35#include <ctype.h> 36#include <ctype.h>
36#include <sched.h> 37#include <sched.h>
37 38
38#define MSR_NEHALEM_PLATFORM_INFO 0xCE
39#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD
40#define MSR_IVT_TURBO_RATIO_LIMIT 0x1AE
41#define MSR_APERF 0xE8
42#define MSR_MPERF 0xE7
43#define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */
44#define MSR_PKG_C3_RESIDENCY 0x3F8
45#define MSR_PKG_C6_RESIDENCY 0x3F9
46#define MSR_PKG_C7_RESIDENCY 0x3FA /* SNB only */
47#define MSR_CORE_C3_RESIDENCY 0x3FC
48#define MSR_CORE_C6_RESIDENCY 0x3FD
49#define MSR_CORE_C7_RESIDENCY 0x3FE /* SNB only */
50
51char *proc_stat = "/proc/stat"; 39char *proc_stat = "/proc/stat";
52unsigned int interval_sec = 5; /* set with -i interval_sec */ 40unsigned int interval_sec = 5; /* set with -i interval_sec */
53unsigned int verbose; /* set with -v */ 41unsigned int verbose; /* set with -v */
42unsigned int rapl_verbose; /* set with -R */
43unsigned int thermal_verbose; /* set with -T */
54unsigned int summary_only; /* set with -s */ 44unsigned int summary_only; /* set with -s */
55unsigned int skip_c0; 45unsigned int skip_c0;
56unsigned int skip_c1; 46unsigned int skip_c1;
57unsigned int do_nhm_cstates; 47unsigned int do_nhm_cstates;
58unsigned int do_snb_cstates; 48unsigned int do_snb_cstates;
59unsigned int has_aperf; 49unsigned int has_aperf;
50unsigned int has_epb;
60unsigned int units = 1000000000; /* Ghz etc */ 51unsigned int units = 1000000000; /* Ghz etc */
61unsigned int genuine_intel; 52unsigned int genuine_intel;
62unsigned int has_invariant_tsc; 53unsigned int has_invariant_tsc;
@@ -67,6 +58,7 @@ unsigned int extra_msr_offset32;
67unsigned int extra_msr_offset64; 58unsigned int extra_msr_offset64;
68unsigned int extra_delta_offset32; 59unsigned int extra_delta_offset32;
69unsigned int extra_delta_offset64; 60unsigned int extra_delta_offset64;
61int do_smi;
70double bclk; 62double bclk;
71unsigned int show_pkg; 63unsigned int show_pkg;
72unsigned int show_core; 64unsigned int show_core;
@@ -74,6 +66,23 @@ unsigned int show_cpu;
74unsigned int show_pkg_only; 66unsigned int show_pkg_only;
75unsigned int show_core_only; 67unsigned int show_core_only;
76char *output_buffer, *outp; 68char *output_buffer, *outp;
69unsigned int do_rapl;
70unsigned int do_dts;
71unsigned int do_ptm;
72unsigned int tcc_activation_temp;
73unsigned int tcc_activation_temp_override;
74double rapl_power_units, rapl_energy_units, rapl_time_units;
75double rapl_joule_counter_range;
76
77#define RAPL_PKG (1 << 0)
78#define RAPL_CORES (1 << 1)
79#define RAPL_GFX (1 << 2)
80#define RAPL_DRAM (1 << 3)
81#define RAPL_PKG_PERF_STATUS (1 << 4)
82#define RAPL_DRAM_PERF_STATUS (1 << 5)
83#define TJMAX_DEFAULT 100
84
85#define MAX(a, b) ((a) > (b) ? (a) : (b))
77 86
78int aperf_mperf_unstable; 87int aperf_mperf_unstable;
79int backwards_count; 88int backwards_count;
@@ -91,6 +100,7 @@ struct thread_data {
91 unsigned long long extra_delta64; 100 unsigned long long extra_delta64;
92 unsigned long long extra_msr32; 101 unsigned long long extra_msr32;
93 unsigned long long extra_delta32; 102 unsigned long long extra_delta32;
103 unsigned int smi_count;
94 unsigned int cpu_id; 104 unsigned int cpu_id;
95 unsigned int flags; 105 unsigned int flags;
96#define CPU_IS_FIRST_THREAD_IN_CORE 0x2 106#define CPU_IS_FIRST_THREAD_IN_CORE 0x2
@@ -101,6 +111,7 @@ struct core_data {
101 unsigned long long c3; 111 unsigned long long c3;
102 unsigned long long c6; 112 unsigned long long c6;
103 unsigned long long c7; 113 unsigned long long c7;
114 unsigned int core_temp_c;
104 unsigned int core_id; 115 unsigned int core_id;
105} *core_even, *core_odd; 116} *core_even, *core_odd;
106 117
@@ -110,6 +121,14 @@ struct pkg_data {
110 unsigned long long pc6; 121 unsigned long long pc6;
111 unsigned long long pc7; 122 unsigned long long pc7;
112 unsigned int package_id; 123 unsigned int package_id;
124 unsigned int energy_pkg; /* MSR_PKG_ENERGY_STATUS */
125 unsigned int energy_dram; /* MSR_DRAM_ENERGY_STATUS */
126 unsigned int energy_cores; /* MSR_PP0_ENERGY_STATUS */
127 unsigned int energy_gfx; /* MSR_PP1_ENERGY_STATUS */
128 unsigned int rapl_pkg_perf_status; /* MSR_PKG_PERF_STATUS */
129 unsigned int rapl_dram_perf_status; /* MSR_DRAM_PERF_STATUS */
130 unsigned int pkg_temp_c;
131
113} *package_even, *package_odd; 132} *package_even, *package_odd;
114 133
115#define ODD_COUNTERS thread_odd, core_odd, package_odd 134#define ODD_COUNTERS thread_odd, core_odd, package_odd
@@ -206,8 +225,10 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
206 retval = pread(fd, msr, sizeof *msr, offset); 225 retval = pread(fd, msr, sizeof *msr, offset);
207 close(fd); 226 close(fd);
208 227
209 if (retval != sizeof *msr) 228 if (retval != sizeof *msr) {
229 fprintf(stderr, "%s offset 0x%zx read failed\n", pathname, offset);
210 return -1; 230 return -1;
231 }
211 232
212 return 0; 233 return 0;
213} 234}
@@ -229,6 +250,8 @@ void print_header(void)
229 if (has_aperf) 250 if (has_aperf)
230 outp += sprintf(outp, " GHz"); 251 outp += sprintf(outp, " GHz");
231 outp += sprintf(outp, " TSC"); 252 outp += sprintf(outp, " TSC");
253 if (do_smi)
254 outp += sprintf(outp, " SMI");
232 if (extra_delta_offset32) 255 if (extra_delta_offset32)
233 outp += sprintf(outp, " count 0x%03X", extra_delta_offset32); 256 outp += sprintf(outp, " count 0x%03X", extra_delta_offset32);
234 if (extra_delta_offset64) 257 if (extra_delta_offset64)
@@ -245,6 +268,12 @@ void print_header(void)
245 outp += sprintf(outp, " %%c6"); 268 outp += sprintf(outp, " %%c6");
246 if (do_snb_cstates) 269 if (do_snb_cstates)
247 outp += sprintf(outp, " %%c7"); 270 outp += sprintf(outp, " %%c7");
271
272 if (do_dts)
273 outp += sprintf(outp, " CTMP");
274 if (do_ptm)
275 outp += sprintf(outp, " PTMP");
276
248 if (do_snb_cstates) 277 if (do_snb_cstates)
249 outp += sprintf(outp, " %%pc2"); 278 outp += sprintf(outp, " %%pc2");
250 if (do_nhm_cstates) 279 if (do_nhm_cstates)
@@ -254,6 +283,19 @@ void print_header(void)
254 if (do_snb_cstates) 283 if (do_snb_cstates)
255 outp += sprintf(outp, " %%pc7"); 284 outp += sprintf(outp, " %%pc7");
256 285
286 if (do_rapl & RAPL_PKG)
287 outp += sprintf(outp, " Pkg_W");
288 if (do_rapl & RAPL_CORES)
289 outp += sprintf(outp, " Cor_W");
290 if (do_rapl & RAPL_GFX)
291 outp += sprintf(outp, " GFX_W");
292 if (do_rapl & RAPL_DRAM)
293 outp += sprintf(outp, " RAM_W");
294 if (do_rapl & RAPL_PKG_PERF_STATUS)
295 outp += sprintf(outp, " PKG_%%");
296 if (do_rapl & RAPL_DRAM_PERF_STATUS)
297 outp += sprintf(outp, " RAM_%%");
298
257 outp += sprintf(outp, "\n"); 299 outp += sprintf(outp, "\n");
258} 300}
259 301
@@ -276,6 +318,8 @@ int dump_counters(struct thread_data *t, struct core_data *c,
276 extra_msr_offset32, t->extra_msr32); 318 extra_msr_offset32, t->extra_msr32);
277 fprintf(stderr, "msr0x%x: %016llX\n", 319 fprintf(stderr, "msr0x%x: %016llX\n",
278 extra_msr_offset64, t->extra_msr64); 320 extra_msr_offset64, t->extra_msr64);
321 if (do_smi)
322 fprintf(stderr, "SMI: %08X\n", t->smi_count);
279 } 323 }
280 324
281 if (c) { 325 if (c) {
@@ -283,6 +327,7 @@ int dump_counters(struct thread_data *t, struct core_data *c,
283 fprintf(stderr, "c3: %016llX\n", c->c3); 327 fprintf(stderr, "c3: %016llX\n", c->c3);
284 fprintf(stderr, "c6: %016llX\n", c->c6); 328 fprintf(stderr, "c6: %016llX\n", c->c6);
285 fprintf(stderr, "c7: %016llX\n", c->c7); 329 fprintf(stderr, "c7: %016llX\n", c->c7);
330 fprintf(stderr, "DTS: %dC\n", c->core_temp_c);
286 } 331 }
287 332
288 if (p) { 333 if (p) {
@@ -291,6 +336,13 @@ int dump_counters(struct thread_data *t, struct core_data *c,
291 fprintf(stderr, "pc3: %016llX\n", p->pc3); 336 fprintf(stderr, "pc3: %016llX\n", p->pc3);
292 fprintf(stderr, "pc6: %016llX\n", p->pc6); 337 fprintf(stderr, "pc6: %016llX\n", p->pc6);
293 fprintf(stderr, "pc7: %016llX\n", p->pc7); 338 fprintf(stderr, "pc7: %016llX\n", p->pc7);
339 fprintf(stderr, "Joules PKG: %0X\n", p->energy_pkg);
340 fprintf(stderr, "Joules COR: %0X\n", p->energy_cores);
341 fprintf(stderr, "Joules GFX: %0X\n", p->energy_gfx);
342 fprintf(stderr, "Joules RAM: %0X\n", p->energy_dram);
343 fprintf(stderr, "Throttle PKG: %0X\n", p->rapl_pkg_perf_status);
344 fprintf(stderr, "Throttle RAM: %0X\n", p->rapl_dram_perf_status);
345 fprintf(stderr, "PTM: %dC\n", p->pkg_temp_c);
294 } 346 }
295 return 0; 347 return 0;
296} 348}
@@ -300,14 +352,22 @@ int dump_counters(struct thread_data *t, struct core_data *c,
300 * package: "pk" 2 columns %2d 352 * package: "pk" 2 columns %2d
301 * core: "cor" 3 columns %3d 353 * core: "cor" 3 columns %3d
302 * CPU: "CPU" 3 columns %3d 354 * CPU: "CPU" 3 columns %3d
355 * Pkg_W: %6.2
356 * Cor_W: %6.2
357 * GFX_W: %5.2
358 * RAM_W: %5.2
303 * GHz: "GHz" 3 columns %3.2 359 * GHz: "GHz" 3 columns %3.2
304 * TSC: "TSC" 3 columns %3.2 360 * TSC: "TSC" 3 columns %3.2
361 * SMI: "SMI" 4 columns %4d
305 * percentage " %pc3" %6.2 362 * percentage " %pc3" %6.2
363 * Perf Status percentage: %5.2
364 * "CTMP" 4 columns %4d
306 */ 365 */
307int format_counters(struct thread_data *t, struct core_data *c, 366int format_counters(struct thread_data *t, struct core_data *c,
308 struct pkg_data *p) 367 struct pkg_data *p)
309{ 368{
310 double interval_float; 369 double interval_float;
370 char *fmt5, *fmt6;
311 371
312 /* if showing only 1st thread in core and this isn't one, bail out */ 372 /* if showing only 1st thread in core and this isn't one, bail out */
313 if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) 373 if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
@@ -347,7 +407,6 @@ int format_counters(struct thread_data *t, struct core_data *c,
347 if (show_cpu) 407 if (show_cpu)
348 outp += sprintf(outp, " %3d", t->cpu_id); 408 outp += sprintf(outp, " %3d", t->cpu_id);
349 } 409 }
350
351 /* %c0 */ 410 /* %c0 */
352 if (do_nhm_cstates) { 411 if (do_nhm_cstates) {
353 if (show_pkg || show_core || show_cpu) 412 if (show_pkg || show_core || show_cpu)
@@ -379,6 +438,10 @@ int format_counters(struct thread_data *t, struct core_data *c,
379 /* TSC */ 438 /* TSC */
380 outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); 439 outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float);
381 440
441 /* SMI */
442 if (do_smi)
443 outp += sprintf(outp, "%4d", t->smi_count);
444
382 /* delta */ 445 /* delta */
383 if (extra_delta_offset32) 446 if (extra_delta_offset32)
384 outp += sprintf(outp, " %11llu", t->extra_delta32); 447 outp += sprintf(outp, " %11llu", t->extra_delta32);
@@ -412,10 +475,16 @@ int format_counters(struct thread_data *t, struct core_data *c,
412 if (do_snb_cstates) 475 if (do_snb_cstates)
413 outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc); 476 outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc);
414 477
478 if (do_dts)
479 outp += sprintf(outp, " %4d", c->core_temp_c);
480
415 /* print per-package data only for 1st core in package */ 481 /* print per-package data only for 1st core in package */
416 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) 482 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
417 goto done; 483 goto done;
418 484
485 if (do_ptm)
486 outp += sprintf(outp, " %4d", p->pkg_temp_c);
487
419 if (do_snb_cstates) 488 if (do_snb_cstates)
420 outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc); 489 outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc);
421 if (do_nhm_cstates) 490 if (do_nhm_cstates)
@@ -424,6 +493,32 @@ int format_counters(struct thread_data *t, struct core_data *c,
424 outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc); 493 outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc);
425 if (do_snb_cstates) 494 if (do_snb_cstates)
426 outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc); 495 outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc);
496
497 /*
498 * If measurement interval exceeds minimum RAPL Joule Counter range,
499 * indicate that results are suspect by printing "**" in fraction place.
500 */
501 if (interval_float < rapl_joule_counter_range) {
502 fmt5 = " %5.2f";
503 fmt6 = " %6.2f";
504 } else {
505 fmt5 = " %3.0f**";
506 fmt6 = " %4.0f**";
507 }
508
509 if (do_rapl & RAPL_PKG)
510 outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float);
511 if (do_rapl & RAPL_CORES)
512 outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float);
513 if (do_rapl & RAPL_GFX)
514 outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float);
515 if (do_rapl & RAPL_DRAM)
516 outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float);
517 if (do_rapl & RAPL_PKG_PERF_STATUS )
518 outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float);
519 if (do_rapl & RAPL_DRAM_PERF_STATUS )
520 outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float);
521
427done: 522done:
428 outp += sprintf(outp, "\n"); 523 outp += sprintf(outp, "\n");
429 524
@@ -433,6 +528,7 @@ done:
433void flush_stdout() 528void flush_stdout()
434{ 529{
435 fputs(output_buffer, stdout); 530 fputs(output_buffer, stdout);
531 fflush(stdout);
436 outp = output_buffer; 532 outp = output_buffer;
437} 533}
438void flush_stderr() 534void flush_stderr()
@@ -459,6 +555,13 @@ void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_
459 for_all_cpus(format_counters, t, c, p); 555 for_all_cpus(format_counters, t, c, p);
460} 556}
461 557
558#define DELTA_WRAP32(new, old) \
559 if (new > old) { \
560 old = new - old; \
561 } else { \
562 old = 0x100000000 + new - old; \
563 }
564
462void 565void
463delta_package(struct pkg_data *new, struct pkg_data *old) 566delta_package(struct pkg_data *new, struct pkg_data *old)
464{ 567{
@@ -466,6 +569,14 @@ delta_package(struct pkg_data *new, struct pkg_data *old)
466 old->pc3 = new->pc3 - old->pc3; 569 old->pc3 = new->pc3 - old->pc3;
467 old->pc6 = new->pc6 - old->pc6; 570 old->pc6 = new->pc6 - old->pc6;
468 old->pc7 = new->pc7 - old->pc7; 571 old->pc7 = new->pc7 - old->pc7;
572 old->pkg_temp_c = new->pkg_temp_c;
573
574 DELTA_WRAP32(new->energy_pkg, old->energy_pkg);
575 DELTA_WRAP32(new->energy_cores, old->energy_cores);
576 DELTA_WRAP32(new->energy_gfx, old->energy_gfx);
577 DELTA_WRAP32(new->energy_dram, old->energy_dram);
578 DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status);
579 DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status);
469} 580}
470 581
471void 582void
@@ -474,6 +585,7 @@ delta_core(struct core_data *new, struct core_data *old)
474 old->c3 = new->c3 - old->c3; 585 old->c3 = new->c3 - old->c3;
475 old->c6 = new->c6 - old->c6; 586 old->c6 = new->c6 - old->c6;
476 old->c7 = new->c7 - old->c7; 587 old->c7 = new->c7 - old->c7;
588 old->core_temp_c = new->core_temp_c;
477} 589}
478 590
479/* 591/*
@@ -544,6 +656,9 @@ delta_thread(struct thread_data *new, struct thread_data *old,
544 */ 656 */
545 old->extra_msr32 = new->extra_msr32; 657 old->extra_msr32 = new->extra_msr32;
546 old->extra_msr64 = new->extra_msr64; 658 old->extra_msr64 = new->extra_msr64;
659
660 if (do_smi)
661 old->smi_count = new->smi_count - old->smi_count;
547} 662}
548 663
549int delta_cpu(struct thread_data *t, struct core_data *c, 664int delta_cpu(struct thread_data *t, struct core_data *c,
@@ -571,6 +686,7 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
571 t->mperf = 0; 686 t->mperf = 0;
572 t->c1 = 0; 687 t->c1 = 0;
573 688
689 t->smi_count = 0;
574 t->extra_delta32 = 0; 690 t->extra_delta32 = 0;
575 t->extra_delta64 = 0; 691 t->extra_delta64 = 0;
576 692
@@ -580,11 +696,20 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
580 c->c3 = 0; 696 c->c3 = 0;
581 c->c6 = 0; 697 c->c6 = 0;
582 c->c7 = 0; 698 c->c7 = 0;
699 c->core_temp_c = 0;
583 700
584 p->pc2 = 0; 701 p->pc2 = 0;
585 p->pc3 = 0; 702 p->pc3 = 0;
586 p->pc6 = 0; 703 p->pc6 = 0;
587 p->pc7 = 0; 704 p->pc7 = 0;
705
706 p->energy_pkg = 0;
707 p->energy_dram = 0;
708 p->energy_cores = 0;
709 p->energy_gfx = 0;
710 p->rapl_pkg_perf_status = 0;
711 p->rapl_dram_perf_status = 0;
712 p->pkg_temp_c = 0;
588} 713}
589int sum_counters(struct thread_data *t, struct core_data *c, 714int sum_counters(struct thread_data *t, struct core_data *c,
590 struct pkg_data *p) 715 struct pkg_data *p)
@@ -605,6 +730,8 @@ int sum_counters(struct thread_data *t, struct core_data *c,
605 average.cores.c6 += c->c6; 730 average.cores.c6 += c->c6;
606 average.cores.c7 += c->c7; 731 average.cores.c7 += c->c7;
607 732
733 average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c);
734
608 /* sum per-pkg values only for 1st core in pkg */ 735 /* sum per-pkg values only for 1st core in pkg */
609 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) 736 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
610 return 0; 737 return 0;
@@ -614,6 +741,15 @@ int sum_counters(struct thread_data *t, struct core_data *c,
614 average.packages.pc6 += p->pc6; 741 average.packages.pc6 += p->pc6;
615 average.packages.pc7 += p->pc7; 742 average.packages.pc7 += p->pc7;
616 743
744 average.packages.energy_pkg += p->energy_pkg;
745 average.packages.energy_dram += p->energy_dram;
746 average.packages.energy_cores += p->energy_cores;
747 average.packages.energy_gfx += p->energy_gfx;
748
749 average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c);
750
751 average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status;
752 average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status;
617 return 0; 753 return 0;
618} 754}
619/* 755/*
@@ -665,23 +801,31 @@ static unsigned long long rdtsc(void)
665int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) 801int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
666{ 802{
667 int cpu = t->cpu_id; 803 int cpu = t->cpu_id;
804 unsigned long long msr;
668 805
669 if (cpu_migrate(cpu)) 806 if (cpu_migrate(cpu)) {
807 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
670 return -1; 808 return -1;
809 }
671 810
672 t->tsc = rdtsc(); /* we are running on local CPU of interest */ 811 t->tsc = rdtsc(); /* we are running on local CPU of interest */
673 812
674 if (has_aperf) { 813 if (has_aperf) {
675 if (get_msr(cpu, MSR_APERF, &t->aperf)) 814 if (get_msr(cpu, MSR_IA32_APERF, &t->aperf))
676 return -3; 815 return -3;
677 if (get_msr(cpu, MSR_MPERF, &t->mperf)) 816 if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf))
678 return -4; 817 return -4;
679 } 818 }
680 819
820 if (do_smi) {
821 if (get_msr(cpu, MSR_SMI_COUNT, &msr))
822 return -5;
823 t->smi_count = msr & 0xFFFFFFFF;
824 }
681 if (extra_delta_offset32) { 825 if (extra_delta_offset32) {
682 if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32)) 826 if (get_msr(cpu, extra_delta_offset32, &msr))
683 return -5; 827 return -5;
684 t->extra_delta32 &= 0xFFFFFFFF; 828 t->extra_delta32 = msr & 0xFFFFFFFF;
685 } 829 }
686 830
687 if (extra_delta_offset64) 831 if (extra_delta_offset64)
@@ -689,9 +833,9 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
689 return -5; 833 return -5;
690 834
691 if (extra_msr_offset32) { 835 if (extra_msr_offset32) {
692 if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32)) 836 if (get_msr(cpu, extra_msr_offset32, &msr))
693 return -5; 837 return -5;
694 t->extra_msr32 &= 0xFFFFFFFF; 838 t->extra_msr32 = msr & 0xFFFFFFFF;
695 } 839 }
696 840
697 if (extra_msr_offset64) 841 if (extra_msr_offset64)
@@ -713,6 +857,13 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
713 if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7)) 857 if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
714 return -8; 858 return -8;
715 859
860 if (do_dts) {
861 if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
862 return -9;
863 c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
864 }
865
866
716 /* collect package counters only for 1st core in package */ 867 /* collect package counters only for 1st core in package */
717 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) 868 if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
718 return 0; 869 return 0;
@@ -729,6 +880,41 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
729 if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7)) 880 if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7))
730 return -12; 881 return -12;
731 } 882 }
883 if (do_rapl & RAPL_PKG) {
884 if (get_msr(cpu, MSR_PKG_ENERGY_STATUS, &msr))
885 return -13;
886 p->energy_pkg = msr & 0xFFFFFFFF;
887 }
888 if (do_rapl & RAPL_CORES) {
889 if (get_msr(cpu, MSR_PP0_ENERGY_STATUS, &msr))
890 return -14;
891 p->energy_cores = msr & 0xFFFFFFFF;
892 }
893 if (do_rapl & RAPL_DRAM) {
894 if (get_msr(cpu, MSR_DRAM_ENERGY_STATUS, &msr))
895 return -15;
896 p->energy_dram = msr & 0xFFFFFFFF;
897 }
898 if (do_rapl & RAPL_GFX) {
899 if (get_msr(cpu, MSR_PP1_ENERGY_STATUS, &msr))
900 return -16;
901 p->energy_gfx = msr & 0xFFFFFFFF;
902 }
903 if (do_rapl & RAPL_PKG_PERF_STATUS) {
904 if (get_msr(cpu, MSR_PKG_PERF_STATUS, &msr))
905 return -16;
906 p->rapl_pkg_perf_status = msr & 0xFFFFFFFF;
907 }
908 if (do_rapl & RAPL_DRAM_PERF_STATUS) {
909 if (get_msr(cpu, MSR_DRAM_PERF_STATUS, &msr))
910 return -16;
911 p->rapl_dram_perf_status = msr & 0xFFFFFFFF;
912 }
913 if (do_ptm) {
914 if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
915 return -17;
916 p->pkg_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
917 }
732 return 0; 918 return 0;
733} 919}
734 920
@@ -740,10 +926,9 @@ void print_verbose_header(void)
740 if (!do_nehalem_platform_info) 926 if (!do_nehalem_platform_info)
741 return; 927 return;
742 928
743 get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr); 929 get_msr(0, MSR_NHM_PLATFORM_INFO, &msr);
744 930
745 if (verbose > 1) 931 fprintf(stderr, "cpu0: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", msr);
746 fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
747 932
748 ratio = (msr >> 40) & 0xFF; 933 ratio = (msr >> 40) & 0xFF;
749 fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", 934 fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
@@ -753,13 +938,16 @@ void print_verbose_header(void)
753 fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n", 938 fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n",
754 ratio, bclk, ratio * bclk); 939 ratio, bclk, ratio * bclk);
755 940
941 get_msr(0, MSR_IA32_POWER_CTL, &msr);
942 fprintf(stderr, "cpu0: MSR_IA32_POWER_CTL: 0x%08llx (C1E: %sabled)\n",
943 msr, msr & 0x2 ? "EN" : "DIS");
944
756 if (!do_ivt_turbo_ratio_limit) 945 if (!do_ivt_turbo_ratio_limit)
757 goto print_nhm_turbo_ratio_limits; 946 goto print_nhm_turbo_ratio_limits;
758 947
759 get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr); 948 get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr);
760 949
761 if (verbose > 1) 950 fprintf(stderr, "cpu0: MSR_IVT_TURBO_RATIO_LIMIT: 0x%08llx\n", msr);
762 fprintf(stderr, "MSR_IVT_TURBO_RATIO_LIMIT: 0x%llx\n", msr);
763 951
764 ratio = (msr >> 56) & 0xFF; 952 ratio = (msr >> 56) & 0xFF;
765 if (ratio) 953 if (ratio)
@@ -802,14 +990,55 @@ void print_verbose_header(void)
802 ratio, bclk, ratio * bclk); 990 ratio, bclk, ratio * bclk);
803 991
804print_nhm_turbo_ratio_limits: 992print_nhm_turbo_ratio_limits:
993 get_msr(0, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
994
995#define SNB_C1_AUTO_UNDEMOTE (1UL << 27)
996#define SNB_C3_AUTO_UNDEMOTE (1UL << 28)
997
998 fprintf(stderr, "cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", msr);
999
1000 fprintf(stderr, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: ",
1001 (msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "",
1002 (msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "",
1003 (msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "",
1004 (msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "",
1005 (msr & (1 << 15)) ? "" : "UN",
1006 (unsigned int)msr & 7);
1007
1008
1009 switch(msr & 0x7) {
1010 case 0:
1011 fprintf(stderr, "pc0");
1012 break;
1013 case 1:
1014 fprintf(stderr, do_snb_cstates ? "pc2" : "pc0");
1015 break;
1016 case 2:
1017 fprintf(stderr, do_snb_cstates ? "pc6-noret" : "pc3");
1018 break;
1019 case 3:
1020 fprintf(stderr, "pc6");
1021 break;
1022 case 4:
1023 fprintf(stderr, "pc7");
1024 break;
1025 case 5:
1026 fprintf(stderr, do_snb_cstates ? "pc7s" : "invalid");
1027 break;
1028 case 7:
1029 fprintf(stderr, "unlimited");
1030 break;
1031 default:
1032 fprintf(stderr, "invalid");
1033 }
1034 fprintf(stderr, ")\n");
805 1035
806 if (!do_nehalem_turbo_ratio_limit) 1036 if (!do_nehalem_turbo_ratio_limit)
807 return; 1037 return;
808 1038
809 get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr); 1039 get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr);
810 1040
811 if (verbose > 1) 1041 fprintf(stderr, "cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x%08llx\n", msr);
812 fprintf(stderr, "MSR_NEHALEM_TURBO_RATIO_LIMIT: 0x%llx\n", msr);
813 1042
814 ratio = (msr >> 56) & 0xFF; 1043 ratio = (msr >> 56) & 0xFF;
815 if (ratio) 1044 if (ratio)
@@ -1098,13 +1327,22 @@ int mark_cpu_present(int cpu)
1098void turbostat_loop() 1327void turbostat_loop()
1099{ 1328{
1100 int retval; 1329 int retval;
1330 int restarted = 0;
1101 1331
1102restart: 1332restart:
1333 restarted++;
1334
1103 retval = for_all_cpus(get_counters, EVEN_COUNTERS); 1335 retval = for_all_cpus(get_counters, EVEN_COUNTERS);
1104 if (retval) { 1336 if (retval < -1) {
1337 exit(retval);
1338 } else if (retval == -1) {
1339 if (restarted > 1) {
1340 exit(retval);
1341 }
1105 re_initialize(); 1342 re_initialize();
1106 goto restart; 1343 goto restart;
1107 } 1344 }
1345 restarted = 0;
1108 gettimeofday(&tv_even, (struct timezone *)NULL); 1346 gettimeofday(&tv_even, (struct timezone *)NULL);
1109 1347
1110 while (1) { 1348 while (1) {
@@ -1114,7 +1352,9 @@ restart:
1114 } 1352 }
1115 sleep(interval_sec); 1353 sleep(interval_sec);
1116 retval = for_all_cpus(get_counters, ODD_COUNTERS); 1354 retval = for_all_cpus(get_counters, ODD_COUNTERS);
1117 if (retval) { 1355 if (retval < -1) {
1356 exit(retval);
1357 } else if (retval == -1) {
1118 re_initialize(); 1358 re_initialize();
1119 goto restart; 1359 goto restart;
1120 } 1360 }
@@ -1126,7 +1366,9 @@ restart:
1126 flush_stdout(); 1366 flush_stdout();
1127 sleep(interval_sec); 1367 sleep(interval_sec);
1128 retval = for_all_cpus(get_counters, EVEN_COUNTERS); 1368 retval = for_all_cpus(get_counters, EVEN_COUNTERS);
1129 if (retval) { 1369 if (retval < -1) {
1370 exit(retval);
1371 } else if (retval == -1) {
1130 re_initialize(); 1372 re_initialize();
1131 goto restart; 1373 goto restart;
1132 } 1374 }
@@ -1176,6 +1418,9 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
1176 case 0x2D: /* SNB Xeon */ 1418 case 0x2D: /* SNB Xeon */
1177 case 0x3A: /* IVB */ 1419 case 0x3A: /* IVB */
1178 case 0x3E: /* IVB Xeon */ 1420 case 0x3E: /* IVB Xeon */
1421 case 0x3C: /* HSW */
1422 case 0x3F: /* HSW */
1423 case 0x45: /* HSW */
1179 return 1; 1424 return 1;
1180 case 0x2E: /* Nehalem-EX Xeon - Beckton */ 1425 case 0x2E: /* Nehalem-EX Xeon - Beckton */
1181 case 0x2F: /* Westmere-EX Xeon - Eagleton */ 1426 case 0x2F: /* Westmere-EX Xeon - Eagleton */
@@ -1199,6 +1444,302 @@ int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model)
1199 } 1444 }
1200} 1445}
1201 1446
1447/*
1448 * print_epb()
1449 * Decode the ENERGY_PERF_BIAS MSR
1450 */
1451int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1452{
1453 unsigned long long msr;
1454 char *epb_string;
1455 int cpu;
1456
1457 if (!has_epb)
1458 return 0;
1459
1460 cpu = t->cpu_id;
1461
1462 /* EPB is per-package */
1463 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1464 return 0;
1465
1466 if (cpu_migrate(cpu)) {
1467 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
1468 return -1;
1469 }
1470
1471 if (get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr))
1472 return 0;
1473
1474 switch (msr & 0x7) {
1475 case ENERGY_PERF_BIAS_PERFORMANCE:
1476 epb_string = "performance";
1477 break;
1478 case ENERGY_PERF_BIAS_NORMAL:
1479 epb_string = "balanced";
1480 break;
1481 case ENERGY_PERF_BIAS_POWERSAVE:
1482 epb_string = "powersave";
1483 break;
1484 default:
1485 epb_string = "custom";
1486 break;
1487 }
1488 fprintf(stderr, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string);
1489
1490 return 0;
1491}
1492
1493#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */
1494#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */
1495
1496/*
1497 * rapl_probe()
1498 *
1499 * sets do_rapl
1500 */
1501void rapl_probe(unsigned int family, unsigned int model)
1502{
1503 unsigned long long msr;
1504 double tdp;
1505
1506 if (!genuine_intel)
1507 return;
1508
1509 if (family != 6)
1510 return;
1511
1512 switch (model) {
1513 case 0x2A:
1514 case 0x3A:
1515 case 0x3C: /* HSW */
1516 case 0x3F: /* HSW */
1517 case 0x45: /* HSW */
1518 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX;
1519 break;
1520 case 0x2D:
1521 case 0x3E:
1522 do_rapl = RAPL_PKG | RAPL_CORES | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS;
1523 break;
1524 default:
1525 return;
1526 }
1527
1528 /* units on package 0, verify later other packages match */
1529 if (get_msr(0, MSR_RAPL_POWER_UNIT, &msr))
1530 return;
1531
1532 rapl_power_units = 1.0 / (1 << (msr & 0xF));
1533 rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
1534 rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF));
1535
1536 /* get TDP to determine energy counter range */
1537 if (get_msr(0, MSR_PKG_POWER_INFO, &msr))
1538 return;
1539
1540 tdp = ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units;
1541
1542 rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
1543
1544 if (verbose)
1545 fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range\n", rapl_joule_counter_range);
1546
1547 return;
1548}
1549
1550int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1551{
1552 unsigned long long msr;
1553 unsigned int dts;
1554 int cpu;
1555
1556 if (!(do_dts || do_ptm))
1557 return 0;
1558
1559 cpu = t->cpu_id;
1560
1561 /* DTS is per-core, no need to print for each thread */
1562 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
1563 return 0;
1564
1565 if (cpu_migrate(cpu)) {
1566 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
1567 return -1;
1568 }
1569
1570 if (do_ptm && (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) {
1571 if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
1572 return 0;
1573
1574 dts = (msr >> 16) & 0x7F;
1575 fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n",
1576 cpu, msr, tcc_activation_temp - dts);
1577
1578#ifdef THERM_DEBUG
1579 if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr))
1580 return 0;
1581
1582 dts = (msr >> 16) & 0x7F;
1583 dts2 = (msr >> 8) & 0x7F;
1584 fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
1585 cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
1586#endif
1587 }
1588
1589
1590 if (do_dts) {
1591 unsigned int resolution;
1592
1593 if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr))
1594 return 0;
1595
1596 dts = (msr >> 16) & 0x7F;
1597 resolution = (msr >> 27) & 0xF;
1598 fprintf(stderr, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n",
1599 cpu, msr, tcc_activation_temp - dts, resolution);
1600
1601#ifdef THERM_DEBUG
1602 if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr))
1603 return 0;
1604
1605 dts = (msr >> 16) & 0x7F;
1606 dts2 = (msr >> 8) & 0x7F;
1607 fprintf(stderr, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n",
1608 cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2);
1609#endif
1610 }
1611
1612 return 0;
1613}
1614
1615void print_power_limit_msr(int cpu, unsigned long long msr, char *label)
1616{
1617 fprintf(stderr, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n",
1618 cpu, label,
1619 ((msr >> 15) & 1) ? "EN" : "DIS",
1620 ((msr >> 0) & 0x7FFF) * rapl_power_units,
1621 (1.0 + (((msr >> 22) & 0x3)/4.0)) * (1 << ((msr >> 17) & 0x1F)) * rapl_time_units,
1622 (((msr >> 16) & 1) ? "EN" : "DIS"));
1623
1624 return;
1625}
1626
1627int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1628{
1629 unsigned long long msr;
1630 int cpu;
1631 double local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units;
1632
1633 if (!do_rapl)
1634 return 0;
1635
1636 /* RAPL counters are per package, so print only for 1st thread/package */
1637 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1638 return 0;
1639
1640 cpu = t->cpu_id;
1641 if (cpu_migrate(cpu)) {
1642 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
1643 return -1;
1644 }
1645
1646 if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))
1647 return -1;
1648
1649 local_rapl_power_units = 1.0 / (1 << (msr & 0xF));
1650 local_rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
1651 local_rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF));
1652
1653 if (local_rapl_power_units != rapl_power_units)
1654 fprintf(stderr, "cpu%d, ERROR: Power units mis-match\n", cpu);
1655 if (local_rapl_energy_units != rapl_energy_units)
1656 fprintf(stderr, "cpu%d, ERROR: Energy units mis-match\n", cpu);
1657 if (local_rapl_time_units != rapl_time_units)
1658 fprintf(stderr, "cpu%d, ERROR: Time units mis-match\n", cpu);
1659
1660 if (verbose) {
1661 fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx "
1662 "(%f Watts, %f Joules, %f sec.)\n", cpu, msr,
1663 local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units);
1664 }
1665 if (do_rapl & RAPL_PKG) {
1666 if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr))
1667 return -5;
1668
1669
1670 fprintf(stderr, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
1671 cpu, msr,
1672 ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1673 ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1674 ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1675 ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
1676
1677 if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr))
1678 return -9;
1679
1680 fprintf(stderr, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n",
1681 cpu, msr, (msr >> 63) & 1 ? "": "UN");
1682
1683 print_power_limit_msr(cpu, msr, "PKG Limit #1");
1684 fprintf(stderr, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n",
1685 cpu,
1686 ((msr >> 47) & 1) ? "EN" : "DIS",
1687 ((msr >> 32) & 0x7FFF) * rapl_power_units,
1688 (1.0 + (((msr >> 54) & 0x3)/4.0)) * (1 << ((msr >> 49) & 0x1F)) * rapl_time_units,
1689 ((msr >> 48) & 1) ? "EN" : "DIS");
1690 }
1691
1692 if (do_rapl & RAPL_DRAM) {
1693 if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr))
1694 return -6;
1695
1696
1697 fprintf(stderr, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n",
1698 cpu, msr,
1699 ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1700 ((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1701 ((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units,
1702 ((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units);
1703
1704
1705 if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr))
1706 return -9;
1707 fprintf(stderr, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n",
1708 cpu, msr, (msr >> 31) & 1 ? "": "UN");
1709
1710 print_power_limit_msr(cpu, msr, "DRAM Limit");
1711 }
1712 if (do_rapl & RAPL_CORES) {
1713 if (verbose) {
1714 if (get_msr(cpu, MSR_PP0_POLICY, &msr))
1715 return -7;
1716
1717 fprintf(stderr, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF);
1718
1719 if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr))
1720 return -9;
1721 fprintf(stderr, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n",
1722 cpu, msr, (msr >> 31) & 1 ? "": "UN");
1723 print_power_limit_msr(cpu, msr, "Cores Limit");
1724 }
1725 }
1726 if (do_rapl & RAPL_GFX) {
1727 if (verbose) {
1728 if (get_msr(cpu, MSR_PP1_POLICY, &msr))
1729 return -8;
1730
1731 fprintf(stderr, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF);
1732
1733 if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr))
1734 return -9;
1735 fprintf(stderr, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n",
1736 cpu, msr, (msr >> 31) & 1 ? "": "UN");
1737 print_power_limit_msr(cpu, msr, "GFX Limit");
1738 }
1739 }
1740 return 0;
1741}
1742
1202 1743
1203int is_snb(unsigned int family, unsigned int model) 1744int is_snb(unsigned int family, unsigned int model)
1204{ 1745{
@@ -1210,6 +1751,9 @@ int is_snb(unsigned int family, unsigned int model)
1210 case 0x2D: 1751 case 0x2D:
1211 case 0x3A: /* IVB */ 1752 case 0x3A: /* IVB */
1212 case 0x3E: /* IVB Xeon */ 1753 case 0x3E: /* IVB Xeon */
1754 case 0x3C: /* HSW */
1755 case 0x3F: /* HSW */
1756 case 0x45: /* HSW */
1213 return 1; 1757 return 1;
1214 } 1758 }
1215 return 0; 1759 return 0;
@@ -1223,6 +1767,72 @@ double discover_bclk(unsigned int family, unsigned int model)
1223 return 133.33; 1767 return 133.33;
1224} 1768}
1225 1769
1770/*
1771 * MSR_IA32_TEMPERATURE_TARGET indicates the temperature where
1772 * the Thermal Control Circuit (TCC) activates.
1773 * This is usually equal to tjMax.
1774 *
1775 * Older processors do not have this MSR, so there we guess,
1776 * but also allow cmdline over-ride with -T.
1777 *
1778 * Several MSR temperature values are in units of degrees-C
1779 * below this value, including the Digital Thermal Sensor (DTS),
1780 * Package Thermal Management Sensor (PTM), and thermal event thresholds.
1781 */
1782int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p)
1783{
1784 unsigned long long msr;
1785 unsigned int target_c_local;
1786 int cpu;
1787
1788 /* tcc_activation_temp is used only for dts or ptm */
1789 if (!(do_dts || do_ptm))
1790 return 0;
1791
1792 /* this is a per-package concept */
1793 if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
1794 return 0;
1795
1796 cpu = t->cpu_id;
1797 if (cpu_migrate(cpu)) {
1798 fprintf(stderr, "Could not migrate to CPU %d\n", cpu);
1799 return -1;
1800 }
1801
1802 if (tcc_activation_temp_override != 0) {
1803 tcc_activation_temp = tcc_activation_temp_override;
1804 fprintf(stderr, "cpu%d: Using cmdline TCC Target (%d C)\n",
1805 cpu, tcc_activation_temp);
1806 return 0;
1807 }
1808
1809 /* Temperature Target MSR is Nehalem and newer only */
1810 if (!do_nehalem_platform_info)
1811 goto guess;
1812
1813 if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr))
1814 goto guess;
1815
1816 target_c_local = (msr >> 16) & 0x7F;
1817
1818 if (verbose)
1819 fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n",
1820 cpu, msr, target_c_local);
1821
1822 if (target_c_local < 85 || target_c_local > 120)
1823 goto guess;
1824
1825 tcc_activation_temp = target_c_local;
1826
1827 return 0;
1828
1829guess:
1830 tcc_activation_temp = TJMAX_DEFAULT;
1831 fprintf(stderr, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n",
1832 cpu, tcc_activation_temp);
1833
1834 return 0;
1835}
1226void check_cpuid() 1836void check_cpuid()
1227{ 1837{
1228 unsigned int eax, ebx, ecx, edx, max_level; 1838 unsigned int eax, ebx, ecx, edx, max_level;
@@ -1236,7 +1846,7 @@ void check_cpuid()
1236 genuine_intel = 1; 1846 genuine_intel = 1;
1237 1847
1238 if (verbose) 1848 if (verbose)
1239 fprintf(stderr, "%.4s%.4s%.4s ", 1849 fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ",
1240 (char *)&ebx, (char *)&edx, (char *)&ecx); 1850 (char *)&ebx, (char *)&edx, (char *)&ecx);
1241 1851
1242 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); 1852 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
@@ -1287,24 +1897,37 @@ void check_cpuid()
1287 1897
1288 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); 1898 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
1289 has_aperf = ecx & (1 << 0); 1899 has_aperf = ecx & (1 << 0);
1290 if (!has_aperf) { 1900 do_dts = eax & (1 << 0);
1291 fprintf(stderr, "No APERF MSR\n"); 1901 do_ptm = eax & (1 << 6);
1292 exit(1); 1902 has_epb = ecx & (1 << 3);
1293 } 1903
1904 if (verbose)
1905 fprintf(stderr, "CPUID(6): %s%s%s%s\n",
1906 has_aperf ? "APERF" : "No APERF!",
1907 do_dts ? ", DTS" : "",
1908 do_ptm ? ", PTM": "",
1909 has_epb ? ", EPB": "");
1910
1911 if (!has_aperf)
1912 exit(-1);
1294 1913
1295 do_nehalem_platform_info = genuine_intel && has_invariant_tsc; 1914 do_nehalem_platform_info = genuine_intel && has_invariant_tsc;
1296 do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ 1915 do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */
1916 do_smi = do_nhm_cstates;
1297 do_snb_cstates = is_snb(family, model); 1917 do_snb_cstates = is_snb(family, model);
1298 bclk = discover_bclk(family, model); 1918 bclk = discover_bclk(family, model);
1299 1919
1300 do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); 1920 do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
1301 do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model); 1921 do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model);
1922 rapl_probe(family, model);
1923
1924 return;
1302} 1925}
1303 1926
1304 1927
1305void usage() 1928void usage()
1306{ 1929{
1307 fprintf(stderr, "%s: [-v][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", 1930 fprintf(stderr, "%s: [-v][-R][-T][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n",
1308 progname); 1931 progname);
1309 exit(1); 1932 exit(1);
1310} 1933}
@@ -1540,13 +2163,27 @@ void turbostat_init()
1540 2163
1541 if (verbose) 2164 if (verbose)
1542 print_verbose_header(); 2165 print_verbose_header();
2166
2167 if (verbose)
2168 for_all_cpus(print_epb, ODD_COUNTERS);
2169
2170 if (verbose)
2171 for_all_cpus(print_rapl, ODD_COUNTERS);
2172
2173 for_all_cpus(set_temperature_target, ODD_COUNTERS);
2174
2175 if (verbose)
2176 for_all_cpus(print_thermal, ODD_COUNTERS);
1543} 2177}
1544 2178
1545int fork_it(char **argv) 2179int fork_it(char **argv)
1546{ 2180{
1547 pid_t child_pid; 2181 pid_t child_pid;
2182 int status;
1548 2183
1549 for_all_cpus(get_counters, EVEN_COUNTERS); 2184 status = for_all_cpus(get_counters, EVEN_COUNTERS);
2185 if (status)
2186 exit(status);
1550 /* clear affinity side-effect of get_counters() */ 2187 /* clear affinity side-effect of get_counters() */
1551 sched_setaffinity(0, cpu_present_setsize, cpu_present_set); 2188 sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
1552 gettimeofday(&tv_even, (struct timezone *)NULL); 2189 gettimeofday(&tv_even, (struct timezone *)NULL);
@@ -1556,7 +2193,6 @@ int fork_it(char **argv)
1556 /* child */ 2193 /* child */
1557 execvp(argv[0], argv); 2194 execvp(argv[0], argv);
1558 } else { 2195 } else {
1559 int status;
1560 2196
1561 /* parent */ 2197 /* parent */
1562 if (child_pid == -1) { 2198 if (child_pid == -1) {
@@ -1568,7 +2204,7 @@ int fork_it(char **argv)
1568 signal(SIGQUIT, SIG_IGN); 2204 signal(SIGQUIT, SIG_IGN);
1569 if (waitpid(child_pid, &status, 0) == -1) { 2205 if (waitpid(child_pid, &status, 0) == -1) {
1570 perror("wait"); 2206 perror("wait");
1571 exit(1); 2207 exit(status);
1572 } 2208 }
1573 } 2209 }
1574 /* 2210 /*
@@ -1585,7 +2221,7 @@ int fork_it(char **argv)
1585 2221
1586 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0); 2222 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
1587 2223
1588 return 0; 2224 return status;
1589} 2225}
1590 2226
1591void cmdline(int argc, char **argv) 2227void cmdline(int argc, char **argv)
@@ -1594,7 +2230,7 @@ void cmdline(int argc, char **argv)
1594 2230
1595 progname = argv[0]; 2231 progname = argv[0];
1596 2232
1597 while ((opt = getopt(argc, argv, "+pPSvisc:sC:m:M:")) != -1) { 2233 while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:RT:")) != -1) {
1598 switch (opt) { 2234 switch (opt) {
1599 case 'p': 2235 case 'p':
1600 show_core_only++; 2236 show_core_only++;
@@ -1614,9 +2250,6 @@ void cmdline(int argc, char **argv)
1614 case 'c': 2250 case 'c':
1615 sscanf(optarg, "%x", &extra_delta_offset32); 2251 sscanf(optarg, "%x", &extra_delta_offset32);
1616 break; 2252 break;
1617 case 's':
1618 extra_delta_offset32 = 0x34; /* SMI counter */
1619 break;
1620 case 'C': 2253 case 'C':
1621 sscanf(optarg, "%x", &extra_delta_offset64); 2254 sscanf(optarg, "%x", &extra_delta_offset64);
1622 break; 2255 break;
@@ -1626,6 +2259,12 @@ void cmdline(int argc, char **argv)
1626 case 'M': 2259 case 'M':
1627 sscanf(optarg, "%x", &extra_msr_offset64); 2260 sscanf(optarg, "%x", &extra_msr_offset64);
1628 break; 2261 break;
2262 case 'R':
2263 rapl_verbose++;
2264 break;
2265 case 'T':
2266 tcc_activation_temp_override = atoi(optarg);
2267 break;
1629 default: 2268 default:
1630 usage(); 2269 usage();
1631 } 2270 }
@@ -1636,8 +2275,8 @@ int main(int argc, char **argv)
1636{ 2275{
1637 cmdline(argc, argv); 2276 cmdline(argc, argv);
1638 2277
1639 if (verbose > 1) 2278 if (verbose)
1640 fprintf(stderr, "turbostat v2.1 October 6, 2012" 2279 fprintf(stderr, "turbostat v3.2 February 11, 2013"
1641 " - Len Brown <lenb@kernel.org>\n"); 2280 " - Len Brown <lenb@kernel.org>\n");
1642 2281
1643 turbostat_init(); 2282 turbostat_init();
diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile
index f458237fdd79..971c9ffdcb50 100644
--- a/tools/power/x86/x86_energy_perf_policy/Makefile
+++ b/tools/power/x86/x86_energy_perf_policy/Makefile
@@ -1,8 +1,10 @@
1DESTDIR ?=
2
1x86_energy_perf_policy : x86_energy_perf_policy.c 3x86_energy_perf_policy : x86_energy_perf_policy.c
2 4
3clean : 5clean :
4 rm -f x86_energy_perf_policy 6 rm -f x86_energy_perf_policy
5 7
6install : 8install :
7 install x86_energy_perf_policy /usr/bin/ 9 install x86_energy_perf_policy ${DESTDIR}/usr/bin/
8 install x86_energy_perf_policy.8 /usr/share/man/man8/ 10 install x86_energy_perf_policy.8 ${DESTDIR}/usr/share/man/man8/
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
index 33c5c7ee148f..40b3e5482f8a 100644
--- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
+++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
@@ -289,7 +289,7 @@ void for_every_cpu(void (func)(int))
289 "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", 289 "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n",
290 &cpu); 290 &cpu);
291 if (retval != 1) 291 if (retval != 1)
292 return; 292 break;
293 293
294 func(cpu); 294 func(cpu);
295 } 295 }
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index 96ce80a3743b..2964b96aa55f 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -1,8 +1,11 @@
1ifeq ("$(origin O)", "command line") 1ifeq ($(origin O), command line)
2 dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) 2 dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),)
3 ABSOLUTE_O := $(shell cd $(O) ; pwd) 3 ABSOLUTE_O := $(shell cd $(O) ; pwd)
4 OUTPUT := $(ABSOLUTE_O)/ 4 OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/)
5 COMMAND_O := O=$(ABSOLUTE_O) 5 COMMAND_O := O=$(ABSOLUTE_O)
6ifeq ($(objtree),)
7 objtree := $(O)
8endif
6endif 9endif
7 10
8ifneq ($(OUTPUT),) 11ifneq ($(OUTPUT),)
@@ -41,7 +44,16 @@ else
41NO_SUBDIR = : 44NO_SUBDIR = :
42endif 45endif
43 46
44QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir 47#
48# Define a callable command for descending to a new directory
49#
50# Call by doing: $(call descend,directory[,target])
51#
52descend = \
53 +mkdir -p $(OUTPUT)$(1) && \
54 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
55
56QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir
45QUIET_SUBDIR1 = 57QUIET_SUBDIR1 =
46 58
47ifneq ($(findstring $(MAKEFLAGS),s),s) 59ifneq ($(findstring $(MAKEFLAGS),s),s)
@@ -56,5 +68,10 @@ ifndef V
56 $(MAKE) $(PRINT_DIR) -C $$subdir 68 $(MAKE) $(PRINT_DIR) -C $$subdir
57 QUIET_FLEX = @echo ' ' FLEX $@; 69 QUIET_FLEX = @echo ' ' FLEX $@;
58 QUIET_BISON = @echo ' ' BISON $@; 70 QUIET_BISON = @echo ' ' BISON $@;
71
72 descend = \
73 @echo ' ' DESCEND $(1); \
74 mkdir -p $(OUTPUT)$(1) && \
75 $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
59endif 76endif
60endif 77endif
diff --git a/tools/testing/ktest/examples/include/patchcheck.conf b/tools/testing/ktest/examples/include/patchcheck.conf
index 339d3e1700ff..0eb0a5ac77da 100644
--- a/tools/testing/ktest/examples/include/patchcheck.conf
+++ b/tools/testing/ktest/examples/include/patchcheck.conf
@@ -14,6 +14,16 @@
14PATCH_START := HEAD~3 14PATCH_START := HEAD~3
15PATCH_END := HEAD 15PATCH_END := HEAD
16 16
17# Use the oldconfig if build_type wasn't defined
18DEFAULTS IF NOT DEFINED BUILD_TYPE
19DO_BUILD_TYPE := oldconfig
20
21DEFAULTS ELSE
22DO_BUILD_TYPE := ${BUILD_TYPE}
23
24DEFAULTS
25
26
17# Change PATCH_CHECKOUT to be the branch you want to test. The test will 27# Change PATCH_CHECKOUT to be the branch you want to test. The test will
18# do a git checkout of this branch before starting. Obviously both 28# do a git checkout of this branch before starting. Obviously both
19# PATCH_START and PATCH_END must be in this branch (and PATCH_START must 29# PATCH_START and PATCH_END must be in this branch (and PATCH_START must
@@ -43,6 +53,31 @@ PATCH_TEST_TYPE := boot
43# (space delimited) 53# (space delimited)
44#IGNORE_WARNINGS = 39eaf7ef884dcc44f7ff1bac803ca2a1dcf43544 6edb2a8a385f0cdef51dae37ff23e74d76d8a6ce 54#IGNORE_WARNINGS = 39eaf7ef884dcc44f7ff1bac803ca2a1dcf43544 6edb2a8a385f0cdef51dae37ff23e74d76d8a6ce
45 55
56# Instead of just checking for warnings to files that are changed
57# it can be advantageous to check for any new warnings. If a
58# header file is changed, it could cause a warning in a file not
59# touched by the commit. To detect these kinds of warnings, you
60# can use the WARNINGS_FILE option.
61#
62# If the variable CREATE_WARNINGS_FILE is set, this config will
63# enable the WARNINGS_FILE during the patchcheck test. Also,
64# before running the patchcheck test, it will create the
65# warnings file.
66#
67DEFAULTS IF DEFINED CREATE_WARNINGS_FILE
68WARNINGS_FILE = ${OUTPUT_DIR}/warnings_file
69
70TEST_START IF DEFINED CREATE_WARNINGS_FILE
71# WARNINGS_FILE is already set by the DEFAULTS above
72TEST_TYPE = make_warnings_file
73# Checkout the commit before the patches to test,
74# and record all the warnings that exist before the patches
75# to test are added
76CHECKOUT = ${PATCHCHECK_START}~1
77# Force a full build
78BUILD_NOCLEAN = 0
79BUILD_TYPE = ${DO_BUILD_TYPE}
80
46# If you are running a multi test, and the test failed on the first 81# If you are running a multi test, and the test failed on the first
47# test but on, say the 5th patch. If you want to restart on the 82# test but on, say the 5th patch. If you want to restart on the
48# fifth patch, set PATCH_START1. This will make the first test start 83# fifth patch, set PATCH_START1. This will make the first test start
@@ -61,6 +96,7 @@ PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
61PATCHCHECK_START = ${PATCH_START1} 96PATCHCHECK_START = ${PATCH_START1}
62PATCHCHECK_END = ${PATCH_END} 97PATCHCHECK_END = ${PATCH_END}
63CHECKOUT = ${PATCH_CHECKOUT} 98CHECKOUT = ${PATCH_CHECKOUT}
99BUILD_TYPE = ${DO_BUILD_TYPE}
64 100
65TEST_START IF ${TEST} == patchcheck && ${MULTI} 101TEST_START IF ${TEST} == patchcheck && ${MULTI}
66TEST_TYPE = patchcheck 102TEST_TYPE = patchcheck
@@ -72,3 +108,4 @@ PATCHCHECK_END = ${PATCH_END}
72CHECKOUT = ${PATCH_CHECKOUT} 108CHECKOUT = ${PATCH_CHECKOUT}
73# Use multi to test different compilers? 109# Use multi to test different compilers?
74MAKE_CMD = CC=gcc-4.5.1 make 110MAKE_CMD = CC=gcc-4.5.1 make
111BUILD_TYPE = ${DO_BUILD_TYPE}
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index c7ba7614061b..4e67d52eb3a2 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -53,6 +53,9 @@ my %default = (
53 "STOP_AFTER_FAILURE" => 60, 53 "STOP_AFTER_FAILURE" => 60,
54 "STOP_TEST_AFTER" => 600, 54 "STOP_TEST_AFTER" => 600,
55 "MAX_MONITOR_WAIT" => 1800, 55 "MAX_MONITOR_WAIT" => 1800,
56 "GRUB_REBOOT" => "grub2-reboot",
57 "SYSLINUX" => "extlinux",
58 "SYSLINUX_PATH" => "/boot/extlinux",
56 59
57# required, and we will ask users if they don't have them but we keep the default 60# required, and we will ask users if they don't have them but we keep the default
58# value something that is common. 61# value something that is common.
@@ -105,7 +108,12 @@ my $scp_to_target;
105my $scp_to_target_install; 108my $scp_to_target_install;
106my $power_off; 109my $power_off;
107my $grub_menu; 110my $grub_menu;
111my $grub_file;
108my $grub_number; 112my $grub_number;
113my $grub_reboot;
114my $syslinux;
115my $syslinux_path;
116my $syslinux_label;
109my $target; 117my $target;
110my $make; 118my $make;
111my $pre_install; 119my $pre_install;
@@ -118,6 +126,7 @@ my $start_minconfig_defined;
118my $output_minconfig; 126my $output_minconfig;
119my $minconfig_type; 127my $minconfig_type;
120my $use_output_minconfig; 128my $use_output_minconfig;
129my $warnings_file;
121my $ignore_config; 130my $ignore_config;
122my $ignore_errors; 131my $ignore_errors;
123my $addconfig; 132my $addconfig;
@@ -185,6 +194,9 @@ my $patchcheck_end;
185# which would require more options. 194# which would require more options.
186my $buildonly = 1; 195my $buildonly = 1;
187 196
197# tell build not to worry about warnings, even when WARNINGS_FILE is set
198my $warnings_ok = 0;
199
188# set when creating a new config 200# set when creating a new config
189my $newconfig = 0; 201my $newconfig = 0;
190 202
@@ -227,11 +239,17 @@ my %option_map = (
227 "START_MIN_CONFIG" => \$start_minconfig, 239 "START_MIN_CONFIG" => \$start_minconfig,
228 "MIN_CONFIG_TYPE" => \$minconfig_type, 240 "MIN_CONFIG_TYPE" => \$minconfig_type,
229 "USE_OUTPUT_MIN_CONFIG" => \$use_output_minconfig, 241 "USE_OUTPUT_MIN_CONFIG" => \$use_output_minconfig,
242 "WARNINGS_FILE" => \$warnings_file,
230 "IGNORE_CONFIG" => \$ignore_config, 243 "IGNORE_CONFIG" => \$ignore_config,
231 "TEST" => \$run_test, 244 "TEST" => \$run_test,
232 "ADD_CONFIG" => \$addconfig, 245 "ADD_CONFIG" => \$addconfig,
233 "REBOOT_TYPE" => \$reboot_type, 246 "REBOOT_TYPE" => \$reboot_type,
234 "GRUB_MENU" => \$grub_menu, 247 "GRUB_MENU" => \$grub_menu,
248 "GRUB_FILE" => \$grub_file,
249 "GRUB_REBOOT" => \$grub_reboot,
250 "SYSLINUX" => \$syslinux,
251 "SYSLINUX_PATH" => \$syslinux_path,
252 "SYSLINUX_LABEL" => \$syslinux_label,
235 "PRE_INSTALL" => \$pre_install, 253 "PRE_INSTALL" => \$pre_install,
236 "POST_INSTALL" => \$post_install, 254 "POST_INSTALL" => \$post_install,
237 "NO_INSTALL" => \$no_install, 255 "NO_INSTALL" => \$no_install,
@@ -368,7 +386,7 @@ EOF
368 ; 386 ;
369$config_help{"REBOOT_TYPE"} = << "EOF" 387$config_help{"REBOOT_TYPE"} = << "EOF"
370 Way to reboot the box to the test kernel. 388 Way to reboot the box to the test kernel.
371 Only valid options so far are "grub" and "script". 389 Only valid options so far are "grub", "grub2", "syslinux", and "script".
372 390
373 If you specify grub, it will assume grub version 1 391 If you specify grub, it will assume grub version 1
374 and will search in /boot/grub/menu.lst for the title \$GRUB_MENU 392 and will search in /boot/grub/menu.lst for the title \$GRUB_MENU
@@ -378,11 +396,19 @@ $config_help{"REBOOT_TYPE"} = << "EOF"
378 396
379 The entry in /boot/grub/menu.lst must be entered in manually. 397 The entry in /boot/grub/menu.lst must be entered in manually.
380 The test will not modify that file. 398 The test will not modify that file.
399
400 If you specify grub2, then you also need to specify both \$GRUB_MENU
401 and \$GRUB_FILE.
402
403 If you specify syslinux, then you may use SYSLINUX to define the syslinux
404 command (defaults to extlinux), and SYSLINUX_PATH to specify the path to
405 the syslinux install (defaults to /boot/extlinux). But you have to specify
406 SYSLINUX_LABEL to define the label to boot to for the test kernel.
381EOF 407EOF
382 ; 408 ;
383$config_help{"GRUB_MENU"} = << "EOF" 409$config_help{"GRUB_MENU"} = << "EOF"
384 The grub title name for the test kernel to boot 410 The grub title name for the test kernel to boot
385 (Only mandatory if REBOOT_TYPE = grub) 411 (Only mandatory if REBOOT_TYPE = grub or grub2)
386 412
387 Note, ktest.pl will not update the grub menu.lst, you need to 413 Note, ktest.pl will not update the grub menu.lst, you need to
388 manually add an option for the test. ktest.pl will search 414 manually add an option for the test. ktest.pl will search
@@ -393,6 +419,22 @@ $config_help{"GRUB_MENU"} = << "EOF"
393 title Test Kernel 419 title Test Kernel
394 kernel vmlinuz-test 420 kernel vmlinuz-test
395 GRUB_MENU = Test Kernel 421 GRUB_MENU = Test Kernel
422
423 For grub2, a search of \$GRUB_FILE is performed for the lines
424 that begin with "menuentry". It will not detect submenus. The
425 menu must be a non-nested menu. Add the quotes used in the menu
426 to guarantee your selection, as the first menuentry with the content
427 of \$GRUB_MENU that is found will be used.
428EOF
429 ;
430$config_help{"GRUB_FILE"} = << "EOF"
431 If grub2 is used, the full path for the grub.cfg file is placed
432 here. Use something like /boot/grub2/grub.cfg to search.
433EOF
434 ;
435$config_help{"SYSLINUX_LABEL"} = << "EOF"
436 If syslinux is used, the label that boots the target kernel must
437 be specified with SYSLINUX_LABEL.
396EOF 438EOF
397 ; 439 ;
398$config_help{"REBOOT_SCRIPT"} = << "EOF" 440$config_help{"REBOOT_SCRIPT"} = << "EOF"
@@ -521,6 +563,15 @@ sub get_ktest_configs {
521 if ($rtype eq "grub") { 563 if ($rtype eq "grub") {
522 get_ktest_config("GRUB_MENU"); 564 get_ktest_config("GRUB_MENU");
523 } 565 }
566
567 if ($rtype eq "grub2") {
568 get_ktest_config("GRUB_MENU");
569 get_ktest_config("GRUB_FILE");
570 }
571
572 if ($rtype eq "syslinux") {
573 get_ktest_config("SYSLINUX_LABEL");
574 }
524} 575}
525 576
526sub process_variables { 577sub process_variables {
@@ -573,6 +624,18 @@ sub set_value {
573 # Note if a test is something other than build, then we 624 # Note if a test is something other than build, then we
574 # will need other manditory options. 625 # will need other manditory options.
575 if ($prvalue ne "install") { 626 if ($prvalue ne "install") {
627 # for bisect, we need to check BISECT_TYPE
628 if ($prvalue ne "bisect") {
629 $buildonly = 0;
630 }
631 } else {
632 # install still limits some manditory options.
633 $buildonly = 2;
634 }
635 }
636
637 if ($buildonly && $lvalue =~ /^BISECT_TYPE(\[.*\])?$/ && $prvalue ne "build") {
638 if ($prvalue ne "install") {
576 $buildonly = 0; 639 $buildonly = 0;
577 } else { 640 } else {
578 # install still limits some manditory options. 641 # install still limits some manditory options.
@@ -1016,7 +1079,7 @@ sub read_config {
1016} 1079}
1017 1080
1018sub __eval_option { 1081sub __eval_option {
1019 my ($option, $i) = @_; 1082 my ($name, $option, $i) = @_;
1020 1083
1021 # Add space to evaluate the character before $ 1084 # Add space to evaluate the character before $
1022 $option = " $option"; 1085 $option = " $option";
@@ -1048,7 +1111,11 @@ sub __eval_option {
1048 my $o = "$var\[$i\]"; 1111 my $o = "$var\[$i\]";
1049 my $parento = "$var\[$parent\]"; 1112 my $parento = "$var\[$parent\]";
1050 1113
1051 if (defined($opt{$o})) { 1114 # If a variable contains itself, use the default var
1115 if (($var eq $name) && defined($opt{$var})) {
1116 $o = $opt{$var};
1117 $retval = "$retval$o";
1118 } elsif (defined($opt{$o})) {
1052 $o = $opt{$o}; 1119 $o = $opt{$o};
1053 $retval = "$retval$o"; 1120 $retval = "$retval$o";
1054 } elsif ($repeated && defined($opt{$parento})) { 1121 } elsif ($repeated && defined($opt{$parento})) {
@@ -1072,7 +1139,7 @@ sub __eval_option {
1072} 1139}
1073 1140
1074sub eval_option { 1141sub eval_option {
1075 my ($option, $i) = @_; 1142 my ($name, $option, $i) = @_;
1076 1143
1077 my $prev = ""; 1144 my $prev = "";
1078 1145
@@ -1088,7 +1155,7 @@ sub eval_option {
1088 "Check for recursive variables\n"; 1155 "Check for recursive variables\n";
1089 } 1156 }
1090 $prev = $option; 1157 $prev = $option;
1091 $option = __eval_option($option, $i); 1158 $option = __eval_option($name, $option, $i);
1092 } 1159 }
1093 1160
1094 return $option; 1161 return $option;
@@ -1123,6 +1190,9 @@ sub wait_for_monitor;
1123sub reboot { 1190sub reboot {
1124 my ($time) = @_; 1191 my ($time) = @_;
1125 1192
1193 # Make sure everything has been written to disk
1194 run_ssh("sync");
1195
1126 if (defined($time)) { 1196 if (defined($time)) {
1127 start_monitor; 1197 start_monitor;
1128 # flush out current monitor 1198 # flush out current monitor
@@ -1142,11 +1212,24 @@ sub reboot {
1142 } 1212 }
1143 1213
1144 if (defined($time)) { 1214 if (defined($time)) {
1145 if (wait_for_monitor($time, $reboot_success_line)) { 1215
1216 # We only want to get to the new kernel, don't fail
1217 # if we stumble over a call trace.
1218 my $save_ignore_errors = $ignore_errors;
1219 $ignore_errors = 1;
1220
1221 # Look for the good kernel to boot
1222 if (wait_for_monitor($time, "Linux version")) {
1146 # reboot got stuck? 1223 # reboot got stuck?
1147 doprint "Reboot did not finish. Forcing power cycle\n"; 1224 doprint "Reboot did not finish. Forcing power cycle\n";
1148 run_command "$power_cycle"; 1225 run_command "$power_cycle";
1149 } 1226 }
1227
1228 $ignore_errors = $save_ignore_errors;
1229
1230 # Still need to wait for the reboot to finish
1231 wait_for_monitor($time, $reboot_success_line);
1232
1150 end_monitor; 1233 end_monitor;
1151 } 1234 }
1152} 1235}
@@ -1230,6 +1313,7 @@ sub start_monitor {
1230} 1313}
1231 1314
1232sub end_monitor { 1315sub end_monitor {
1316 return if (!defined $console);
1233 if (--$monitor_cnt) { 1317 if (--$monitor_cnt) {
1234 return; 1318 return;
1235 } 1319 }
@@ -1452,8 +1536,44 @@ sub run_scp_mod {
1452 return run_scp($src, $dst, $cp_scp); 1536 return run_scp($src, $dst, $cp_scp);
1453} 1537}
1454 1538
1539sub get_grub2_index {
1540
1541 return if (defined($grub_number));
1542
1543 doprint "Find grub2 menu ... ";
1544 $grub_number = -1;
1545
1546 my $ssh_grub = $ssh_exec;
1547 $ssh_grub =~ s,\$SSH_COMMAND,cat $grub_file,g;
1548
1549 open(IN, "$ssh_grub |")
1550 or die "unable to get $grub_file";
1551
1552 my $found = 0;
1553
1554 while (<IN>) {
1555 if (/^menuentry.*$grub_menu/) {
1556 $grub_number++;
1557 $found = 1;
1558 last;
1559 } elsif (/^menuentry\s/) {
1560 $grub_number++;
1561 }
1562 }
1563 close(IN);
1564
1565 die "Could not find '$grub_menu' in $grub_file on $machine"
1566 if (!$found);
1567 doprint "$grub_number\n";
1568}
1569
1455sub get_grub_index { 1570sub get_grub_index {
1456 1571
1572 if ($reboot_type eq "grub2") {
1573 get_grub2_index;
1574 return;
1575 }
1576
1457 if ($reboot_type ne "grub") { 1577 if ($reboot_type ne "grub") {
1458 return; 1578 return;
1459 } 1579 }
@@ -1500,7 +1620,7 @@ sub wait_for_input
1500 1620
1501 $rin = ''; 1621 $rin = '';
1502 vec($rin, fileno($fp), 1) = 1; 1622 vec($rin, fileno($fp), 1) = 1;
1503 $ready = select($rin, undef, undef, $time); 1623 ($ready, $time) = select($rin, undef, undef, $time);
1504 1624
1505 $line = ""; 1625 $line = "";
1506 1626
@@ -1524,6 +1644,10 @@ sub reboot_to {
1524 1644
1525 if ($reboot_type eq "grub") { 1645 if ($reboot_type eq "grub") {
1526 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'"; 1646 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'";
1647 } elsif ($reboot_type eq "grub2") {
1648 run_ssh "$grub_reboot $grub_number";
1649 } elsif ($reboot_type eq "syslinux") {
1650 run_ssh "$syslinux --once \\\"$syslinux_label\\\" $syslinux_path";
1527 } elsif (defined $reboot_script) { 1651 } elsif (defined $reboot_script) {
1528 run_command "$reboot_script"; 1652 run_command "$reboot_script";
1529 } 1653 }
@@ -1718,6 +1842,14 @@ sub do_post_install {
1718 dodie "Failed to run post install"; 1842 dodie "Failed to run post install";
1719} 1843}
1720 1844
1845# Sometimes the reboot fails, and will hang. We try to ssh to the box
1846# and if we fail, we force another reboot, that should powercycle it.
1847sub test_booted {
1848 if (!run_ssh "echo testing connection") {
1849 reboot $sleep_time;
1850 }
1851}
1852
1721sub install { 1853sub install {
1722 1854
1723 return if ($no_install); 1855 return if ($no_install);
@@ -1730,6 +1862,8 @@ sub install {
1730 1862
1731 my $cp_target = eval_kernel_version $target_image; 1863 my $cp_target = eval_kernel_version $target_image;
1732 1864
1865 test_booted;
1866
1733 run_scp_install "$outputdir/$build_target", "$cp_target" or 1867 run_scp_install "$outputdir/$build_target", "$cp_target" or
1734 dodie "failed to copy image"; 1868 dodie "failed to copy image";
1735 1869
@@ -1792,23 +1926,102 @@ sub get_version {
1792 1926
1793sub start_monitor_and_boot { 1927sub start_monitor_and_boot {
1794 # Make sure the stable kernel has finished booting 1928 # Make sure the stable kernel has finished booting
1795 start_monitor; 1929
1796 wait_for_monitor 5; 1930 # Install bisects, don't need console
1797 end_monitor; 1931 if (defined $console) {
1932 start_monitor;
1933 wait_for_monitor 5;
1934 end_monitor;
1935 }
1798 1936
1799 get_grub_index; 1937 get_grub_index;
1800 get_version; 1938 get_version;
1801 install; 1939 install;
1802 1940
1803 start_monitor; 1941 start_monitor if (defined $console);
1804 return monitor; 1942 return monitor;
1805} 1943}
1806 1944
1945my $check_build_re = ".*:.*(warning|error|Error):.*";
1946my $utf8_quote = "\\x{e2}\\x{80}(\\x{98}|\\x{99})";
1947
1948sub process_warning_line {
1949 my ($line) = @_;
1950
1951 chomp $line;
1952
1953 # for distcc heterogeneous systems, some compilers
1954 # do things differently causing warning lines
1955 # to be slightly different. This makes an attempt
1956 # to fixe those issues.
1957
1958 # chop off the index into the line
1959 # using distcc, some compilers give different indexes
1960 # depending on white space
1961 $line =~ s/^(\s*\S+:\d+:)\d+/$1/;
1962
1963 # Some compilers use UTF-8 extended for quotes and some don't.
1964 $line =~ s/$utf8_quote/'/g;
1965
1966 return $line;
1967}
1968
1969# Read buildlog and check against warnings file for any
1970# new warnings.
1971#
1972# Returns 1 if OK
1973# 0 otherwise
1807sub check_buildlog { 1974sub check_buildlog {
1975 return 1 if (!defined $warnings_file);
1976
1977 my %warnings_list;
1978
1979 # Failed builds should not reboot the target
1980 my $save_no_reboot = $no_reboot;
1981 $no_reboot = 1;
1982
1983 if (-f $warnings_file) {
1984 open(IN, $warnings_file) or
1985 dodie "Error opening $warnings_file";
1986
1987 while (<IN>) {
1988 if (/$check_build_re/) {
1989 my $warning = process_warning_line $_;
1990
1991 $warnings_list{$warning} = 1;
1992 }
1993 }
1994 close(IN);
1995 }
1996
1997 # If warnings file didn't exist, and WARNINGS_FILE exist,
1998 # then we fail on any warning!
1999
2000 open(IN, $buildlog) or dodie "Can't open $buildlog";
2001 while (<IN>) {
2002 if (/$check_build_re/) {
2003 my $warning = process_warning_line $_;
2004
2005 if (!defined $warnings_list{$warning}) {
2006 fail "New warning found (not in $warnings_file)\n$_\n";
2007 $no_reboot = $save_no_reboot;
2008 return 0;
2009 }
2010 }
2011 }
2012 $no_reboot = $save_no_reboot;
2013 close(IN);
2014}
2015
2016sub check_patch_buildlog {
1808 my ($patch) = @_; 2017 my ($patch) = @_;
1809 2018
1810 my @files = `git show $patch | diffstat -l`; 2019 my @files = `git show $patch | diffstat -l`;
1811 2020
2021 foreach my $file (@files) {
2022 chomp $file;
2023 }
2024
1812 open(IN, "git show $patch |") or 2025 open(IN, "git show $patch |") or
1813 dodie "failed to show $patch"; 2026 dodie "failed to show $patch";
1814 while (<IN>) { 2027 while (<IN>) {
@@ -1877,10 +2090,14 @@ sub make_oldconfig {
1877 2090
1878 if (!run_command "$make olddefconfig") { 2091 if (!run_command "$make olddefconfig") {
1879 # Perhaps olddefconfig doesn't exist in this version of the kernel 2092 # Perhaps olddefconfig doesn't exist in this version of the kernel
1880 # try a yes '' | oldconfig 2093 # try oldnoconfig
1881 doprint "olddefconfig failed, trying yes '' | make oldconfig\n"; 2094 doprint "olddefconfig failed, trying make oldnoconfig\n";
1882 run_command "yes '' | $make oldconfig" or 2095 if (!run_command "$make oldnoconfig") {
1883 dodie "failed make config oldconfig"; 2096 doprint "oldnoconfig failed, trying yes '' | make oldconfig\n";
2097 # try a yes '' | oldconfig
2098 run_command "yes '' | $make oldconfig" or
2099 dodie "failed make config oldconfig";
2100 }
1884 } 2101 }
1885} 2102}
1886 2103
@@ -2952,11 +3169,13 @@ sub patchcheck {
2952 build "oldconfig" or return 0; 3169 build "oldconfig" or return 0;
2953 } 3170 }
2954 3171
2955 3172 # No need to do per patch checking if warnings file exists
2956 if (!defined($ignored_warnings{$sha1})) { 3173 if (!defined($warnings_file) && !defined($ignored_warnings{$sha1})) {
2957 check_buildlog $sha1 or return 0; 3174 check_patch_buildlog $sha1 or return 0;
2958 } 3175 }
2959 3176
3177 check_buildlog or return 0;
3178
2960 next if ($type eq "build"); 3179 next if ($type eq "build");
2961 3180
2962 my $failed = 0; 3181 my $failed = 0;
@@ -3514,6 +3733,39 @@ sub make_min_config {
3514 return 1; 3733 return 1;
3515} 3734}
3516 3735
3736sub make_warnings_file {
3737 my ($i) = @_;
3738
3739 if (!defined($warnings_file)) {
3740 dodie "Must define WARNINGS_FILE for make_warnings_file test";
3741 }
3742
3743 if ($build_type eq "nobuild") {
3744 dodie "BUILD_TYPE can not be 'nobuild' for make_warnings_file test";
3745 }
3746
3747 build $build_type or dodie "Failed to build";
3748
3749 open(OUT, ">$warnings_file") or dodie "Can't create $warnings_file";
3750
3751 open(IN, $buildlog) or dodie "Can't open $buildlog";
3752 while (<IN>) {
3753
3754 # Some compilers use UTF-8 extended for quotes
3755 # for distcc heterogeneous systems, this causes issues
3756 s/$utf8_quote/'/g;
3757
3758 if (/$check_build_re/) {
3759 print OUT;
3760 }
3761 }
3762 close(IN);
3763
3764 close(OUT);
3765
3766 success $i;
3767}
3768
3517$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n"; 3769$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n";
3518 3770
3519if ($#ARGV == 0) { 3771if ($#ARGV == 0) {
@@ -3559,7 +3811,7 @@ EOF
3559read_config $ktest_config; 3811read_config $ktest_config;
3560 3812
3561if (defined($opt{"LOG_FILE"})) { 3813if (defined($opt{"LOG_FILE"})) {
3562 $opt{"LOG_FILE"} = eval_option($opt{"LOG_FILE"}, -1); 3814 $opt{"LOG_FILE"} = eval_option("LOG_FILE", $opt{"LOG_FILE"}, -1);
3563} 3815}
3564 3816
3565# Append any configs entered in manually to the config file. 3817# Append any configs entered in manually to the config file.
@@ -3636,7 +3888,7 @@ sub set_test_option {
3636 my $option = __set_test_option($name, $i); 3888 my $option = __set_test_option($name, $i);
3637 return $option if (!defined($option)); 3889 return $option if (!defined($option));
3638 3890
3639 return eval_option($option, $i); 3891 return eval_option($name, $option, $i);
3640} 3892}
3641 3893
3642# First we need to do is the builds 3894# First we need to do is the builds
@@ -3700,6 +3952,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3700 $target = "$ssh_user\@$machine"; 3952 $target = "$ssh_user\@$machine";
3701 if ($reboot_type eq "grub") { 3953 if ($reboot_type eq "grub") {
3702 dodie "GRUB_MENU not defined" if (!defined($grub_menu)); 3954 dodie "GRUB_MENU not defined" if (!defined($grub_menu));
3955 } elsif ($reboot_type eq "grub2") {
3956 dodie "GRUB_MENU not defined" if (!defined($grub_menu));
3957 dodie "GRUB_FILE not defined" if (!defined($grub_file));
3958 } elsif ($reboot_type eq "syslinux") {
3959 dodie "SYSLINUX_LABEL not defined" if (!defined($syslinux_label));
3703 } 3960 }
3704 } 3961 }
3705 3962
@@ -3710,9 +3967,9 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3710 $run_type = $bisect_type; 3967 $run_type = $bisect_type;
3711 } elsif ($test_type eq "config_bisect") { 3968 } elsif ($test_type eq "config_bisect") {
3712 $run_type = $config_bisect_type; 3969 $run_type = $config_bisect_type;
3713 } 3970 } elsif ($test_type eq "make_min_config") {
3714 3971 $run_type = "";
3715 if ($test_type eq "make_min_config") { 3972 } elsif ($test_type eq "make_warnings_file") {
3716 $run_type = ""; 3973 $run_type = "";
3717 } 3974 }
3718 3975
@@ -3769,10 +4026,15 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
3769 } elsif ($test_type eq "make_min_config") { 4026 } elsif ($test_type eq "make_min_config") {
3770 make_min_config $i; 4027 make_min_config $i;
3771 next; 4028 next;
4029 } elsif ($test_type eq "make_warnings_file") {
4030 $no_reboot = 1;
4031 make_warnings_file $i;
4032 next;
3772 } 4033 }
3773 4034
3774 if ($build_type ne "nobuild") { 4035 if ($build_type ne "nobuild") {
3775 build $build_type or next; 4036 build $build_type or next;
4037 check_buildlog or next;
3776 } 4038 }
3777 4039
3778 if ($test_type eq "install") { 4040 if ($test_type eq "install") {
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index de28a0a3b8fc..0a290fb4cd5e 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -332,8 +332,18 @@
332# from other linux builds on the system. 332# from other linux builds on the system.
333#LOCALVERSION = -test 333#LOCALVERSION = -test
334 334
335# For REBOOT_TYPE = grub2, you must specify where the grub.cfg
336# file is. This is the file that is searched to find the menu
337# option to boot to with GRUB_REBOOT
338#GRUB_FILE = /boot/grub2/grub.cfg
339
340# The tool for REBOOT_TYPE = grub2 to set the next reboot kernel
341# to boot into (one shot mode).
342# (default grub2_reboot)
343#GRUB_REBOOT = grub2_reboot
344
335# The grub title name for the test kernel to boot 345# The grub title name for the test kernel to boot
336# (Only mandatory if REBOOT_TYPE = grub) 346# (Only mandatory if REBOOT_TYPE = grub or grub2)
337# 347#
338# Note, ktest.pl will not update the grub menu.lst, you need to 348# Note, ktest.pl will not update the grub menu.lst, you need to
339# manually add an option for the test. ktest.pl will search 349# manually add an option for the test. ktest.pl will search
@@ -343,8 +353,33 @@
343# For example, if in the /boot/grub/menu.lst the test kernel title has: 353# For example, if in the /boot/grub/menu.lst the test kernel title has:
344# title Test Kernel 354# title Test Kernel
345# kernel vmlinuz-test 355# kernel vmlinuz-test
356#
357# For grub2, a search of top level "menuentry"s are done. No
358# submenu is searched. The menu is found by searching for the
359# contents of GRUB_MENU in the line that starts with "menuentry".
360# You may want to include the quotes around the option. For example:
361# for: menuentry 'Test Kernel'
362# do a: GRUB_MENU = 'Test Kernel'
363# For customizing, add your entry in /etc/grub.d/40_custom.
364#
346#GRUB_MENU = Test Kernel 365#GRUB_MENU = Test Kernel
347 366
367# For REBOOT_TYPE = syslinux, the name of the syslinux executable
368# (on the target) to use to set up the next reboot to boot the
369# test kernel.
370# (default extlinux)
371#SYSLINUX = syslinux
372
373# For REBOOT_TYPE = syslinux, the path that is passed to to the
374# syslinux command where syslinux is installed.
375# (default /boot/extlinux)
376#SYSLINUX_PATH = /boot/syslinux
377
378# For REBOOT_TYPE = syslinux, the syslinux label that references the
379# test kernel in the syslinux config file.
380# (default undefined)
381#SYSLINUX_LABEL = "test-kernel"
382
348# A script to reboot the target into the test kernel 383# A script to reboot the target into the test kernel
349# This and SWITCH_TO_TEST are about the same, except 384# This and SWITCH_TO_TEST are about the same, except
350# SWITCH_TO_TEST is run even for REBOOT_TYPE = grub. 385# SWITCH_TO_TEST is run even for REBOOT_TYPE = grub.
@@ -497,7 +532,7 @@
497#POST_BUILD_DIE = 1 532#POST_BUILD_DIE = 1
498 533
499# Way to reboot the box to the test kernel. 534# Way to reboot the box to the test kernel.
500# Only valid options so far are "grub" and "script" 535# Only valid options so far are "grub", "grub2", "syslinux" and "script"
501# (default grub) 536# (default grub)
502# If you specify grub, it will assume grub version 1 537# If you specify grub, it will assume grub version 1
503# and will search in /boot/grub/menu.lst for the title $GRUB_MENU 538# and will search in /boot/grub/menu.lst for the title $GRUB_MENU
@@ -505,6 +540,13 @@
505# your setup, then specify "script" and have a command or script 540# your setup, then specify "script" and have a command or script
506# specified in REBOOT_SCRIPT to boot to the target. 541# specified in REBOOT_SCRIPT to boot to the target.
507# 542#
543# For REBOOT_TYPE = grub2, you must define both GRUB_MENU and
544# GRUB_FILE.
545#
546# For REBOOT_TYPE = syslinux, you must define SYSLINUX_LABEL, and
547# perhaps modify SYSLINUX (default extlinux) and SYSLINUX_PATH
548# (default /boot/extlinux)
549#
508# The entry in /boot/grub/menu.lst must be entered in manually. 550# The entry in /boot/grub/menu.lst must be entered in manually.
509# The test will not modify that file. 551# The test will not modify that file.
510#REBOOT_TYPE = grub 552#REBOOT_TYPE = grub
@@ -751,6 +793,20 @@
751# Example for a virtual guest call "Guest". 793# Example for a virtual guest call "Guest".
752#POWER_OFF = virsh destroy Guest 794#POWER_OFF = virsh destroy Guest
753 795
796# To have the build fail on "new" warnings, create a file that
797# contains a list of all known warnings (they must match exactly
798# to the line with 'warning:', 'error:' or 'Error:'. If the option
799# WARNINGS_FILE is set, then that file will be read, and if the
800# build detects a warning, it will examine this file and if the
801# warning does not exist in it, it will fail the build.
802#
803# Note, if this option is defined to a file that does not exist
804# then any warning will fail the build.
805# (see make_warnings_file below)
806#
807# (optional, default undefined)
808#WARNINGS_FILE = ${OUTPUT_DIR}/warnings_file
809
754# The way to execute a command on the target 810# The way to execute a command on the target
755# (default ssh $SSH_USER@$MACHINE $SSH_COMMAND";) 811# (default ssh $SSH_USER@$MACHINE $SSH_COMMAND";)
756# The variables SSH_USER, MACHINE and SSH_COMMAND are defined 812# The variables SSH_USER, MACHINE and SSH_COMMAND are defined
@@ -1180,3 +1236,33 @@
1180# MIN_CONFIG_TYPE = test 1236# MIN_CONFIG_TYPE = test
1181# TEST = ssh ${USER}@${MACHINE} echo hi 1237# TEST = ssh ${USER}@${MACHINE} echo hi
1182# 1238#
1239#
1240#
1241#
1242# For TEST_TYPE = make_warnings_file
1243#
1244# If you want the build to fail when a new warning is discovered
1245# you set the WARNINGS_FILE to point to a file of known warnings.
1246#
1247# The test "make_warnings_file" will let you create a new warnings
1248# file before you run other tests, like patchcheck.
1249#
1250# What this test does is to run just a build, you still need to
1251# specify BUILD_TYPE to tell the test what type of config to use.
1252# A BUILD_TYPE of nobuild will fail this test.
1253#
1254# The test will do the build and scan for all warnings. Any warning
1255# it discovers will be saved in the WARNINGS_FILE (required) option.
1256#
1257# It is recommended (but not necessary) to make sure BUILD_NOCLEAN is
1258# off, so that a full build is done (make mrproper is performed).
1259# That way, all warnings will be captured.
1260#
1261# Example:
1262#
1263# TEST_TYPE = make_warnings_file
1264# WARNINGS_FILE = ${OUTPUT_DIR}
1265# BUILD_TYPE = useconfig:oldconfig
1266# CHECKOUT = v3.8
1267# BUILD_NOCLEAN = 0
1268#
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 43480149119e..3cc0ad7ae863 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,4 +1,10 @@
1TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug epoll 1TARGETS = breakpoints
2TARGETS += kcmp
3TARGETS += mqueue
4TARGETS += vm
5TARGETS += cpu-hotplug
6TARGETS += memory-hotplug
7TARGETS += efivarfs
2 8
3all: 9all:
4 for TARGET in $(TARGETS); do \ 10 for TARGET in $(TARGETS); do \
diff --git a/tools/testing/selftests/README.txt b/tools/testing/selftests/README.txt
new file mode 100644
index 000000000000..5e2faf9c55d3
--- /dev/null
+++ b/tools/testing/selftests/README.txt
@@ -0,0 +1,42 @@
1Linux Kernel Selftests
2
3The kernel contains a set of "self tests" under the tools/testing/selftests/
4directory. These are intended to be small unit tests to exercise individual
5code paths in the kernel.
6
7Running the selftests
8=====================
9
10To build the tests:
11
12 $ make -C tools/testing/selftests
13
14
15To run the tests:
16
17 $ make -C tools/testing/selftests run_tests
18
19- note that some tests will require root privileges.
20
21
22To run only tests targetted for a single subsystem:
23
24 $ make -C tools/testing/selftests TARGETS=cpu-hotplug run_tests
25
26See the top-level tools/testing/selftests/Makefile for the list of all possible
27targets.
28
29
30Contributing new tests
31======================
32
33In general, the rules for for selftests are
34
35 * Do as much as you can if you're not root;
36
37 * Don't take too long;
38
39 * Don't break the build on any architecture, and
40
41 * Don't cause the top-level "make run_tests" to fail if your feature is
42 unconfigured.
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile
index 931278035f5c..e18b42b254af 100644
--- a/tools/testing/selftests/breakpoints/Makefile
+++ b/tools/testing/selftests/breakpoints/Makefile
@@ -17,7 +17,7 @@ else
17endif 17endif
18 18
19run_tests: 19run_tests:
20 ./breakpoint_test 20 @./breakpoint_test || echo "breakpoints selftests: [FAIL]"
21 21
22clean: 22clean:
23 rm -fr breakpoint_test 23 rm -fr breakpoint_test
diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile
index 7c9c20ff578a..12657a5e4bf9 100644
--- a/tools/testing/selftests/cpu-hotplug/Makefile
+++ b/tools/testing/selftests/cpu-hotplug/Makefile
@@ -1,6 +1,6 @@
1all: 1all:
2 2
3run_tests: 3run_tests:
4 ./on-off-test.sh 4 @./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]"
5 5
6clean: 6clean:
diff --git a/tools/testing/selftests/efivarfs/Makefile b/tools/testing/selftests/efivarfs/Makefile
new file mode 100644
index 000000000000..29e8c6bc81b0
--- /dev/null
+++ b/tools/testing/selftests/efivarfs/Makefile
@@ -0,0 +1,12 @@
1CC = $(CROSS_COMPILE)gcc
2CFLAGS = -Wall
3
4test_objs = open-unlink create-read
5
6all: $(test_objs)
7
8run_tests: all
9 @/bin/bash ./efivarfs.sh || echo "efivarfs selftests: [FAIL]"
10
11clean:
12 rm -f $(test_objs)
diff --git a/tools/testing/selftests/efivarfs/create-read.c b/tools/testing/selftests/efivarfs/create-read.c
new file mode 100644
index 000000000000..7feef1880968
--- /dev/null
+++ b/tools/testing/selftests/efivarfs/create-read.c
@@ -0,0 +1,38 @@
1#include <stdio.h>
2#include <stdint.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <errno.h>
9#include <string.h>
10
11int main(int argc, char **argv)
12{
13 const char *path;
14 char buf[4];
15 int fd, rc;
16
17 if (argc < 2) {
18 fprintf(stderr, "usage: %s <path>\n", argv[0]);
19 return EXIT_FAILURE;
20 }
21
22 path = argv[1];
23
24 /* create a test variable */
25 fd = open(path, O_RDWR | O_CREAT, 0600);
26 if (fd < 0) {
27 perror("open(O_WRONLY)");
28 return EXIT_FAILURE;
29 }
30
31 rc = read(fd, buf, sizeof(buf));
32 if (rc != 0) {
33 fprintf(stderr, "Reading a new var should return EOF\n");
34 return EXIT_FAILURE;
35 }
36
37 return EXIT_SUCCESS;
38}
diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh
new file mode 100644
index 000000000000..77edcdcc016b
--- /dev/null
+++ b/tools/testing/selftests/efivarfs/efivarfs.sh
@@ -0,0 +1,198 @@
1#!/bin/bash
2
3efivarfs_mount=/sys/firmware/efi/efivars
4test_guid=210be57c-9849-4fc7-a635-e6382d1aec27
5
6check_prereqs()
7{
8 local msg="skip all tests:"
9
10 if [ $UID != 0 ]; then
11 echo $msg must be run as root >&2
12 exit 0
13 fi
14
15 if ! grep -q "^\S\+ $efivarfs_mount efivarfs" /proc/mounts; then
16 echo $msg efivarfs is not mounted on $efivarfs_mount >&2
17 exit 0
18 fi
19}
20
21run_test()
22{
23 local test="$1"
24
25 echo "--------------------"
26 echo "running $test"
27 echo "--------------------"
28
29 if [ "$(type -t $test)" = 'function' ]; then
30 ( $test )
31 else
32 ( ./$test )
33 fi
34
35 if [ $? -ne 0 ]; then
36 echo " [FAIL]"
37 rc=1
38 else
39 echo " [PASS]"
40 fi
41}
42
43test_create()
44{
45 local attrs='\x07\x00\x00\x00'
46 local file=$efivarfs_mount/$FUNCNAME-$test_guid
47
48 printf "$attrs\x00" > $file
49
50 if [ ! -e $file ]; then
51 echo "$file couldn't be created" >&2
52 exit 1
53 fi
54
55 if [ $(stat -c %s $file) -ne 5 ]; then
56 echo "$file has invalid size" >&2
57 exit 1
58 fi
59}
60
61test_create_empty()
62{
63 local file=$efivarfs_mount/$FUNCNAME-$test_guid
64
65 : > $file
66
67 if [ ! -e $file ]; then
68 echo "$file can not be created without writing" >&2
69 exit 1
70 fi
71}
72
73test_create_read()
74{
75 local file=$efivarfs_mount/$FUNCNAME-$test_guid
76 ./create-read $file
77}
78
79test_delete()
80{
81 local attrs='\x07\x00\x00\x00'
82 local file=$efivarfs_mount/$FUNCNAME-$test_guid
83
84 printf "$attrs\x00" > $file
85
86 if [ ! -e $file ]; then
87 echo "$file couldn't be created" >&2
88 exit 1
89 fi
90
91 rm $file
92
93 if [ -e $file ]; then
94 echo "$file couldn't be deleted" >&2
95 exit 1
96 fi
97
98}
99
100# test that we can remove a variable by issuing a write with only
101# attributes specified
102test_zero_size_delete()
103{
104 local attrs='\x07\x00\x00\x00'
105 local file=$efivarfs_mount/$FUNCNAME-$test_guid
106
107 printf "$attrs\x00" > $file
108
109 if [ ! -e $file ]; then
110 echo "$file does not exist" >&2
111 exit 1
112 fi
113
114 printf "$attrs" > $file
115
116 if [ -e $file ]; then
117 echo "$file should have been deleted" >&2
118 exit 1
119 fi
120}
121
122test_open_unlink()
123{
124 local file=$efivarfs_mount/$FUNCNAME-$test_guid
125 ./open-unlink $file
126}
127
128# test that we can create a range of filenames
129test_valid_filenames()
130{
131 local attrs='\x07\x00\x00\x00'
132 local ret=0
133
134 local file_list="abc dump-type0-11-1-1362436005 1234 -"
135 for f in $file_list; do
136 local file=$efivarfs_mount/$f-$test_guid
137
138 printf "$attrs\x00" > $file
139
140 if [ ! -e $file ]; then
141 echo "$file could not be created" >&2
142 ret=1
143 else
144 rm $file
145 fi
146 done
147
148 exit $ret
149}
150
151test_invalid_filenames()
152{
153 local attrs='\x07\x00\x00\x00'
154 local ret=0
155
156 local file_list="
157 -1234-1234-1234-123456789abc
158 foo
159 foo-bar
160 -foo-
161 foo-barbazba-foob-foob-foob-foobarbazfoo
162 foo-------------------------------------
163 -12345678-1234-1234-1234-123456789abc
164 a-12345678=1234-1234-1234-123456789abc
165 a-12345678-1234=1234-1234-123456789abc
166 a-12345678-1234-1234=1234-123456789abc
167 a-12345678-1234-1234-1234=123456789abc
168 1112345678-1234-1234-1234-123456789abc"
169
170 for f in $file_list; do
171 local file=$efivarfs_mount/$f
172
173 printf "$attrs\x00" 2>/dev/null > $file
174
175 if [ -e $file ]; then
176 echo "Creating $file should have failed" >&2
177 rm $file
178 ret=1
179 fi
180 done
181
182 exit $ret
183}
184
185check_prereqs
186
187rc=0
188
189run_test test_create
190run_test test_create_empty
191run_test test_create_read
192run_test test_delete
193run_test test_zero_size_delete
194run_test test_open_unlink
195run_test test_valid_filenames
196run_test test_invalid_filenames
197
198exit $rc
diff --git a/tools/testing/selftests/efivarfs/open-unlink.c b/tools/testing/selftests/efivarfs/open-unlink.c
new file mode 100644
index 000000000000..8c0764407b3c
--- /dev/null
+++ b/tools/testing/selftests/efivarfs/open-unlink.c
@@ -0,0 +1,63 @@
1#include <stdio.h>
2#include <stdint.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8
9int main(int argc, char **argv)
10{
11 const char *path;
12 char buf[5];
13 int fd, rc;
14
15 if (argc < 2) {
16 fprintf(stderr, "usage: %s <path>\n", argv[0]);
17 return EXIT_FAILURE;
18 }
19
20 path = argv[1];
21
22 /* attributes: EFI_VARIABLE_NON_VOLATILE |
23 * EFI_VARIABLE_BOOTSERVICE_ACCESS |
24 * EFI_VARIABLE_RUNTIME_ACCESS
25 */
26 *(uint32_t *)buf = 0x7;
27 buf[4] = 0;
28
29 /* create a test variable */
30 fd = open(path, O_WRONLY | O_CREAT);
31 if (fd < 0) {
32 perror("open(O_WRONLY)");
33 return EXIT_FAILURE;
34 }
35
36 rc = write(fd, buf, sizeof(buf));
37 if (rc != sizeof(buf)) {
38 perror("write");
39 return EXIT_FAILURE;
40 }
41
42 close(fd);
43
44 fd = open(path, O_RDONLY);
45 if (fd < 0) {
46 perror("open");
47 return EXIT_FAILURE;
48 }
49
50 if (unlink(path) < 0) {
51 perror("unlink");
52 return EXIT_FAILURE;
53 }
54
55 rc = read(fd, buf, sizeof(buf));
56 if (rc > 0) {
57 fprintf(stderr, "reading from an unlinked variable "
58 "shouldn't be possible\n");
59 return EXIT_FAILURE;
60 }
61
62 return EXIT_SUCCESS;
63}
diff --git a/tools/testing/selftests/epoll/Makefile b/tools/testing/selftests/epoll/Makefile
deleted file mode 100644
index 19806ed62f50..000000000000
--- a/tools/testing/selftests/epoll/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
1# Makefile for epoll selftests
2
3all: test_epoll
4%: %.c
5 gcc -pthread -g -o $@ $^
6
7run_tests: all
8 ./test_epoll
9
10clean:
11 $(RM) test_epoll
diff --git a/tools/testing/selftests/epoll/test_epoll.c b/tools/testing/selftests/epoll/test_epoll.c
deleted file mode 100644
index f7525392ce84..000000000000
--- a/tools/testing/selftests/epoll/test_epoll.c
+++ /dev/null
@@ -1,344 +0,0 @@
1/*
2 * tools/testing/selftests/epoll/test_epoll.c
3 *
4 * Copyright 2012 Adobe Systems Incorporated
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * Paton J. Lewis <palewis@adobe.com>
12 *
13 */
14
15#include <errno.h>
16#include <fcntl.h>
17#include <pthread.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <sys/epoll.h>
22#include <sys/socket.h>
23
24/*
25 * A pointer to an epoll_item_private structure will be stored in the epoll
26 * item's event structure so that we can get access to the epoll_item_private
27 * data after calling epoll_wait:
28 */
29struct epoll_item_private {
30 int index; /* Position of this struct within the epoll_items array. */
31 int fd;
32 uint32_t events;
33 pthread_mutex_t mutex; /* Guards the following variables... */
34 int stop;
35 int status; /* Stores any error encountered while handling item. */
36 /* The following variable allows us to test whether we have encountered
37 a problem while attempting to cancel and delete the associated
38 event. When the test program exits, 'deleted' should be exactly
39 one. If it is greater than one, then the failed test reflects a real
40 world situation where we would have tried to access the epoll item's
41 private data after deleting it: */
42 int deleted;
43};
44
45struct epoll_item_private *epoll_items;
46
47/*
48 * Delete the specified item from the epoll set. In a real-world secneario this
49 * is where we would free the associated data structure, but in this testing
50 * environment we retain the structure so that we can test for double-deletion:
51 */
52void delete_item(int index)
53{
54 __sync_fetch_and_add(&epoll_items[index].deleted, 1);
55}
56
57/*
58 * A pointer to a read_thread_data structure will be passed as the argument to
59 * each read thread:
60 */
61struct read_thread_data {
62 int stop;
63 int status; /* Indicates any error encountered by the read thread. */
64 int epoll_set;
65};
66
67/*
68 * The function executed by the read threads:
69 */
70void *read_thread_function(void *function_data)
71{
72 struct read_thread_data *thread_data =
73 (struct read_thread_data *)function_data;
74 struct epoll_event event_data;
75 struct epoll_item_private *item_data;
76 char socket_data;
77
78 /* Handle events until we encounter an error or this thread's 'stop'
79 condition is set: */
80 while (1) {
81 int result = epoll_wait(thread_data->epoll_set,
82 &event_data,
83 1, /* Number of desired events */
84 1000); /* Timeout in ms */
85 if (result < 0) {
86 /* Breakpoints signal all threads. Ignore that while
87 debugging: */
88 if (errno == EINTR)
89 continue;
90 thread_data->status = errno;
91 return 0;
92 } else if (thread_data->stop)
93 return 0;
94 else if (result == 0) /* Timeout */
95 continue;
96
97 /* We need the mutex here because checking for the stop
98 condition and re-enabling the epoll item need to be done
99 together as one atomic operation when EPOLL_CTL_DISABLE is
100 available: */
101 item_data = (struct epoll_item_private *)event_data.data.ptr;
102 pthread_mutex_lock(&item_data->mutex);
103
104 /* Remove the item from the epoll set if we want to stop
105 handling that event: */
106 if (item_data->stop)
107 delete_item(item_data->index);
108 else {
109 /* Clear the data that was written to the other end of
110 our non-blocking socket: */
111 do {
112 if (read(item_data->fd, &socket_data, 1) < 1) {
113 if ((errno == EAGAIN) ||
114 (errno == EWOULDBLOCK))
115 break;
116 else
117 goto error_unlock;
118 }
119 } while (item_data->events & EPOLLET);
120
121 /* The item was one-shot, so re-enable it: */
122 event_data.events = item_data->events;
123 if (epoll_ctl(thread_data->epoll_set,
124 EPOLL_CTL_MOD,
125 item_data->fd,
126 &event_data) < 0)
127 goto error_unlock;
128 }
129
130 pthread_mutex_unlock(&item_data->mutex);
131 }
132
133error_unlock:
134 thread_data->status = item_data->status = errno;
135 pthread_mutex_unlock(&item_data->mutex);
136 return 0;
137}
138
139/*
140 * A pointer to a write_thread_data structure will be passed as the argument to
141 * the write thread:
142 */
143struct write_thread_data {
144 int stop;
145 int status; /* Indicates any error encountered by the write thread. */
146 int n_fds;
147 int *fds;
148};
149
150/*
151 * The function executed by the write thread. It writes a single byte to each
152 * socket in turn until the stop condition for this thread is set. If writing to
153 * a socket would block (i.e. errno was EAGAIN), we leave that socket alone for
154 * the moment and just move on to the next socket in the list. We don't care
155 * about the order in which we deliver events to the epoll set. In fact we don't
156 * care about the data we're writing to the pipes at all; we just want to
157 * trigger epoll events:
158 */
159void *write_thread_function(void *function_data)
160{
161 const char data = 'X';
162 int index;
163 struct write_thread_data *thread_data =
164 (struct write_thread_data *)function_data;
165 while (!thread_data->stop)
166 for (index = 0;
167 !thread_data->stop && (index < thread_data->n_fds);
168 ++index)
169 if ((write(thread_data->fds[index], &data, 1) < 1) &&
170 (errno != EAGAIN) &&
171 (errno != EWOULDBLOCK)) {
172 thread_data->status = errno;
173 return;
174 }
175}
176
177/*
178 * Arguments are currently ignored:
179 */
180int main(int argc, char **argv)
181{
182 const int n_read_threads = 100;
183 const int n_epoll_items = 500;
184 int index;
185 int epoll_set = epoll_create1(0);
186 struct write_thread_data write_thread_data = {
187 0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int))
188 };
189 struct read_thread_data *read_thread_data =
190 malloc(n_read_threads * sizeof(struct read_thread_data));
191 pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t));
192 pthread_t write_thread;
193
194 printf("-----------------\n");
195 printf("Runing test_epoll\n");
196 printf("-----------------\n");
197
198 epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private));
199
200 if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 ||
201 read_thread_data == 0 || read_threads == 0)
202 goto error;
203
204 if (sysconf(_SC_NPROCESSORS_ONLN) < 2) {
205 printf("Error: please run this test on a multi-core system.\n");
206 goto error;
207 }
208
209 /* Create the socket pairs and epoll items: */
210 for (index = 0; index < n_epoll_items; ++index) {
211 int socket_pair[2];
212 struct epoll_event event_data;
213 if (socketpair(AF_UNIX,
214 SOCK_STREAM | SOCK_NONBLOCK,
215 0,
216 socket_pair) < 0)
217 goto error;
218 write_thread_data.fds[index] = socket_pair[0];
219 epoll_items[index].index = index;
220 epoll_items[index].fd = socket_pair[1];
221 if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0)
222 goto error;
223 /* We always use EPOLLONESHOT because this test is currently
224 structured to demonstrate the need for EPOLL_CTL_DISABLE,
225 which only produces useful information in the EPOLLONESHOT
226 case (without EPOLLONESHOT, calling epoll_ctl with
227 EPOLL_CTL_DISABLE will never return EBUSY). If support for
228 testing events without EPOLLONESHOT is desired, it should
229 probably be implemented in a separate unit test. */
230 epoll_items[index].events = EPOLLIN | EPOLLONESHOT;
231 if (index < n_epoll_items / 2)
232 epoll_items[index].events |= EPOLLET;
233 epoll_items[index].stop = 0;
234 epoll_items[index].status = 0;
235 epoll_items[index].deleted = 0;
236 event_data.events = epoll_items[index].events;
237 event_data.data.ptr = &epoll_items[index];
238 if (epoll_ctl(epoll_set,
239 EPOLL_CTL_ADD,
240 epoll_items[index].fd,
241 &event_data) < 0)
242 goto error;
243 }
244
245 /* Create and start the read threads: */
246 for (index = 0; index < n_read_threads; ++index) {
247 read_thread_data[index].stop = 0;
248 read_thread_data[index].status = 0;
249 read_thread_data[index].epoll_set = epoll_set;
250 if (pthread_create(&read_threads[index],
251 NULL,
252 read_thread_function,
253 &read_thread_data[index]) != 0)
254 goto error;
255 }
256
257 if (pthread_create(&write_thread,
258 NULL,
259 write_thread_function,
260 &write_thread_data) != 0)
261 goto error;
262
263 /* Cancel all event pollers: */
264#ifdef EPOLL_CTL_DISABLE
265 for (index = 0; index < n_epoll_items; ++index) {
266 pthread_mutex_lock(&epoll_items[index].mutex);
267 ++epoll_items[index].stop;
268 if (epoll_ctl(epoll_set,
269 EPOLL_CTL_DISABLE,
270 epoll_items[index].fd,
271 NULL) == 0)
272 delete_item(index);
273 else if (errno != EBUSY) {
274 pthread_mutex_unlock(&epoll_items[index].mutex);
275 goto error;
276 }
277 /* EBUSY means events were being handled; allow the other thread
278 to delete the item. */
279 pthread_mutex_unlock(&epoll_items[index].mutex);
280 }
281#else
282 for (index = 0; index < n_epoll_items; ++index) {
283 pthread_mutex_lock(&epoll_items[index].mutex);
284 ++epoll_items[index].stop;
285 pthread_mutex_unlock(&epoll_items[index].mutex);
286 /* Wait in case a thread running read_thread_function is
287 currently executing code between epoll_wait and
288 pthread_mutex_lock with this item. Note that a longer delay
289 would make double-deletion less likely (at the expense of
290 performance), but there is no guarantee that any delay would
291 ever be sufficient. Note also that we delete all event
292 pollers at once for testing purposes, but in a real-world
293 environment we are likely to want to be able to cancel event
294 pollers at arbitrary times. Therefore we can't improve this
295 situation by just splitting this loop into two loops
296 (i.e. signal 'stop' for all items, sleep, and then delete all
297 items). We also can't fix the problem via EPOLL_CTL_DEL
298 because that command can't prevent the case where some other
299 thread is executing read_thread_function within the region
300 mentioned above: */
301 usleep(1);
302 pthread_mutex_lock(&epoll_items[index].mutex);
303 if (!epoll_items[index].deleted)
304 delete_item(index);
305 pthread_mutex_unlock(&epoll_items[index].mutex);
306 }
307#endif
308
309 /* Shut down the read threads: */
310 for (index = 0; index < n_read_threads; ++index)
311 __sync_fetch_and_add(&read_thread_data[index].stop, 1);
312 for (index = 0; index < n_read_threads; ++index) {
313 if (pthread_join(read_threads[index], NULL) != 0)
314 goto error;
315 if (read_thread_data[index].status)
316 goto error;
317 }
318
319 /* Shut down the write thread: */
320 __sync_fetch_and_add(&write_thread_data.stop, 1);
321 if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status)
322 goto error;
323
324 /* Check for final error conditions: */
325 for (index = 0; index < n_epoll_items; ++index) {
326 if (epoll_items[index].status != 0)
327 goto error;
328 if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0)
329 goto error;
330 }
331 for (index = 0; index < n_epoll_items; ++index)
332 if (epoll_items[index].deleted != 1) {
333 printf("Error: item data deleted %1d times.\n",
334 epoll_items[index].deleted);
335 goto error;
336 }
337
338 printf("[PASS]\n");
339 return 0;
340
341 error:
342 printf("[FAIL]\n");
343 return errno;
344}
diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile
new file mode 100644
index 000000000000..5386fd7c43ae
--- /dev/null
+++ b/tools/testing/selftests/ipc/Makefile
@@ -0,0 +1,25 @@
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
5 CFLAGS := -DCONFIG_X86_32 -D__i386__
6endif
7ifeq ($(ARCH),x86_64)
8 ARCH := X86
9 CFLAGS := -DCONFIG_X86_64 -D__x86_64__
10endif
11
12CFLAGS += -I../../../../usr/include/
13
14all:
15ifeq ($(ARCH),X86)
16 gcc $(CFLAGS) msgque.c -o msgque_test
17else
18 echo "Not an x86 target, can't build msgque selftest"
19endif
20
21run_tests: all
22 ./msgque_test
23
24clean:
25 rm -fr ./msgque_test
diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c
new file mode 100644
index 000000000000..d66418237d21
--- /dev/null
+++ b/tools/testing/selftests/ipc/msgque.c
@@ -0,0 +1,246 @@
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <errno.h>
5#include <linux/msg.h>
6#include <fcntl.h>
7
8#define MAX_MSG_SIZE 32
9
10struct msg1 {
11 int msize;
12 long mtype;
13 char mtext[MAX_MSG_SIZE];
14};
15
16#define TEST_STRING "Test sysv5 msg"
17#define MSG_TYPE 1
18
19#define ANOTHER_TEST_STRING "Yet another test sysv5 msg"
20#define ANOTHER_MSG_TYPE 26538
21
22struct msgque_data {
23 key_t key;
24 int msq_id;
25 int qbytes;
26 int qnum;
27 int mode;
28 struct msg1 *messages;
29};
30
31int restore_queue(struct msgque_data *msgque)
32{
33 int fd, ret, id, i;
34 char buf[32];
35
36 fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY);
37 if (fd == -1) {
38 printf("Failed to open /proc/sys/kernel/msg_next_id\n");
39 return -errno;
40 }
41 sprintf(buf, "%d", msgque->msq_id);
42
43 ret = write(fd, buf, strlen(buf));
44 if (ret != strlen(buf)) {
45 printf("Failed to write to /proc/sys/kernel/msg_next_id\n");
46 return -errno;
47 }
48
49 id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL);
50 if (id == -1) {
51 printf("Failed to create queue\n");
52 return -errno;
53 }
54
55 if (id != msgque->msq_id) {
56 printf("Restored queue has wrong id (%d instead of %d)\n",
57 id, msgque->msq_id);
58 ret = -EFAULT;
59 goto destroy;
60 }
61
62 for (i = 0; i < msgque->qnum; i++) {
63 if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype,
64 msgque->messages[i].msize, IPC_NOWAIT) != 0) {
65 printf("msgsnd failed (%m)\n");
66 ret = -errno;
67 goto destroy;
68 };
69 }
70 return 0;
71
72destroy:
73 if (msgctl(id, IPC_RMID, 0))
74 printf("Failed to destroy queue: %d\n", -errno);
75 return ret;
76}
77
78int check_and_destroy_queue(struct msgque_data *msgque)
79{
80 struct msg1 message;
81 int cnt = 0, ret;
82
83 while (1) {
84 ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE,
85 0, IPC_NOWAIT);
86 if (ret < 0) {
87 if (errno == ENOMSG)
88 break;
89 printf("Failed to read IPC message: %m\n");
90 ret = -errno;
91 goto err;
92 }
93 if (ret != msgque->messages[cnt].msize) {
94 printf("Wrong message size: %d (expected %d)\n", ret,
95 msgque->messages[cnt].msize);
96 ret = -EINVAL;
97 goto err;
98 }
99 if (message.mtype != msgque->messages[cnt].mtype) {
100 printf("Wrong message type\n");
101 ret = -EINVAL;
102 goto err;
103 }
104 if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) {
105 printf("Wrong message content\n");
106 ret = -EINVAL;
107 goto err;
108 }
109 cnt++;
110 }
111
112 if (cnt != msgque->qnum) {
113 printf("Wrong message number\n");
114 ret = -EINVAL;
115 goto err;
116 }
117
118 ret = 0;
119err:
120 if (msgctl(msgque->msq_id, IPC_RMID, 0)) {
121 printf("Failed to destroy queue: %d\n", -errno);
122 return -errno;
123 }
124 return ret;
125}
126
127int dump_queue(struct msgque_data *msgque)
128{
129 struct msqid64_ds ds;
130 int kern_id;
131 int i, ret;
132
133 for (kern_id = 0; kern_id < 256; kern_id++) {
134 ret = msgctl(kern_id, MSG_STAT, &ds);
135 if (ret < 0) {
136 if (errno == -EINVAL)
137 continue;
138 printf("Failed to get stats for IPC queue with id %d\n",
139 kern_id);
140 return -errno;
141 }
142
143 if (ret == msgque->msq_id)
144 break;
145 }
146
147 msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum);
148 if (msgque->messages == NULL) {
149 printf("Failed to get stats for IPC queue\n");
150 return -ENOMEM;
151 }
152
153 msgque->qnum = ds.msg_qnum;
154 msgque->mode = ds.msg_perm.mode;
155 msgque->qbytes = ds.msg_qbytes;
156
157 for (i = 0; i < msgque->qnum; i++) {
158 ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype,
159 MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY);
160 if (ret < 0) {
161 printf("Failed to copy IPC message: %m (%d)\n", errno);
162 return -errno;
163 }
164 msgque->messages[i].msize = ret;
165 }
166 return 0;
167}
168
169int fill_msgque(struct msgque_data *msgque)
170{
171 struct msg1 msgbuf;
172
173 msgbuf.mtype = MSG_TYPE;
174 memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING));
175 if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING),
176 IPC_NOWAIT) != 0) {
177 printf("First message send failed (%m)\n");
178 return -errno;
179 };
180
181 msgbuf.mtype = ANOTHER_MSG_TYPE;
182 memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING));
183 if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING),
184 IPC_NOWAIT) != 0) {
185 printf("Second message send failed (%m)\n");
186 return -errno;
187 };
188 return 0;
189}
190
191int main(int argc, char **argv)
192{
193 int msg, pid, err;
194 struct msgque_data msgque;
195
196 msgque.key = ftok(argv[0], 822155650);
197 if (msgque.key == -1) {
198 printf("Can't make key\n");
199 return -errno;
200 }
201
202 msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
203 if (msgque.msq_id == -1) {
204 printf("Can't create queue\n");
205 goto err_out;
206 }
207
208 err = fill_msgque(&msgque);
209 if (err) {
210 printf("Failed to fill queue\n");
211 goto err_destroy;
212 }
213
214 err = dump_queue(&msgque);
215 if (err) {
216 printf("Failed to dump queue\n");
217 goto err_destroy;
218 }
219
220 err = check_and_destroy_queue(&msgque);
221 if (err) {
222 printf("Failed to check and destroy queue\n");
223 goto err_out;
224 }
225
226 err = restore_queue(&msgque);
227 if (err) {
228 printf("Failed to restore queue\n");
229 goto err_destroy;
230 }
231
232 err = check_and_destroy_queue(&msgque);
233 if (err) {
234 printf("Failed to test queue\n");
235 goto err_out;
236 }
237 return 0;
238
239err_destroy:
240 if (msgctl(msgque.msq_id, IPC_RMID, 0)) {
241 printf("Failed to destroy queue: %d\n", -errno);
242 return -errno;
243 }
244err_out:
245 return err;
246}
diff --git a/tools/testing/selftests/kcmp/Makefile b/tools/testing/selftests/kcmp/Makefile
index dc79b86ea65c..56eb5523dbb8 100644
--- a/tools/testing/selftests/kcmp/Makefile
+++ b/tools/testing/selftests/kcmp/Makefile
@@ -16,13 +16,13 @@ CFLAGS += -I../../../../arch/x86/include/
16 16
17all: 17all:
18ifeq ($(ARCH),X86) 18ifeq ($(ARCH),X86)
19 gcc $(CFLAGS) kcmp_test.c -o run_test 19 gcc $(CFLAGS) kcmp_test.c -o kcmp_test
20else 20else
21 echo "Not an x86 target, can't build kcmp selftest" 21 echo "Not an x86 target, can't build kcmp selftest"
22endif 22endif
23 23
24run-tests: all 24run_tests: all
25 ./kcmp_test 25 @./kcmp_test || echo "kcmp_test: [FAIL]"
26 26
27clean: 27clean:
28 rm -fr ./run_test 28 rm -fr ./run_test
diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c
index 358cc6bfa35d..fa4f1b37e045 100644
--- a/tools/testing/selftests/kcmp/kcmp_test.c
+++ b/tools/testing/selftests/kcmp/kcmp_test.c
@@ -72,7 +72,8 @@ int main(int argc, char **argv)
72 /* This one should return same fd */ 72 /* This one should return same fd */
73 ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd1); 73 ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd1);
74 if (ret) { 74 if (ret) {
75 printf("FAIL: 0 expected but %d returned\n", ret); 75 printf("FAIL: 0 expected but %d returned (%s)\n",
76 ret, strerror(errno));
76 ret = -1; 77 ret = -1;
77 } else 78 } else
78 printf("PASS: 0 returned as expected\n"); 79 printf("PASS: 0 returned as expected\n");
@@ -80,7 +81,8 @@ int main(int argc, char **argv)
80 /* Compare with self */ 81 /* Compare with self */
81 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0); 82 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0);
82 if (ret) { 83 if (ret) {
83 printf("FAIL: 0 expected but %li returned\n", ret); 84 printf("FAIL: 0 expected but %li returned (%s)\n",
85 ret, strerror(errno));
84 ret = -1; 86 ret = -1;
85 } else 87 } else
86 printf("PASS: 0 returned as expected\n"); 88 printf("PASS: 0 returned as expected\n");
diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile
index 7c9c20ff578a..0f49c3f5f58d 100644
--- a/tools/testing/selftests/memory-hotplug/Makefile
+++ b/tools/testing/selftests/memory-hotplug/Makefile
@@ -1,6 +1,6 @@
1all: 1all:
2 2
3run_tests: 3run_tests:
4 ./on-off-test.sh 4 @./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]"
5 5
6clean: 6clean:
diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile
index 54c0aad2b47c..218a122c7951 100644
--- a/tools/testing/selftests/mqueue/Makefile
+++ b/tools/testing/selftests/mqueue/Makefile
@@ -3,8 +3,8 @@ all:
3 gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c 3 gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c
4 4
5run_tests: 5run_tests:
6 ./mq_open_tests /test1 6 @./mq_open_tests /test1 || echo "mq_open_tests: [FAIL]"
7 ./mq_perf_tests 7 @./mq_perf_tests || echo "mq_perf_tests: [FAIL]"
8 8
9clean: 9clean:
10 rm -f mq_open_tests mq_perf_tests 10 rm -f mq_open_tests mq_perf_tests
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index b336b24aa6c0..436d2e81868b 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -1,14 +1,14 @@
1# Makefile for vm selftests 1# Makefile for vm selftests
2 2
3CC = $(CROSS_COMPILE)gcc 3CC = $(CROSS_COMPILE)gcc
4CFLAGS = -Wall -Wextra 4CFLAGS = -Wall
5 5
6all: hugepage-mmap hugepage-shm map_hugetlb 6all: hugepage-mmap hugepage-shm map_hugetlb thuge-gen
7%: %.c 7%: %.c
8 $(CC) $(CFLAGS) -o $@ $^ 8 $(CC) $(CFLAGS) -o $@ $^
9 9
10run_tests: all 10run_tests: all
11 /bin/sh ./run_vmtests 11 @/bin/sh ./run_vmtests || echo "vmtests: [FAIL]"
12 12
13clean: 13clean:
14 $(RM) hugepage-mmap hugepage-shm map_hugetlb 14 $(RM) hugepage-mmap hugepage-shm map_hugetlb
diff --git a/tools/testing/selftests/vm/thuge-gen.c b/tools/testing/selftests/vm/thuge-gen.c
new file mode 100644
index 000000000000..c87957295f74
--- /dev/null
+++ b/tools/testing/selftests/vm/thuge-gen.c
@@ -0,0 +1,254 @@
1/* Test selecting other page sizes for mmap/shmget.
2
3 Before running this huge pages for each huge page size must have been
4 reserved.
5 For large pages beyond MAX_ORDER (like 1GB on x86) boot options must be used.
6 Also shmmax must be increased.
7 And you need to run as root to work around some weird permissions in shm.
8 And nothing using huge pages should run in parallel.
9 When the program aborts you may need to clean up the shm segments with
10 ipcrm -m by hand, like this
11 sudo ipcs | awk '$1 == "0x00000000" {print $2}' | xargs -n1 sudo ipcrm -m
12 (warning this will remove all if someone else uses them) */
13
14#define _GNU_SOURCE 1
15#include <sys/mman.h>
16#include <stdlib.h>
17#include <stdio.h>
18#include <sys/ipc.h>
19#include <sys/shm.h>
20#include <sys/stat.h>
21#include <glob.h>
22#include <assert.h>
23#include <unistd.h>
24#include <stdarg.h>
25#include <string.h>
26
27#define err(x) perror(x), exit(1)
28
29#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
30#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT)
31#define MAP_HUGE_SHIFT 26
32#define MAP_HUGE_MASK 0x3f
33#define MAP_HUGETLB 0x40000
34
35#define SHM_HUGETLB 04000 /* segment will use huge TLB pages */
36#define SHM_HUGE_SHIFT 26
37#define SHM_HUGE_MASK 0x3f
38#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT)
39#define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT)
40
41#define NUM_PAGESIZES 5
42
43#define NUM_PAGES 4
44
45#define Dprintf(fmt...) // printf(fmt)
46
47unsigned long page_sizes[NUM_PAGESIZES];
48int num_page_sizes;
49
50int ilog2(unsigned long v)
51{
52 int l = 0;
53 while ((1UL << l) < v)
54 l++;
55 return l;
56}
57
58void find_pagesizes(void)
59{
60 glob_t g;
61 int i;
62 glob("/sys/kernel/mm/hugepages/hugepages-*kB", 0, NULL, &g);
63 assert(g.gl_pathc <= NUM_PAGESIZES);
64 for (i = 0; i < g.gl_pathc; i++) {
65 sscanf(g.gl_pathv[i], "/sys/kernel/mm/hugepages/hugepages-%lukB",
66 &page_sizes[i]);
67 page_sizes[i] <<= 10;
68 printf("Found %luMB\n", page_sizes[i] >> 20);
69 }
70 num_page_sizes = g.gl_pathc;
71 globfree(&g);
72}
73
74unsigned long default_huge_page_size(void)
75{
76 unsigned long hps = 0;
77 char *line = NULL;
78 size_t linelen = 0;
79 FILE *f = fopen("/proc/meminfo", "r");
80 if (!f)
81 return 0;
82 while (getline(&line, &linelen, f) > 0) {
83 if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
84 hps <<= 10;
85 break;
86 }
87 }
88 free(line);
89 return hps;
90}
91
92void show(unsigned long ps)
93{
94 char buf[100];
95 if (ps == getpagesize())
96 return;
97 printf("%luMB: ", ps >> 20);
98 fflush(stdout);
99 snprintf(buf, sizeof buf,
100 "cat /sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
101 ps >> 10);
102 system(buf);
103}
104
105unsigned long read_sysfs(int warn, char *fmt, ...)
106{
107 char *line = NULL;
108 size_t linelen = 0;
109 char buf[100];
110 FILE *f;
111 va_list ap;
112 unsigned long val = 0;
113
114 va_start(ap, fmt);
115 vsnprintf(buf, sizeof buf, fmt, ap);
116 va_end(ap);
117
118 f = fopen(buf, "r");
119 if (!f) {
120 if (warn)
121 printf("missing %s\n", buf);
122 return 0;
123 }
124 if (getline(&line, &linelen, f) > 0) {
125 sscanf(line, "%lu", &val);
126 }
127 fclose(f);
128 free(line);
129 return val;
130}
131
132unsigned long read_free(unsigned long ps)
133{
134 return read_sysfs(ps != getpagesize(),
135 "/sys/kernel/mm/hugepages/hugepages-%lukB/free_hugepages",
136 ps >> 10);
137}
138
139void test_mmap(unsigned long size, unsigned flags)
140{
141 char *map;
142 unsigned long before, after;
143 int err;
144
145 before = read_free(size);
146 map = mmap(NULL, size*NUM_PAGES, PROT_READ|PROT_WRITE,
147 MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|flags, 0, 0);
148
149 if (map == (char *)-1) err("mmap");
150 memset(map, 0xff, size*NUM_PAGES);
151 after = read_free(size);
152 Dprintf("before %lu after %lu diff %ld size %lu\n",
153 before, after, before - after, size);
154 assert(size == getpagesize() || (before - after) == NUM_PAGES);
155 show(size);
156 err = munmap(map, size);
157 assert(!err);
158}
159
160void test_shmget(unsigned long size, unsigned flags)
161{
162 int id;
163 unsigned long before, after;
164 int err;
165
166 before = read_free(size);
167 id = shmget(IPC_PRIVATE, size * NUM_PAGES, IPC_CREAT|0600|flags);
168 if (id < 0) err("shmget");
169
170 struct shm_info i;
171 if (shmctl(id, SHM_INFO, (void *)&i) < 0) err("shmctl");
172 Dprintf("alloc %lu res %lu\n", i.shm_tot, i.shm_rss);
173
174
175 Dprintf("id %d\n", id);
176 char *map = shmat(id, NULL, 0600);
177 if (map == (char*)-1) err("shmat");
178
179 shmctl(id, IPC_RMID, NULL);
180
181 memset(map, 0xff, size*NUM_PAGES);
182 after = read_free(size);
183
184 Dprintf("before %lu after %lu diff %ld size %lu\n",
185 before, after, before - after, size);
186 assert(size == getpagesize() || (before - after) == NUM_PAGES);
187 show(size);
188 err = shmdt(map);
189 assert(!err);
190}
191
192void sanity_checks(void)
193{
194 int i;
195 unsigned long largest = getpagesize();
196
197 for (i = 0; i < num_page_sizes; i++) {
198 if (page_sizes[i] > largest)
199 largest = page_sizes[i];
200
201 if (read_free(page_sizes[i]) < NUM_PAGES) {
202 printf("Not enough huge pages for page size %lu MB, need %u\n",
203 page_sizes[i] >> 20,
204 NUM_PAGES);
205 exit(0);
206 }
207 }
208
209 if (read_sysfs(0, "/proc/sys/kernel/shmmax") < NUM_PAGES * largest) {
210 printf("Please do echo %lu > /proc/sys/kernel/shmmax", largest * NUM_PAGES);
211 exit(0);
212 }
213
214#if defined(__x86_64__)
215 if (largest != 1U<<30) {
216 printf("No GB pages available on x86-64\n"
217 "Please boot with hugepagesz=1G hugepages=%d\n", NUM_PAGES);
218 exit(0);
219 }
220#endif
221}
222
223int main(void)
224{
225 int i;
226 unsigned default_hps = default_huge_page_size();
227
228 find_pagesizes();
229
230 sanity_checks();
231
232 for (i = 0; i < num_page_sizes; i++) {
233 unsigned long ps = page_sizes[i];
234 int arg = ilog2(ps) << MAP_HUGE_SHIFT;
235 printf("Testing %luMB mmap with shift %x\n", ps >> 20, arg);
236 test_mmap(ps, MAP_HUGETLB | arg);
237 }
238 printf("Testing default huge mmap\n");
239 test_mmap(default_hps, SHM_HUGETLB);
240
241 puts("Testing non-huge shmget");
242 test_shmget(getpagesize(), 0);
243
244 for (i = 0; i < num_page_sizes; i++) {
245 unsigned long ps = page_sizes[i];
246 int arg = ilog2(ps) << SHM_HUGE_SHIFT;
247 printf("Testing %luMB shmget with shift %x\n", ps >> 20, arg);
248 test_shmget(ps, SHM_HUGETLB | arg);
249 }
250 puts("default huge shmget");
251 test_shmget(default_hps, SHM_HUGETLB);
252
253 return 0;
254}
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index 8674b9ec14f6..fe1e66b6ef40 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -38,7 +38,7 @@
38#include <unistd.h> 38#include <unistd.h>
39#include <tools/le_byteshift.h> 39#include <tools/le_byteshift.h>
40 40
41#include "../../include/linux/usb/functionfs.h" 41#include "../../include/uapi/linux/usb/functionfs.h"
42 42
43 43
44/******************** Little Endian Handling ********************************/ 44/******************** Little Endian Handling ********************************/
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index 68d0734b2081..879f9870a6bc 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -279,8 +279,7 @@ nomem:
279 279
280 entry->ifnum = ifnum; 280 entry->ifnum = ifnum;
281 281
282 /* FIXME ask usbfs what speed; update USBDEVFS_CONNECTINFO so 282 /* FIXME update USBDEVFS_CONNECTINFO so it tells about high speed etc */
283 * it tells about high speed etc */
284 283
285 fprintf(stderr, "%s speed\t%s\t%u\n", 284 fprintf(stderr, "%s speed\t%s\t%u\n",
286 speed(entry->speed), entry->name, entry->ifnum); 285 speed(entry->speed), entry->name, entry->ifnum);
@@ -351,7 +350,7 @@ restart:
351 return arg; 350 return arg;
352} 351}
353 352
354static const char *usbfs_dir_find(void) 353static const char *usb_dir_find(void)
355{ 354{
356 static char udev_usb_path[] = "/dev/bus/usb"; 355 static char udev_usb_path[] = "/dev/bus/usb";
357 356
@@ -380,7 +379,7 @@ int main (int argc, char **argv)
380 int c; 379 int c;
381 struct testdev *entry; 380 struct testdev *entry;
382 char *device; 381 char *device;
383 const char *usbfs_dir = NULL; 382 const char *usb_dir = NULL;
384 int all = 0, forever = 0, not = 0; 383 int all = 0, forever = 0, not = 0;
385 int test = -1 /* all */; 384 int test = -1 /* all */;
386 struct usbtest_param param; 385 struct usbtest_param param;
@@ -407,8 +406,8 @@ int main (int argc, char **argv)
407 case 'D': /* device, if only one */ 406 case 'D': /* device, if only one */
408 device = optarg; 407 device = optarg;
409 continue; 408 continue;
410 case 'A': /* use all devices with specified usbfs dir */ 409 case 'A': /* use all devices with specified USB dir */
411 usbfs_dir = optarg; 410 usb_dir = optarg;
412 /* FALL THROUGH */ 411 /* FALL THROUGH */
413 case 'a': /* use all devices */ 412 case 'a': /* use all devices */
414 device = NULL; 413 device = NULL;
@@ -449,7 +448,7 @@ usage:
449 "usage: %s [options]\n" 448 "usage: %s [options]\n"
450 "Options:\n" 449 "Options:\n"
451 "\t-D dev only test specific device\n" 450 "\t-D dev only test specific device\n"
452 "\t-A usbfs-dir\n" 451 "\t-A usb-dir\n"
453 "\t-a test all recognized devices\n" 452 "\t-a test all recognized devices\n"
454 "\t-l loop forever(for stress test)\n" 453 "\t-l loop forever(for stress test)\n"
455 "\t-t testnum only run specified case\n" 454 "\t-t testnum only run specified case\n"
@@ -470,18 +469,18 @@ usage:
470 goto usage; 469 goto usage;
471 } 470 }
472 471
473 /* Find usbfs mount point */ 472 /* Find usb device subdirectory */
474 if (!usbfs_dir) { 473 if (!usb_dir) {
475 usbfs_dir = usbfs_dir_find(); 474 usb_dir = usb_dir_find();
476 if (!usbfs_dir) { 475 if (!usb_dir) {
477 fputs ("usbfs files are missing\n", stderr); 476 fputs ("USB device files are missing\n", stderr);
478 return -1; 477 return -1;
479 } 478 }
480 } 479 }
481 480
482 /* collect and list the test devices */ 481 /* collect and list the test devices */
483 if (ftw (usbfs_dir, find_testdev, 3) != 0) { 482 if (ftw (usb_dir, find_testdev, 3) != 0) {
484 fputs ("ftw failed; is usbfs missing?\n", stderr); 483 fputs ("ftw failed; are USB device files missing?\n", stderr);
485 return -1; 484 return -1;
486 } 485 }
487 486
@@ -507,10 +506,8 @@ usage:
507 return handle_testdev (entry) != entry; 506 return handle_testdev (entry) != entry;
508 } 507 }
509 status = pthread_create (&entry->thread, 0, handle_testdev, entry); 508 status = pthread_create (&entry->thread, 0, handle_testdev, entry);
510 if (status) { 509 if (status)
511 perror ("pthread_create"); 510 perror ("pthread_create");
512 continue;
513 }
514 } 511 }
515 if (device) { 512 if (device) {
516 struct testdev dev; 513 struct testdev dev;
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index e626fa553c5a..fcc9aa25fd08 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -164,7 +164,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
164 r = virtqueue_add_buf(vq->vq, &sl, 1, 0, 164 r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
165 dev->buf + started, 165 dev->buf + started,
166 GFP_ATOMIC); 166 GFP_ATOMIC);
167 if (likely(r >= 0)) { 167 if (likely(r == 0)) {
168 ++started; 168 ++started;
169 virtqueue_kick(vq->vq); 169 virtqueue_kick(vq->vq);
170 } 170 }
@@ -177,7 +177,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
177 r = 0; 177 r = 0;
178 } 178 }
179 179
180 } while (r >= 0); 180 } while (r == 0);
181 if (completed == completed_before) 181 if (completed == completed_before)
182 ++spurious; 182 ++spurious;
183 assert(completed <= bufs); 183 assert(completed <= bufs);
@@ -232,7 +232,7 @@ const struct option longopts[] = {
232 } 232 }
233}; 233};
234 234
235static void help() 235static void help(void)
236{ 236{
237 fprintf(stderr, "Usage: virtio_test [--help]" 237 fprintf(stderr, "Usage: virtio_test [--help]"
238 " [--no-indirect]" 238 " [--no-indirect]"
diff --git a/tools/vm/.gitignore b/tools/vm/.gitignore
new file mode 100644
index 000000000000..44f095fa2604
--- /dev/null
+++ b/tools/vm/.gitignore
@@ -0,0 +1,2 @@
1slabinfo
2page-types