aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMichal Marek <mmarek@suse.cz>2011-03-09 10:15:44 -0500
committerMichal Marek <mmarek@suse.cz>2011-03-09 10:15:44 -0500
commit2d8ad8719591fa803b0d589ed057fa46f49b7155 (patch)
tree4ae051577dad1161c91dafbf4207bb10a9dc91bb /tools
parent9b4ce7bce5f30712fd926ab4599a803314a07719 (diff)
parentc56eb8fb6dccb83d9fe62fd4dc00c834de9bc470 (diff)
Merge commit 'v2.6.38-rc1' into kbuild/packaging
Diffstat (limited to 'tools')
-rw-r--r--tools/firewire/Makefile19
-rw-r--r--tools/firewire/decode-fcp.c213
-rw-r--r--tools/firewire/list.h62
-rw-r--r--tools/firewire/nosy-dump.c1031
-rw-r--r--tools/firewire/nosy-dump.h173
-rw-r--r--tools/perf/.gitignore4
-rw-r--r--tools/perf/Documentation/Makefile4
-rw-r--r--tools/perf/Documentation/perf-annotate.txt48
-rw-r--r--tools/perf/Documentation/perf-archive.txt22
-rw-r--r--tools/perf/Documentation/perf-bench.txt8
-rw-r--r--tools/perf/Documentation/perf-buildid-cache.txt33
-rw-r--r--tools/perf/Documentation/perf-buildid-list.txt3
-rw-r--r--tools/perf/Documentation/perf-diff.txt23
-rw-r--r--tools/perf/Documentation/perf-inject.txt35
-rw-r--r--tools/perf/Documentation/perf-kmem.txt2
-rw-r--r--tools/perf/Documentation/perf-kvm.txt74
-rw-r--r--tools/perf/Documentation/perf-list.txt50
-rw-r--r--tools/perf/Documentation/perf-lock.txt44
-rw-r--r--tools/perf/Documentation/perf-probe.txt115
-rw-r--r--tools/perf/Documentation/perf-record.txt46
-rw-r--r--tools/perf/Documentation/perf-report.txt62
-rw-r--r--tools/perf/Documentation/perf-sched.txt20
-rw-r--r--tools/perf/Documentation/perf-script-perl.txt (renamed from tools/perf/Documentation/perf-trace-perl.txt)34
-rw-r--r--tools/perf/Documentation/perf-script-python.txt623
-rw-r--r--tools/perf/Documentation/perf-script.txt118
-rw-r--r--tools/perf/Documentation/perf-stat.txt54
-rw-r--r--tools/perf/Documentation/perf-test.txt22
-rw-r--r--tools/perf/Documentation/perf-timechart.txt2
-rw-r--r--tools/perf/Documentation/perf-top.txt34
-rw-r--r--tools/perf/Documentation/perf-trace.txt59
-rw-r--r--tools/perf/Documentation/perf.txt2
-rw-r--r--tools/perf/MANIFEST13
-rw-r--r--tools/perf/Makefile574
-rw-r--r--tools/perf/arch/arm/Makefile4
-rw-r--r--tools/perf/arch/arm/util/dwarf-regs.c64
-rw-r--r--tools/perf/arch/powerpc/Makefile4
-rw-r--r--tools/perf/arch/powerpc/util/dwarf-regs.c88
-rw-r--r--tools/perf/arch/s390/Makefile4
-rw-r--r--tools/perf/arch/s390/util/dwarf-regs.c22
-rw-r--r--tools/perf/arch/sh/Makefile4
-rw-r--r--tools/perf/arch/sh/util/dwarf-regs.c55
-rw-r--r--tools/perf/arch/sparc/Makefile4
-rw-r--r--tools/perf/arch/sparc/util/dwarf-regs.c43
-rw-r--r--tools/perf/arch/x86/Makefile4
-rw-r--r--tools/perf/arch/x86/util/dwarf-regs.c75
-rw-r--r--tools/perf/bench/mem-memcpy-arch.h12
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm-def.h4
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm.S2
-rw-r--r--tools/perf/bench/mem-memcpy.c220
-rw-r--r--tools/perf/bench/sched-messaging.c10
-rw-r--r--tools/perf/bench/sched-pipe.c2
-rw-r--r--tools/perf/builtin-annotate.c362
-rw-r--r--tools/perf/builtin-bench.c4
-rw-r--r--tools/perf/builtin-buildid-cache.c132
-rw-r--r--tools/perf/builtin-buildid-list.c41
-rw-r--r--tools/perf/builtin-diff.c141
-rw-r--r--tools/perf/builtin-help.c13
-rw-r--r--tools/perf/builtin-inject.c237
-rw-r--r--tools/perf/builtin-kmem.c85
-rw-r--r--tools/perf/builtin-kvm.c144
-rw-r--r--tools/perf/builtin-lock.c1004
-rw-r--r--tools/perf/builtin-probe.c335
-rw-r--r--tools/perf/builtin-record.c748
-rw-r--r--tools/perf/builtin-report.c379
-rw-r--r--tools/perf/builtin-sched.c114
-rw-r--r--tools/perf/builtin-script.c (renamed from tools/perf/builtin-trace.c)403
-rw-r--r--tools/perf/builtin-stat.c598
-rw-r--r--tools/perf/builtin-test.c497
-rw-r--r--tools/perf/builtin-timechart.c275
-rw-r--r--tools/perf/builtin-top.c577
-rw-r--r--tools/perf/builtin.h7
-rw-r--r--tools/perf/command-list.txt8
-rw-r--r--tools/perf/design.txt8
-rw-r--r--tools/perf/feature-tests.mak130
-rw-r--r--tools/perf/perf-archive.sh46
-rw-r--r--tools/perf/perf.c60
-rw-r--r--tools/perf/perf.h25
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.c7
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.xs5
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/README4
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm2
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm4
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm12
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-record7
-rw-r--r--tools/perf/scripts/perl/bin/check-perf-trace-report6
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-record2
-rw-r--r--tools/perf/scripts/perl/bin/failed-syscalls-report10
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-record3
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-file-report11
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report5
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-record2
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-report20
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-record2
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report5
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report6
-rw-r--r--tools/perf/scripts/perl/check-perf-trace.pl2
-rw-r--r--tools/perf/scripts/perl/failed-syscalls.pl42
-rw-r--r--tools/perf/scripts/perl/rw-by-file.pl2
-rw-r--r--tools/perf/scripts/perl/rw-by-pid.pl60
-rw-r--r--tools/perf/scripts/perl/rwtop.pl199
-rw-r--r--tools/perf/scripts/perl/wakeup-latency.pl12
-rw-r--r--tools/perf/scripts/perl/workqueue-stats.pl14
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/Context.c88
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py121
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py184
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py86
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-record2
-rw-r--r--tools/perf/scripts/python/bin/failed-syscalls-by-pid-report10
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-record2
-rw-r--r--tools/perf/scripts/python/bin/futex-contention-report4
-rw-r--r--tools/perf/scripts/python/bin/netdev-times-record8
-rw-r--r--tools/perf/scripts/python/bin/netdev-times-report5
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-record2
-rw-r--r--tools/perf/scripts/python/bin/sched-migration-report3
-rw-r--r--tools/perf/scripts/python/bin/sctop-record2
-rw-r--r--tools/perf/scripts/python/bin/sctop-report24
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-by-pid-report10
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-record2
-rw-r--r--tools/perf/scripts/python/bin/syscall-counts-report10
-rw-r--r--tools/perf/scripts/python/check-perf-trace.py82
-rw-r--r--tools/perf/scripts/python/failed-syscalls-by-pid.py73
-rw-r--r--tools/perf/scripts/python/futex-contention.py50
-rw-r--r--tools/perf/scripts/python/netdev-times.py464
-rw-r--r--tools/perf/scripts/python/sched-migration.py461
-rw-r--r--tools/perf/scripts/python/sctop.py75
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py69
-rw-r--r--tools/perf/scripts/python/syscall-counts.py59
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN23
-rw-r--r--tools/perf/util/abspath.c81
-rw-r--r--tools/perf/util/bitmap.c21
-rw-r--r--tools/perf/util/build-id.c80
-rw-r--r--tools/perf/util/build-id.h10
-rw-r--r--tools/perf/util/cache.h70
-rw-r--r--tools/perf/util/callchain.c205
-rw-r--r--tools/perf/util/callchain.h32
-rw-r--r--tools/perf/util/color.c48
-rw-r--r--tools/perf/util/color.h4
-rw-r--r--tools/perf/util/config.c495
-rw-r--r--tools/perf/util/cpumap.c179
-rw-r--r--tools/perf/util/cpumap.h13
-rw-r--r--tools/perf/util/data_map.c252
-rw-r--r--tools/perf/util/debug.c57
-rw-r--r--tools/perf/util/debug.h31
-rw-r--r--tools/perf/util/debugfs.c17
-rw-r--r--tools/perf/util/debugfs.h2
-rw-r--r--tools/perf/util/event.c754
-rw-r--r--tools/perf/util/event.h158
-rw-r--r--tools/perf/util/evsel.c201
-rw-r--r--tools/perf/util/evsel.h115
-rw-r--r--tools/perf/util/exec_cmd.c6
-rw-r--r--tools/perf/util/exec_cmd.h1
-rw-r--r--tools/perf/util/header.c789
-rw-r--r--tools/perf/util/header.h47
-rw-r--r--tools/perf/util/help.c30
-rw-r--r--tools/perf/util/hist.c767
-rw-r--r--tools/perf/util/hist.h143
-rw-r--r--tools/perf/util/hweight.c31
-rw-r--r--tools/perf/util/include/asm/bitops.h18
-rw-r--r--tools/perf/util/include/asm/cpufeature.h9
-rw-r--r--tools/perf/util/include/asm/dwarf2.h11
-rw-r--r--tools/perf/util/include/asm/hweight.h8
-rw-r--r--tools/perf/util/include/dwarf-regs.h8
-rw-r--r--tools/perf/util/include/linux/bitmap.h38
-rw-r--r--tools/perf/util/include/linux/bitops.h25
-rw-r--r--tools/perf/util/include/linux/compiler.h2
-rw-r--r--tools/perf/util/include/linux/hash.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h12
-rw-r--r--tools/perf/util/include/linux/linkage.h13
-rw-r--r--tools/perf/util/include/linux/list.h8
-rw-r--r--tools/perf/util/include/linux/types.h12
-rw-r--r--tools/perf/util/map.c555
-rw-r--r--tools/perf/util/map.h237
-rw-r--r--tools/perf/util/parse-events.c231
-rw-r--r--tools/perf/util/parse-events.h18
-rw-r--r--tools/perf/util/parse-options.c55
-rw-r--r--tools/perf/util/parse-options.h33
-rw-r--r--tools/perf/util/path.c207
-rw-r--r--tools/perf/util/probe-event.c1836
-rw-r--r--tools/perf/util/probe-event.h135
-rw-r--r--tools/perf/util/probe-finder.c2177
-rw-r--r--tools/perf/util/probe-finder.h100
-rw-r--r--tools/perf/util/pstack.c75
-rw-r--r--tools/perf/util/pstack.h14
-rw-r--r--tools/perf/util/quote.c433
-rw-r--r--tools/perf/util/quote.h39
-rw-r--r--tools/perf/util/run-command.c90
-rw-r--r--tools/perf/util/run-command.h30
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c (renamed from tools/perf/util/trace-event-perl.c)124
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c594
-rw-r--r--tools/perf/util/session.c1038
-rw-r--r--tools/perf/util/session.h144
-rw-r--r--tools/perf/util/sigchain.c2
-rw-r--r--tools/perf/util/sigchain.h1
-rw-r--r--tools/perf/util/sort.c187
-rw-r--r--tools/perf/util/sort.h55
-rw-r--r--tools/perf/util/strbuf.c229
-rw-r--r--tools/perf/util/strbuf.h45
-rw-r--r--tools/perf/util/string.c143
-rw-r--r--tools/perf/util/string.h17
-rw-r--r--tools/perf/util/symbol.c1536
-rw-r--r--tools/perf/util/symbol.h129
-rw-r--r--tools/perf/util/thread.c250
-rw-r--r--tools/perf/util/thread.h66
-rw-r--r--tools/perf/util/trace-event-info.c115
-rw-r--r--tools/perf/util/trace-event-parse.c142
-rw-r--r--tools/perf/util/trace-event-perl.h55
-rw-r--r--tools/perf/util/trace-event-read.c139
-rw-r--r--tools/perf/util/trace-event-scripting.c167
-rw-r--r--tools/perf/util/trace-event.h26
-rw-r--r--tools/perf/util/ui/browser.c337
-rw-r--r--tools/perf/util/ui/browser.h51
-rw-r--r--tools/perf/util/ui/browsers/annotate.c237
-rw-r--r--tools/perf/util/ui/browsers/hists.c1013
-rw-r--r--tools/perf/util/ui/browsers/map.c155
-rw-r--r--tools/perf/util/ui/browsers/map.h6
-rw-r--r--tools/perf/util/ui/helpline.c69
-rw-r--r--tools/perf/util/ui/helpline.h11
-rw-r--r--tools/perf/util/ui/libslang.h27
-rw-r--r--tools/perf/util/ui/progress.c60
-rw-r--r--tools/perf/util/ui/progress.h11
-rw-r--r--tools/perf/util/ui/setup.c42
-rw-r--r--tools/perf/util/ui/util.c127
-rw-r--r--tools/perf/util/ui/util.h10
-rw-r--r--tools/perf/util/util.c133
-rw-r--r--tools/perf/util/util.h181
-rw-r--r--tools/perf/util/values.c1
-rw-r--r--tools/perf/util/wrapper.c110
-rw-r--r--tools/perf/util/xyarray.c20
-rw-r--r--tools/perf/util/xyarray.h20
-rw-r--r--tools/power/x86/turbostat/Makefile8
-rw-r--r--tools/power/x86/turbostat/turbostat.8172
-rw-r--r--tools/power/x86/turbostat/turbostat.c1048
-rw-r--r--tools/power/x86/x86_energy_perf_policy/Makefile8
-rw-r--r--tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8104
-rw-r--r--tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c325
-rw-r--r--tools/slub/slabinfo.c1364
-rwxr-xr-xtools/testing/ktest/compare-ktest-sample.pl30
-rwxr-xr-xtools/testing/ktest/ktest.pl2023
-rw-r--r--tools/testing/ktest/sample.conf622
-rw-r--r--tools/usb/ffs-test.c554
-rw-r--r--tools/usb/testusb.c547
-rw-r--r--tools/virtio/Makefile12
-rw-r--r--tools/virtio/linux/device.h2
-rw-r--r--tools/virtio/linux/slab.h2
-rw-r--r--tools/virtio/linux/virtio.h223
-rw-r--r--tools/virtio/vhost_test/Makefile2
-rw-r--r--tools/virtio/vhost_test/vhost_test.c1
-rw-r--r--tools/virtio/virtio_test.c248
251 files changed, 32134 insertions, 7048 deletions
diff --git a/tools/firewire/Makefile b/tools/firewire/Makefile
new file mode 100644
index 000000000000..81767adaae7d
--- /dev/null
+++ b/tools/firewire/Makefile
@@ -0,0 +1,19 @@
1prefix = /usr
2nosy-dump-version = 0.4
3
4CC = gcc
5
6all : nosy-dump
7
8nosy-dump : CFLAGS = -Wall -O2 -g
9nosy-dump : CPPFLAGS = -DVERSION=\"$(nosy-dump-version)\" -I../../drivers/firewire
10nosy-dump : LDFLAGS = -g
11nosy-dump : LDLIBS = -lpopt
12
13nosy-dump : nosy-dump.o decode-fcp.o
14
15clean :
16 rm -rf *.o nosy-dump
17
18install :
19 install nosy-dump $(prefix)/bin/nosy-dump
diff --git a/tools/firewire/decode-fcp.c b/tools/firewire/decode-fcp.c
new file mode 100644
index 000000000000..e41223b6a4c8
--- /dev/null
+++ b/tools/firewire/decode-fcp.c
@@ -0,0 +1,213 @@
1#include <linux/firewire-constants.h>
2#include <stdio.h>
3#include <stdlib.h>
4
5#include "list.h"
6#include "nosy-dump.h"
7
8#define CSR_FCP_COMMAND 0xfffff0000b00ull
9#define CSR_FCP_RESPONSE 0xfffff0000d00ull
10
11static const char * const ctype_names[] = {
12 [0x0] = "control", [0x8] = "not implemented",
13 [0x1] = "status", [0x9] = "accepted",
14 [0x2] = "specific inquiry", [0xa] = "rejected",
15 [0x3] = "notify", [0xb] = "in transition",
16 [0x4] = "general inquiry", [0xc] = "stable",
17 [0x5] = "(reserved 0x05)", [0xd] = "changed",
18 [0x6] = "(reserved 0x06)", [0xe] = "(reserved 0x0e)",
19 [0x7] = "(reserved 0x07)", [0xf] = "interim",
20};
21
22static const char * const subunit_type_names[] = {
23 [0x00] = "monitor", [0x10] = "(reserved 0x10)",
24 [0x01] = "audio", [0x11] = "(reserved 0x11)",
25 [0x02] = "printer", [0x12] = "(reserved 0x12)",
26 [0x03] = "disc", [0x13] = "(reserved 0x13)",
27 [0x04] = "tape recorder/player",[0x14] = "(reserved 0x14)",
28 [0x05] = "tuner", [0x15] = "(reserved 0x15)",
29 [0x06] = "ca", [0x16] = "(reserved 0x16)",
30 [0x07] = "camera", [0x17] = "(reserved 0x17)",
31 [0x08] = "(reserved 0x08)", [0x18] = "(reserved 0x18)",
32 [0x09] = "panel", [0x19] = "(reserved 0x19)",
33 [0x0a] = "bulletin board", [0x1a] = "(reserved 0x1a)",
34 [0x0b] = "camera storage", [0x1b] = "(reserved 0x1b)",
35 [0x0c] = "(reserved 0x0c)", [0x1c] = "vendor unique",
36 [0x0d] = "(reserved 0x0d)", [0x1d] = "all subunit types",
37 [0x0e] = "(reserved 0x0e)", [0x1e] = "subunit_type extended to next byte",
38 [0x0f] = "(reserved 0x0f)", [0x1f] = "unit",
39};
40
41struct avc_enum {
42 int value;
43 const char *name;
44};
45
46struct avc_field {
47 const char *name; /* Short name for field. */
48 int offset; /* Location of field, specified in bits; */
49 /* negative means from end of packet. */
50 int width; /* Width of field, 0 means use data_length. */
51 struct avc_enum *names;
52};
53
54struct avc_opcode_info {
55 const char *name;
56 struct avc_field fields[8];
57};
58
59struct avc_enum power_field_names[] = {
60 { 0x70, "on" },
61 { 0x60, "off" },
62 { }
63};
64
65static const struct avc_opcode_info opcode_info[256] = {
66
67 /* TA Document 1999026 */
68 /* AV/C Digital Interface Command Set General Specification 4.0 */
69 [0xb2] = { "power", {
70 { "state", 0, 8, power_field_names }
71 }
72 },
73 [0x30] = { "unit info", {
74 { "foo", 0, 8 },
75 { "unit_type", 8, 5 },
76 { "unit", 13, 3 },
77 { "company id", 16, 24 },
78 }
79 },
80 [0x31] = { "subunit info" },
81 [0x01] = { "reserve" },
82 [0xb0] = { "version" },
83 [0x00] = { "vendor dependent" },
84 [0x02] = { "plug info" },
85 [0x12] = { "channel usage" },
86 [0x24] = { "connect" },
87 [0x20] = { "connect av" },
88 [0x22] = { "connections" },
89 [0x11] = { "digital input" },
90 [0x10] = { "digital output" },
91 [0x25] = { "disconnect" },
92 [0x21] = { "disconnect av" },
93 [0x19] = { "input plug signal format" },
94 [0x18] = { "output plug signal format" },
95 [0x1f] = { "general bus setup" },
96
97 /* TA Document 1999025 */
98 /* AV/C Descriptor Mechanism Specification Version 1.0 */
99 [0x0c] = { "create descriptor" },
100 [0x08] = { "open descriptor" },
101 [0x09] = { "read descriptor" },
102 [0x0a] = { "write descriptor" },
103 [0x05] = { "open info block" },
104 [0x06] = { "read info block" },
105 [0x07] = { "write info block" },
106 [0x0b] = { "search descriptor" },
107 [0x0d] = { "object number select" },
108
109 /* TA Document 1999015 */
110 /* AV/C Command Set for Rate Control of Isochronous Data Flow 1.0 */
111 [0xb3] = { "rate", {
112 { "subfunction", 0, 8 },
113 { "result", 8, 8 },
114 { "plug_type", 16, 8 },
115 { "plug_id", 16, 8 },
116 }
117 },
118
119 /* TA Document 1999008 */
120 /* AV/C Audio Subunit Specification 1.0 */
121 [0xb8] = { "function block" },
122
123 /* TA Document 2001001 */
124 /* AV/C Panel Subunit Specification 1.1 */
125 [0x7d] = { "gui update" },
126 [0x7e] = { "push gui data" },
127 [0x7f] = { "user action" },
128 [0x7c] = { "pass through" },
129
130 /* */
131 [0x26] = { "asynchronous connection" },
132};
133
134struct avc_frame {
135 uint32_t operand0:8;
136 uint32_t opcode:8;
137 uint32_t subunit_id:3;
138 uint32_t subunit_type:5;
139 uint32_t ctype:4;
140 uint32_t cts:4;
141};
142
143static void
144decode_avc(struct link_transaction *t)
145{
146 struct avc_frame *frame =
147 (struct avc_frame *) t->request->packet.write_block.data;
148 const struct avc_opcode_info *info;
149 const char *name;
150 char buffer[32];
151 int i;
152
153 info = &opcode_info[frame->opcode];
154 if (info->name == NULL) {
155 snprintf(buffer, sizeof(buffer),
156 "(unknown opcode 0x%02x)", frame->opcode);
157 name = buffer;
158 } else {
159 name = info->name;
160 }
161
162 printf("av/c %s, subunit_type=%s, subunit_id=%d, opcode=%s",
163 ctype_names[frame->ctype], subunit_type_names[frame->subunit_type],
164 frame->subunit_id, name);
165
166 for (i = 0; info->fields[i].name != NULL; i++)
167 printf(", %s", info->fields[i].name);
168
169 printf("\n");
170}
171
172int
173decode_fcp(struct link_transaction *t)
174{
175 struct avc_frame *frame =
176 (struct avc_frame *) t->request->packet.write_block.data;
177 unsigned long long offset =
178 ((unsigned long long) t->request->packet.common.offset_high << 32) |
179 t->request->packet.common.offset_low;
180
181 if (t->request->packet.common.tcode != TCODE_WRITE_BLOCK_REQUEST)
182 return 0;
183
184 if (offset == CSR_FCP_COMMAND || offset == CSR_FCP_RESPONSE) {
185 switch (frame->cts) {
186 case 0x00:
187 decode_avc(t);
188 break;
189 case 0x01:
190 printf("cal fcp frame (cts=0x01)\n");
191 break;
192 case 0x02:
193 printf("ehs fcp frame (cts=0x02)\n");
194 break;
195 case 0x03:
196 printf("havi fcp frame (cts=0x03)\n");
197 break;
198 case 0x0e:
199 printf("vendor specific fcp frame (cts=0x0e)\n");
200 break;
201 case 0x0f:
202 printf("extended cts\n");
203 break;
204 default:
205 printf("reserved fcp frame (ctx=0x%02x)\n", frame->cts);
206 break;
207 }
208 return 1;
209 }
210
211 return 0;
212}
213
diff --git a/tools/firewire/list.h b/tools/firewire/list.h
new file mode 100644
index 000000000000..41f4bdadf634
--- /dev/null
+++ b/tools/firewire/list.h
@@ -0,0 +1,62 @@
1struct list {
2 struct list *next, *prev;
3};
4
5static inline void
6list_init(struct list *list)
7{
8 list->next = list;
9 list->prev = list;
10}
11
12static inline int
13list_empty(struct list *list)
14{
15 return list->next == list;
16}
17
18static inline void
19list_insert(struct list *link, struct list *new_link)
20{
21 new_link->prev = link->prev;
22 new_link->next = link;
23 new_link->prev->next = new_link;
24 new_link->next->prev = new_link;
25}
26
27static inline void
28list_append(struct list *list, struct list *new_link)
29{
30 list_insert((struct list *)list, new_link);
31}
32
33static inline void
34list_prepend(struct list *list, struct list *new_link)
35{
36 list_insert(list->next, new_link);
37}
38
39static inline void
40list_remove(struct list *link)
41{
42 link->prev->next = link->next;
43 link->next->prev = link->prev;
44}
45
46#define list_entry(link, type, member) \
47 ((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))
48
49#define list_head(list, type, member) \
50 list_entry((list)->next, type, member)
51
52#define list_tail(list, type, member) \
53 list_entry((list)->prev, type, member)
54
55#define list_next(elm, member) \
56 list_entry((elm)->member.next, typeof(*elm), member)
57
58#define list_for_each_entry(pos, list, member) \
59 for (pos = list_head(list, typeof(*pos), member); \
60 &pos->member != (list); \
61 pos = list_next(pos, member))
62
diff --git a/tools/firewire/nosy-dump.c b/tools/firewire/nosy-dump.c
new file mode 100644
index 000000000000..f93b776370b6
--- /dev/null
+++ b/tools/firewire/nosy-dump.c
@@ -0,0 +1,1031 @@
1/*
2 * nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
3 * Copyright (C) 2002-2006 Kristian Høgsberg
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
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 General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20#include <byteswap.h>
21#include <endian.h>
22#include <fcntl.h>
23#include <linux/firewire-constants.h>
24#include <poll.h>
25#include <popt.h>
26#include <signal.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/ioctl.h>
31#include <sys/time.h>
32#include <termios.h>
33#include <unistd.h>
34
35#include "list.h"
36#include "nosy-dump.h"
37#include "nosy-user.h"
38
39enum {
40 PACKET_FIELD_DETAIL = 0x01,
41 PACKET_FIELD_DATA_LENGTH = 0x02,
42 /* Marks the fields we print in transaction view. */
43 PACKET_FIELD_TRANSACTION = 0x04,
44};
45
46static void print_packet(uint32_t *data, size_t length);
47static void decode_link_packet(struct link_packet *packet, size_t length,
48 int include_flags, int exclude_flags);
49static int run = 1;
50sig_t sys_sigint_handler;
51
52static char *option_nosy_device = "/dev/nosy";
53static char *option_view = "packet";
54static char *option_output;
55static char *option_input;
56static int option_hex;
57static int option_iso;
58static int option_cycle_start;
59static int option_version;
60static int option_verbose;
61
62enum {
63 VIEW_TRANSACTION,
64 VIEW_PACKET,
65 VIEW_STATS,
66};
67
68static const struct poptOption options[] = {
69 {
70 .longName = "device",
71 .shortName = 'd',
72 .argInfo = POPT_ARG_STRING,
73 .arg = &option_nosy_device,
74 .descrip = "Path to nosy device.",
75 .argDescrip = "DEVICE"
76 },
77 {
78 .longName = "view",
79 .argInfo = POPT_ARG_STRING,
80 .arg = &option_view,
81 .descrip = "Specify view of bus traffic: packet, transaction or stats.",
82 .argDescrip = "VIEW"
83 },
84 {
85 .longName = "hex",
86 .shortName = 'x',
87 .argInfo = POPT_ARG_NONE,
88 .arg = &option_hex,
89 .descrip = "Print each packet in hex.",
90 },
91 {
92 .longName = "iso",
93 .argInfo = POPT_ARG_NONE,
94 .arg = &option_iso,
95 .descrip = "Print iso packets.",
96 },
97 {
98 .longName = "cycle-start",
99 .argInfo = POPT_ARG_NONE,
100 .arg = &option_cycle_start,
101 .descrip = "Print cycle start packets.",
102 },
103 {
104 .longName = "verbose",
105 .shortName = 'v',
106 .argInfo = POPT_ARG_NONE,
107 .arg = &option_verbose,
108 .descrip = "Verbose packet view.",
109 },
110 {
111 .longName = "output",
112 .shortName = 'o',
113 .argInfo = POPT_ARG_STRING,
114 .arg = &option_output,
115 .descrip = "Log to output file.",
116 .argDescrip = "FILENAME"
117 },
118 {
119 .longName = "input",
120 .shortName = 'i',
121 .argInfo = POPT_ARG_STRING,
122 .arg = &option_input,
123 .descrip = "Decode log from file.",
124 .argDescrip = "FILENAME"
125 },
126 {
127 .longName = "version",
128 .argInfo = POPT_ARG_NONE,
129 .arg = &option_version,
130 .descrip = "Specify print version info.",
131 },
132 POPT_AUTOHELP
133 POPT_TABLEEND
134};
135
136/* Allow all ^C except the first to interrupt the program in the usual way. */
137static void
138sigint_handler(int signal_num)
139{
140 if (run == 1) {
141 run = 0;
142 signal(SIGINT, SIG_DFL);
143 }
144}
145
146static struct subaction *
147subaction_create(uint32_t *data, size_t length)
148{
149 struct subaction *sa;
150
151 /* we put the ack in the subaction struct for easy access. */
152 sa = malloc(sizeof *sa - sizeof sa->packet + length);
153 sa->ack = data[length / 4 - 1];
154 sa->length = length;
155 memcpy(&sa->packet, data, length);
156
157 return sa;
158}
159
160static void
161subaction_destroy(struct subaction *sa)
162{
163 free(sa);
164}
165
166static struct list pending_transaction_list = {
167 &pending_transaction_list, &pending_transaction_list
168};
169
170static struct link_transaction *
171link_transaction_lookup(int request_node, int response_node, int tlabel)
172{
173 struct link_transaction *t;
174
175 list_for_each_entry(t, &pending_transaction_list, link) {
176 if (t->request_node == request_node &&
177 t->response_node == response_node &&
178 t->tlabel == tlabel)
179 return t;
180 }
181
182 t = malloc(sizeof *t);
183 t->request_node = request_node;
184 t->response_node = response_node;
185 t->tlabel = tlabel;
186 list_init(&t->request_list);
187 list_init(&t->response_list);
188
189 list_append(&pending_transaction_list, &t->link);
190
191 return t;
192}
193
194static void
195link_transaction_destroy(struct link_transaction *t)
196{
197 struct subaction *sa;
198
199 while (!list_empty(&t->request_list)) {
200 sa = list_head(&t->request_list, struct subaction, link);
201 list_remove(&sa->link);
202 subaction_destroy(sa);
203 }
204 while (!list_empty(&t->response_list)) {
205 sa = list_head(&t->response_list, struct subaction, link);
206 list_remove(&sa->link);
207 subaction_destroy(sa);
208 }
209 free(t);
210}
211
212struct protocol_decoder {
213 const char *name;
214 int (*decode)(struct link_transaction *t);
215};
216
217static const struct protocol_decoder protocol_decoders[] = {
218 { "FCP", decode_fcp }
219};
220
221static void
222handle_transaction(struct link_transaction *t)
223{
224 struct subaction *sa;
225 int i;
226
227 if (!t->request) {
228 printf("BUG in handle_transaction\n");
229 return;
230 }
231
232 for (i = 0; i < array_length(protocol_decoders); i++)
233 if (protocol_decoders[i].decode(t))
234 break;
235
236 /* HACK: decode only fcp right now. */
237 return;
238
239 decode_link_packet(&t->request->packet, t->request->length,
240 PACKET_FIELD_TRANSACTION, 0);
241 if (t->response)
242 decode_link_packet(&t->response->packet, t->request->length,
243 PACKET_FIELD_TRANSACTION, 0);
244 else
245 printf("[no response]");
246
247 if (option_verbose) {
248 list_for_each_entry(sa, &t->request_list, link)
249 print_packet((uint32_t *) &sa->packet, sa->length);
250 list_for_each_entry(sa, &t->response_list, link)
251 print_packet((uint32_t *) &sa->packet, sa->length);
252 }
253 printf("\r\n");
254
255 link_transaction_destroy(t);
256}
257
258static void
259clear_pending_transaction_list(void)
260{
261 struct link_transaction *t;
262
263 while (!list_empty(&pending_transaction_list)) {
264 t = list_head(&pending_transaction_list,
265 struct link_transaction, link);
266 list_remove(&t->link);
267 link_transaction_destroy(t);
268 /* print unfinished transactions */
269 }
270}
271
272static const char * const tcode_names[] = {
273 [0x0] = "write_quadlet_request", [0x6] = "read_quadlet_response",
274 [0x1] = "write_block_request", [0x7] = "read_block_response",
275 [0x2] = "write_response", [0x8] = "cycle_start",
276 [0x3] = "reserved", [0x9] = "lock_request",
277 [0x4] = "read_quadlet_request", [0xa] = "iso_data",
278 [0x5] = "read_block_request", [0xb] = "lock_response",
279};
280
281static const char * const ack_names[] = {
282 [0x0] = "no ack", [0x8] = "reserved (0x08)",
283 [0x1] = "ack_complete", [0x9] = "reserved (0x09)",
284 [0x2] = "ack_pending", [0xa] = "reserved (0x0a)",
285 [0x3] = "reserved (0x03)", [0xb] = "reserved (0x0b)",
286 [0x4] = "ack_busy_x", [0xc] = "reserved (0x0c)",
287 [0x5] = "ack_busy_a", [0xd] = "ack_data_error",
288 [0x6] = "ack_busy_b", [0xe] = "ack_type_error",
289 [0x7] = "reserved (0x07)", [0xf] = "reserved (0x0f)",
290};
291
292static const char * const rcode_names[] = {
293 [0x0] = "complete", [0x4] = "conflict_error",
294 [0x1] = "reserved (0x01)", [0x5] = "data_error",
295 [0x2] = "reserved (0x02)", [0x6] = "type_error",
296 [0x3] = "reserved (0x03)", [0x7] = "address_error",
297};
298
299static const char * const retry_names[] = {
300 [0x0] = "retry_1",
301 [0x1] = "retry_x",
302 [0x2] = "retry_a",
303 [0x3] = "retry_b",
304};
305
306enum {
307 PACKET_RESERVED,
308 PACKET_REQUEST,
309 PACKET_RESPONSE,
310 PACKET_OTHER,
311};
312
313struct packet_info {
314 const char *name;
315 int type;
316 int response_tcode;
317 const struct packet_field *fields;
318 int field_count;
319};
320
321struct packet_field {
322 const char *name; /* Short name for field. */
323 int offset; /* Location of field, specified in bits; */
324 /* negative means from end of packet. */
325 int width; /* Width of field, 0 means use data_length. */
326 int flags; /* Show options. */
327 const char * const *value_names;
328};
329
330#define COMMON_REQUEST_FIELDS \
331 { "dest", 0, 16, PACKET_FIELD_TRANSACTION }, \
332 { "tl", 16, 6 }, \
333 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
334 { "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names }, \
335 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
336 { "src", 32, 16, PACKET_FIELD_TRANSACTION }, \
337 { "offs", 48, 48, PACKET_FIELD_TRANSACTION }
338
339#define COMMON_RESPONSE_FIELDS \
340 { "dest", 0, 16 }, \
341 { "tl", 16, 6 }, \
342 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
343 { "tcode", 24, 4, 0, tcode_names }, \
344 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
345 { "src", 32, 16 }, \
346 { "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
347
348static const struct packet_field read_quadlet_request_fields[] = {
349 COMMON_REQUEST_FIELDS,
350 { "crc", 96, 32, PACKET_FIELD_DETAIL },
351 { "ack", 156, 4, 0, ack_names },
352};
353
354static const struct packet_field read_quadlet_response_fields[] = {
355 COMMON_RESPONSE_FIELDS,
356 { "data", 96, 32, PACKET_FIELD_TRANSACTION },
357 { "crc", 128, 32, PACKET_FIELD_DETAIL },
358 { "ack", 188, 4, 0, ack_names },
359};
360
361static const struct packet_field read_block_request_fields[] = {
362 COMMON_REQUEST_FIELDS,
363 { "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
364 { "extended_tcode", 112, 16 },
365 { "crc", 128, 32, PACKET_FIELD_DETAIL },
366 { "ack", 188, 4, 0, ack_names },
367};
368
369static const struct packet_field block_response_fields[] = {
370 COMMON_RESPONSE_FIELDS,
371 { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
372 { "extended_tcode", 112, 16 },
373 { "crc", 128, 32, PACKET_FIELD_DETAIL },
374 { "data", 160, 0, PACKET_FIELD_TRANSACTION },
375 { "crc", -64, 32, PACKET_FIELD_DETAIL },
376 { "ack", -4, 4, 0, ack_names },
377};
378
379static const struct packet_field write_quadlet_request_fields[] = {
380 COMMON_REQUEST_FIELDS,
381 { "data", 96, 32, PACKET_FIELD_TRANSACTION },
382 { "ack", -4, 4, 0, ack_names },
383};
384
385static const struct packet_field block_request_fields[] = {
386 COMMON_REQUEST_FIELDS,
387 { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
388 { "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
389 { "crc", 128, 32, PACKET_FIELD_DETAIL },
390 { "data", 160, 0, PACKET_FIELD_TRANSACTION },
391 { "crc", -64, 32, PACKET_FIELD_DETAIL },
392 { "ack", -4, 4, 0, ack_names },
393};
394
395static const struct packet_field write_response_fields[] = {
396 COMMON_RESPONSE_FIELDS,
397 { "reserved", 64, 32, PACKET_FIELD_DETAIL },
398 { "ack", -4, 4, 0, ack_names },
399};
400
401static const struct packet_field iso_data_fields[] = {
402 { "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
403 { "tag", 16, 2 },
404 { "channel", 18, 6 },
405 { "tcode", 24, 4, 0, tcode_names },
406 { "sy", 28, 4 },
407 { "crc", 32, 32, PACKET_FIELD_DETAIL },
408 { "data", 64, 0 },
409 { "crc", -64, 32, PACKET_FIELD_DETAIL },
410 { "ack", -4, 4, 0, ack_names },
411};
412
413static const struct packet_info packet_info[] = {
414 {
415 .name = "write_quadlet_request",
416 .type = PACKET_REQUEST,
417 .response_tcode = TCODE_WRITE_RESPONSE,
418 .fields = write_quadlet_request_fields,
419 .field_count = array_length(write_quadlet_request_fields)
420 },
421 {
422 .name = "write_block_request",
423 .type = PACKET_REQUEST,
424 .response_tcode = TCODE_WRITE_RESPONSE,
425 .fields = block_request_fields,
426 .field_count = array_length(block_request_fields)
427 },
428 {
429 .name = "write_response",
430 .type = PACKET_RESPONSE,
431 .fields = write_response_fields,
432 .field_count = array_length(write_response_fields)
433 },
434 {
435 .name = "reserved",
436 .type = PACKET_RESERVED,
437 },
438 {
439 .name = "read_quadlet_request",
440 .type = PACKET_REQUEST,
441 .response_tcode = TCODE_READ_QUADLET_RESPONSE,
442 .fields = read_quadlet_request_fields,
443 .field_count = array_length(read_quadlet_request_fields)
444 },
445 {
446 .name = "read_block_request",
447 .type = PACKET_REQUEST,
448 .response_tcode = TCODE_READ_BLOCK_RESPONSE,
449 .fields = read_block_request_fields,
450 .field_count = array_length(read_block_request_fields)
451 },
452 {
453 .name = "read_quadlet_response",
454 .type = PACKET_RESPONSE,
455 .fields = read_quadlet_response_fields,
456 .field_count = array_length(read_quadlet_response_fields)
457 },
458 {
459 .name = "read_block_response",
460 .type = PACKET_RESPONSE,
461 .fields = block_response_fields,
462 .field_count = array_length(block_response_fields)
463 },
464 {
465 .name = "cycle_start",
466 .type = PACKET_OTHER,
467 .fields = write_quadlet_request_fields,
468 .field_count = array_length(write_quadlet_request_fields)
469 },
470 {
471 .name = "lock_request",
472 .type = PACKET_REQUEST,
473 .fields = block_request_fields,
474 .field_count = array_length(block_request_fields)
475 },
476 {
477 .name = "iso_data",
478 .type = PACKET_OTHER,
479 .fields = iso_data_fields,
480 .field_count = array_length(iso_data_fields)
481 },
482 {
483 .name = "lock_response",
484 .type = PACKET_RESPONSE,
485 .fields = block_response_fields,
486 .field_count = array_length(block_response_fields)
487 },
488};
489
490static int
491handle_request_packet(uint32_t *data, size_t length)
492{
493 struct link_packet *p = (struct link_packet *) data;
494 struct subaction *sa, *prev;
495 struct link_transaction *t;
496
497 t = link_transaction_lookup(p->common.source, p->common.destination,
498 p->common.tlabel);
499 sa = subaction_create(data, length);
500 t->request = sa;
501
502 if (!list_empty(&t->request_list)) {
503 prev = list_tail(&t->request_list,
504 struct subaction, link);
505
506 if (!ACK_BUSY(prev->ack)) {
507 /*
508 * error, we should only see ack_busy_* before the
509 * ack_pending/ack_complete -- this is an ack_pending
510 * instead (ack_complete would have finished the
511 * transaction).
512 */
513 }
514
515 if (prev->packet.common.tcode != sa->packet.common.tcode ||
516 prev->packet.common.tlabel != sa->packet.common.tlabel) {
517 /* memcmp() ? */
518 /* error, these should match for retries. */
519 }
520 }
521
522 list_append(&t->request_list, &sa->link);
523
524 switch (sa->ack) {
525 case ACK_COMPLETE:
526 if (p->common.tcode != TCODE_WRITE_QUADLET_REQUEST &&
527 p->common.tcode != TCODE_WRITE_BLOCK_REQUEST)
528 /* error, unified transactions only allowed for write */;
529 list_remove(&t->link);
530 handle_transaction(t);
531 break;
532
533 case ACK_NO_ACK:
534 case ACK_DATA_ERROR:
535 case ACK_TYPE_ERROR:
536 list_remove(&t->link);
537 handle_transaction(t);
538 break;
539
540 case ACK_PENDING:
541 /* request subaction phase over, wait for response. */
542 break;
543
544 case ACK_BUSY_X:
545 case ACK_BUSY_A:
546 case ACK_BUSY_B:
547 /* ok, wait for retry. */
548 /* check that retry protocol is respected. */
549 break;
550 }
551
552 return 1;
553}
554
555static int
556handle_response_packet(uint32_t *data, size_t length)
557{
558 struct link_packet *p = (struct link_packet *) data;
559 struct subaction *sa, *prev;
560 struct link_transaction *t;
561
562 t = link_transaction_lookup(p->common.destination, p->common.source,
563 p->common.tlabel);
564 if (list_empty(&t->request_list)) {
565 /* unsolicited response */
566 }
567
568 sa = subaction_create(data, length);
569 t->response = sa;
570
571 if (!list_empty(&t->response_list)) {
572 prev = list_tail(&t->response_list, struct subaction, link);
573
574 if (!ACK_BUSY(prev->ack)) {
575 /*
576 * error, we should only see ack_busy_* before the
577 * ack_pending/ack_complete
578 */
579 }
580
581 if (prev->packet.common.tcode != sa->packet.common.tcode ||
582 prev->packet.common.tlabel != sa->packet.common.tlabel) {
583 /* use memcmp() instead? */
584 /* error, these should match for retries. */
585 }
586 } else {
587 prev = list_tail(&t->request_list, struct subaction, link);
588 if (prev->ack != ACK_PENDING) {
589 /*
590 * error, should not get response unless last request got
591 * ack_pending.
592 */
593 }
594
595 if (packet_info[prev->packet.common.tcode].response_tcode !=
596 sa->packet.common.tcode) {
597 /* error, tcode mismatch */
598 }
599 }
600
601 list_append(&t->response_list, &sa->link);
602
603 switch (sa->ack) {
604 case ACK_COMPLETE:
605 case ACK_NO_ACK:
606 case ACK_DATA_ERROR:
607 case ACK_TYPE_ERROR:
608 list_remove(&t->link);
609 handle_transaction(t);
610 /* transaction complete, remove t from pending list. */
611 break;
612
613 case ACK_PENDING:
614 /* error for responses. */
615 break;
616
617 case ACK_BUSY_X:
618 case ACK_BUSY_A:
619 case ACK_BUSY_B:
620 /* no problem, wait for next retry */
621 break;
622 }
623
624 return 1;
625}
626
627static int
628handle_packet(uint32_t *data, size_t length)
629{
630 if (length == 0) {
631 printf("bus reset\r\n");
632 clear_pending_transaction_list();
633 } else if (length > sizeof(struct phy_packet)) {
634 struct link_packet *p = (struct link_packet *) data;
635
636 switch (packet_info[p->common.tcode].type) {
637 case PACKET_REQUEST:
638 return handle_request_packet(data, length);
639
640 case PACKET_RESPONSE:
641 return handle_response_packet(data, length);
642
643 case PACKET_OTHER:
644 case PACKET_RESERVED:
645 return 0;
646 }
647 }
648
649 return 1;
650}
651
652static unsigned int
653get_bits(struct link_packet *packet, int offset, int width)
654{
655 uint32_t *data = (uint32_t *) packet;
656 uint32_t index, shift, mask;
657
658 index = offset / 32 + 1;
659 shift = 32 - (offset & 31) - width;
660 mask = width == 32 ? ~0 : (1 << width) - 1;
661
662 return (data[index] >> shift) & mask;
663}
664
665#if __BYTE_ORDER == __LITTLE_ENDIAN
666#define byte_index(i) ((i) ^ 3)
667#elif __BYTE_ORDER == __BIG_ENDIAN
668#define byte_index(i) (i)
669#else
670#error unsupported byte order.
671#endif
672
673static void
674dump_data(unsigned char *data, int length)
675{
676 int i, print_length;
677
678 if (length > 128)
679 print_length = 128;
680 else
681 print_length = length;
682
683 for (i = 0; i < print_length; i++)
684 printf("%s%02hhx",
685 (i % 4 == 0 && i != 0) ? " " : "",
686 data[byte_index(i)]);
687
688 if (print_length < length)
689 printf(" (%d more bytes)", length - print_length);
690}
691
692static void
693decode_link_packet(struct link_packet *packet, size_t length,
694 int include_flags, int exclude_flags)
695{
696 const struct packet_info *pi;
697 int data_length = 0;
698 int i;
699
700 pi = &packet_info[packet->common.tcode];
701
702 for (i = 0; i < pi->field_count; i++) {
703 const struct packet_field *f = &pi->fields[i];
704 int offset;
705
706 if (f->flags & exclude_flags)
707 continue;
708 if (include_flags && !(f->flags & include_flags))
709 continue;
710
711 if (f->offset < 0)
712 offset = length * 8 + f->offset - 32;
713 else
714 offset = f->offset;
715
716 if (f->value_names != NULL) {
717 uint32_t bits;
718
719 bits = get_bits(packet, offset, f->width);
720 printf("%s", f->value_names[bits]);
721 } else if (f->width == 0) {
722 printf("%s=[", f->name);
723 dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
724 printf("]");
725 } else {
726 unsigned long long bits;
727 int high_width, low_width;
728
729 if ((offset & ~31) != ((offset + f->width - 1) & ~31)) {
730 /* Bit field spans quadlet boundary. */
731 high_width = ((offset + 31) & ~31) - offset;
732 low_width = f->width - high_width;
733
734 bits = get_bits(packet, offset, high_width);
735 bits = (bits << low_width) |
736 get_bits(packet, offset + high_width, low_width);
737 } else {
738 bits = get_bits(packet, offset, f->width);
739 }
740
741 printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits);
742
743 if (f->flags & PACKET_FIELD_DATA_LENGTH)
744 data_length = bits;
745 }
746
747 if (i < pi->field_count - 1)
748 printf(", ");
749 }
750}
751
752static void
753print_packet(uint32_t *data, size_t length)
754{
755 int i;
756
757 printf("%6u ", data[0]);
758
759 if (length == 4) {
760 printf("bus reset");
761 } else if (length < sizeof(struct phy_packet)) {
762 printf("short packet: ");
763 for (i = 1; i < length / 4; i++)
764 printf("%s%08x", i == 0 ? "[" : " ", data[i]);
765 printf("]");
766
767 } else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
768 struct phy_packet *pp = (struct phy_packet *) data;
769
770 /* phy packet are 3 quadlets: the 1 quadlet payload,
771 * the bitwise inverse of the payload and the snoop
772 * mode ack */
773
774 switch (pp->common.identifier) {
775 case PHY_PACKET_CONFIGURATION:
776 if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
777 printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
778 } else {
779 printf("phy config:");
780 if (pp->phy_config.set_root)
781 printf(" set_root_id=%02x", pp->phy_config.root_id);
782 if (pp->phy_config.set_gap_count)
783 printf(" set_gap_count=%d", pp->phy_config.gap_count);
784 }
785 break;
786
787 case PHY_PACKET_LINK_ON:
788 printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
789 break;
790
791 case PHY_PACKET_SELF_ID:
792 if (pp->self_id.extended) {
793 printf("extended self id: phy_id=%02x, seq=%d",
794 pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
795 } else {
796 static const char * const speed_names[] = {
797 "S100", "S200", "S400", "BETA"
798 };
799 printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
800 pp->self_id.phy_id,
801 (pp->self_id.link_active ? "active" : "not active"),
802 pp->self_id.gap_count,
803 speed_names[pp->self_id.phy_speed],
804 (pp->self_id.contender ? ", irm contender" : ""),
805 (pp->self_id.initiated_reset ? ", initiator" : ""));
806 }
807 break;
808 default:
809 printf("unknown phy packet: ");
810 for (i = 1; i < length / 4; i++)
811 printf("%s%08x", i == 0 ? "[" : " ", data[i]);
812 printf("]");
813 break;
814 }
815 } else {
816 struct link_packet *packet = (struct link_packet *) data;
817
818 decode_link_packet(packet, length, 0,
819 option_verbose ? 0 : PACKET_FIELD_DETAIL);
820 }
821
822 if (option_hex) {
823 printf(" [");
824 dump_data((unsigned char *) data + 4, length - 4);
825 printf("]");
826 }
827
828 printf("\r\n");
829}
830
831#define HIDE_CURSOR "\033[?25l"
832#define SHOW_CURSOR "\033[?25h"
833#define CLEAR "\033[H\033[2J"
834
835static void
836print_stats(uint32_t *data, size_t length)
837{
838 static int bus_reset_count, short_packet_count, phy_packet_count;
839 static int tcode_count[16];
840 static struct timeval last_update;
841 struct timeval now;
842 int i;
843
844 if (length == 0)
845 bus_reset_count++;
846 else if (length < sizeof(struct phy_packet))
847 short_packet_count++;
848 else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
849 phy_packet_count++;
850 else {
851 struct link_packet *packet = (struct link_packet *) data;
852 tcode_count[packet->common.tcode]++;
853 }
854
855 gettimeofday(&now, NULL);
856 if (now.tv_sec <= last_update.tv_sec &&
857 now.tv_usec < last_update.tv_usec + 500000)
858 return;
859
860 last_update = now;
861 printf(CLEAR HIDE_CURSOR
862 " bus resets : %8d\n"
863 " short packets : %8d\n"
864 " phy packets : %8d\n",
865 bus_reset_count, short_packet_count, phy_packet_count);
866
867 for (i = 0; i < array_length(packet_info); i++)
868 if (packet_info[i].type != PACKET_RESERVED)
869 printf(" %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
870 printf(SHOW_CURSOR "\n");
871}
872
873static struct termios saved_attributes;
874
875static void
876reset_input_mode(void)
877{
878 tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
879}
880
881static void
882set_input_mode(void)
883{
884 struct termios tattr;
885
886 /* Make sure stdin is a terminal. */
887 if (!isatty(STDIN_FILENO)) {
888 fprintf(stderr, "Not a terminal.\n");
889 exit(EXIT_FAILURE);
890 }
891
892 /* Save the terminal attributes so we can restore them later. */
893 tcgetattr(STDIN_FILENO, &saved_attributes);
894 atexit(reset_input_mode);
895
896 /* Set the funny terminal modes. */
897 tcgetattr(STDIN_FILENO, &tattr);
898 tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
899 tattr.c_cc[VMIN] = 1;
900 tattr.c_cc[VTIME] = 0;
901 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
902}
903
904int main(int argc, const char *argv[])
905{
906 uint32_t buf[128 * 1024];
907 uint32_t filter;
908 int length, retval, view;
909 int fd = -1;
910 FILE *output = NULL, *input = NULL;
911 poptContext con;
912 char c;
913 struct pollfd pollfds[2];
914
915 sys_sigint_handler = signal(SIGINT, sigint_handler);
916
917 con = poptGetContext(NULL, argc, argv, options, 0);
918 retval = poptGetNextOpt(con);
919 if (retval < -1) {
920 poptPrintUsage(con, stdout, 0);
921 return -1;
922 }
923
924 if (option_version) {
925 printf("dump tool for nosy sniffer, version %s\n", VERSION);
926 return 0;
927 }
928
929 if (__BYTE_ORDER != __LITTLE_ENDIAN)
930 fprintf(stderr, "warning: nosy has only been tested on little "
931 "endian machines\n");
932
933 if (option_input != NULL) {
934 input = fopen(option_input, "r");
935 if (input == NULL) {
936 fprintf(stderr, "Could not open %s, %m\n", option_input);
937 return -1;
938 }
939 } else {
940 fd = open(option_nosy_device, O_RDWR);
941 if (fd < 0) {
942 fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
943 return -1;
944 }
945 set_input_mode();
946 }
947
948 if (strcmp(option_view, "transaction") == 0)
949 view = VIEW_TRANSACTION;
950 else if (strcmp(option_view, "stats") == 0)
951 view = VIEW_STATS;
952 else
953 view = VIEW_PACKET;
954
955 if (option_output) {
956 output = fopen(option_output, "w");
957 if (output == NULL) {
958 fprintf(stderr, "Could not open %s, %m\n", option_output);
959 return -1;
960 }
961 }
962
963 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
964
965 filter = ~0;
966 if (!option_iso)
967 filter &= ~(1 << TCODE_STREAM_DATA);
968 if (!option_cycle_start)
969 filter &= ~(1 << TCODE_CYCLE_START);
970 if (view == VIEW_STATS)
971 filter = ~(1 << TCODE_CYCLE_START);
972
973 ioctl(fd, NOSY_IOC_FILTER, filter);
974
975 ioctl(fd, NOSY_IOC_START);
976
977 pollfds[0].fd = fd;
978 pollfds[0].events = POLLIN;
979 pollfds[1].fd = STDIN_FILENO;
980 pollfds[1].events = POLLIN;
981
982 while (run) {
983 if (input != NULL) {
984 if (fread(&length, sizeof length, 1, input) != 1)
985 return 0;
986 fread(buf, 1, length, input);
987 } else {
988 poll(pollfds, 2, -1);
989 if (pollfds[1].revents) {
990 read(STDIN_FILENO, &c, sizeof c);
991 switch (c) {
992 case 'q':
993 if (output != NULL)
994 fclose(output);
995 return 0;
996 }
997 }
998
999 if (pollfds[0].revents)
1000 length = read(fd, buf, sizeof buf);
1001 else
1002 continue;
1003 }
1004
1005 if (output != NULL) {
1006 fwrite(&length, sizeof length, 1, output);
1007 fwrite(buf, 1, length, output);
1008 }
1009
1010 switch (view) {
1011 case VIEW_TRANSACTION:
1012 handle_packet(buf, length);
1013 break;
1014 case VIEW_PACKET:
1015 print_packet(buf, length);
1016 break;
1017 case VIEW_STATS:
1018 print_stats(buf, length);
1019 break;
1020 }
1021 }
1022
1023 if (output != NULL)
1024 fclose(output);
1025
1026 close(fd);
1027
1028 poptFreeContext(con);
1029
1030 return 0;
1031}
diff --git a/tools/firewire/nosy-dump.h b/tools/firewire/nosy-dump.h
new file mode 100644
index 000000000000..3a4b5b33ba5d
--- /dev/null
+++ b/tools/firewire/nosy-dump.h
@@ -0,0 +1,173 @@
1#ifndef __nosy_dump_h__
2#define __nosy_dump_h__
3
4#define array_length(array) (sizeof(array) / sizeof(array[0]))
5
6#define ACK_NO_ACK 0x0
7#define ACK_DONE(a) ((a >> 2) == 0)
8#define ACK_BUSY(a) ((a >> 2) == 1)
9#define ACK_ERROR(a) ((a >> 2) == 3)
10
11#include <stdint.h>
12
13struct phy_packet {
14 uint32_t timestamp;
15 union {
16 struct {
17 uint32_t zero:24;
18 uint32_t phy_id:6;
19 uint32_t identifier:2;
20 } common, link_on;
21
22 struct {
23 uint32_t zero:16;
24 uint32_t gap_count:6;
25 uint32_t set_gap_count:1;
26 uint32_t set_root:1;
27 uint32_t root_id:6;
28 uint32_t identifier:2;
29 } phy_config;
30
31 struct {
32 uint32_t more_packets:1;
33 uint32_t initiated_reset:1;
34 uint32_t port2:2;
35 uint32_t port1:2;
36 uint32_t port0:2;
37 uint32_t power_class:3;
38 uint32_t contender:1;
39 uint32_t phy_delay:2;
40 uint32_t phy_speed:2;
41 uint32_t gap_count:6;
42 uint32_t link_active:1;
43 uint32_t extended:1;
44 uint32_t phy_id:6;
45 uint32_t identifier:2;
46 } self_id;
47
48 struct {
49 uint32_t more_packets:1;
50 uint32_t reserved1:1;
51 uint32_t porth:2;
52 uint32_t portg:2;
53 uint32_t portf:2;
54 uint32_t porte:2;
55 uint32_t portd:2;
56 uint32_t portc:2;
57 uint32_t portb:2;
58 uint32_t porta:2;
59 uint32_t reserved0:2;
60 uint32_t sequence:3;
61 uint32_t extended:1;
62 uint32_t phy_id:6;
63 uint32_t identifier:2;
64 } ext_self_id;
65 };
66 uint32_t inverted;
67 uint32_t ack;
68};
69
70#define TCODE_PHY_PACKET 0x10
71
72#define PHY_PACKET_CONFIGURATION 0x00
73#define PHY_PACKET_LINK_ON 0x01
74#define PHY_PACKET_SELF_ID 0x02
75
76struct link_packet {
77 uint32_t timestamp;
78 union {
79 struct {
80 uint32_t priority:4;
81 uint32_t tcode:4;
82 uint32_t rt:2;
83 uint32_t tlabel:6;
84 uint32_t destination:16;
85
86 uint32_t offset_high:16;
87 uint32_t source:16;
88
89 uint32_t offset_low;
90 } common;
91
92 struct {
93 uint32_t common[3];
94 uint32_t crc;
95 } read_quadlet;
96
97 struct {
98 uint32_t common[3];
99 uint32_t data;
100 uint32_t crc;
101 } read_quadlet_response;
102
103 struct {
104 uint32_t common[3];
105 uint32_t extended_tcode:16;
106 uint32_t data_length:16;
107 uint32_t crc;
108 } read_block;
109
110 struct {
111 uint32_t common[3];
112 uint32_t extended_tcode:16;
113 uint32_t data_length:16;
114 uint32_t crc;
115 uint32_t data[0];
116 /* crc and ack follows. */
117 } read_block_response;
118
119 struct {
120 uint32_t common[3];
121 uint32_t data;
122 uint32_t crc;
123 } write_quadlet;
124
125 struct {
126 uint32_t common[3];
127 uint32_t extended_tcode:16;
128 uint32_t data_length:16;
129 uint32_t crc;
130 uint32_t data[0];
131 /* crc and ack follows. */
132 } write_block;
133
134 struct {
135 uint32_t common[3];
136 uint32_t crc;
137 } write_response;
138
139 struct {
140 uint32_t common[3];
141 uint32_t data;
142 uint32_t crc;
143 } cycle_start;
144
145 struct {
146 uint32_t sy:4;
147 uint32_t tcode:4;
148 uint32_t channel:6;
149 uint32_t tag:2;
150 uint32_t data_length:16;
151
152 uint32_t crc;
153 } iso_data;
154 };
155};
156
157struct subaction {
158 uint32_t ack;
159 size_t length;
160 struct list link;
161 struct link_packet packet;
162};
163
164struct link_transaction {
165 int request_node, response_node, tlabel;
166 struct subaction *request, *response;
167 struct list request_list, response_list;
168 struct list link;
169};
170
171int decode_fcp(struct link_transaction *t);
172
173#endif /* __nosy_dump_h__ */
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index fe08660ce0bd..cb43289e447f 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -13,6 +13,10 @@ perf*.xml
13perf*.html 13perf*.html
14common-cmds.h 14common-cmds.h
15perf.data 15perf.data
16perf.data.old
17perf-archive
16tags 18tags
17TAGS 19TAGS
18cscope* 20cscope*
21config.mak
22config.mak.autogen
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index bdd3b7ecad0a..bd498d496952 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -24,7 +24,10 @@ DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))
24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT)) 24DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))
25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) 25DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
26 26
27# Make the path relative to DESTDIR, not prefix
28ifndef DESTDIR
27prefix?=$(HOME) 29prefix?=$(HOME)
30endif
28bindir?=$(prefix)/bin 31bindir?=$(prefix)/bin
29htmldir?=$(prefix)/share/doc/perf-doc 32htmldir?=$(prefix)/share/doc/perf-doc
30pdfdir?=$(prefix)/share/doc/perf-doc 33pdfdir?=$(prefix)/share/doc/perf-doc
@@ -32,7 +35,6 @@ mandir?=$(prefix)/share/man
32man1dir=$(mandir)/man1 35man1dir=$(mandir)/man1
33man5dir=$(mandir)/man5 36man5dir=$(mandir)/man5
34man7dir=$(mandir)/man7 37man7dir=$(mandir)/man7
35# DESTDIR=
36 38
37ASCIIDOC=asciidoc 39ASCIIDOC=asciidoc
38ASCIIDOC_EXTRA = --unsafe 40ASCIIDOC_EXTRA = --unsafe
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt
index c9dcade06831..6f5a498608b2 100644
--- a/tools/perf/Documentation/perf-annotate.txt
+++ b/tools/perf/Documentation/perf-annotate.txt
@@ -1,5 +1,5 @@
1perf-annotate(1) 1perf-annotate(1)
2============== 2================
3 3
4NAME 4NAME
5---- 5----
@@ -8,7 +8,7 @@ perf-annotate - Read perf.data (created by perf record) and display annotated co
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf annotate' [-i <file> | --input=file] symbol_name 11'perf annotate' [-i <file> | --input=file] [symbol_name]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -24,6 +24,48 @@ OPTIONS
24--input=:: 24--input=::
25 Input file name. (default: perf.data) 25 Input file name. (default: perf.data)
26 26
27-d::
28--dsos=<dso[,dso...]>::
29 Only consider symbols in these dsos.
30-s::
31--symbol=<symbol>::
32 Symbol to annotate.
33
34-f::
35--force::
36 Don't complain, do it.
37
38-v::
39--verbose::
40 Be more verbose. (Show symbol address, etc)
41
42-D::
43--dump-raw-trace::
44 Dump raw trace in ASCII.
45
46-k::
47--vmlinux=<file>::
48 vmlinux pathname.
49
50-m::
51--modules::
52 Load module symbols. WARNING: use only with -k and LIVE kernel.
53
54-l::
55--print-line::
56 Print matching source lines (may be slow).
57
58-P::
59--full-paths::
60 Don't shorten the displayed pathnames.
61
62--stdio:: Use the stdio interface.
63
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
66 used. This interfaces starts by centering on the line with more
67 samples, TAB/UNTAB cycles through the lines with more samples.
68
27SEE ALSO 69SEE ALSO
28-------- 70--------
29linkperf:perf-record[1] 71linkperf:perf-record[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt
new file mode 100644
index 000000000000..fae174dc7d01
--- /dev/null
+++ b/tools/perf/Documentation/perf-archive.txt
@@ -0,0 +1,22 @@
1perf-archive(1)
2===============
3
4NAME
5----
6perf-archive - Create archive with object files with build-ids found in perf.data file
7
8SYNOPSIS
9--------
10[verse]
11'perf archive' [file]
12
13DESCRIPTION
14-----------
15This command runs runs perf-buildid-list --with-hits, and collects the files
16with the buildids found so that analisys of perf.data contents can be possible
17on another machine.
18
19
20SEE ALSO
21--------
22linkperf:perf-record[1], linkperf:perf-buildid-list[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt
index ae525ac5a2ce..a3dbadb26ef5 100644
--- a/tools/perf/Documentation/perf-bench.txt
+++ b/tools/perf/Documentation/perf-bench.txt
@@ -1,5 +1,5 @@
1perf-bench(1) 1perf-bench(1)
2============ 2=============
3 3
4NAME 4NAME
5---- 5----
@@ -19,12 +19,12 @@ COMMON OPTIONS
19-f:: 19-f::
20--format=:: 20--format=::
21Specify format style. 21Specify format style.
22Current available format styles are, 22Current available format styles are:
23 23
24'default':: 24'default'::
25Default style. This is mainly for human reading. 25Default style. This is mainly for human reading.
26--------------------- 26---------------------
27% perf bench sched pipe # with no style specify 27% perf bench sched pipe # with no style specified
28(executing 1000000 pipe operations between two tasks) 28(executing 1000000 pipe operations between two tasks)
29 Total time:5.855 sec 29 Total time:5.855 sec
30 5.855061 usecs/op 30 5.855061 usecs/op
@@ -79,7 +79,7 @@ options (20 sender and receiver processes per group)
79 79
80 Total time:0.308 sec 80 Total time:0.308 sec
81 81
82% perf bench sched messaging -t -g 20 # be multi-thread,with 20 groups 82% perf bench sched messaging -t -g 20 # be multi-thread, with 20 groups
83(20 sender and receiver threads per group) 83(20 sender and receiver threads per group)
84(20 groups == 800 threads run) 84(20 groups == 800 threads run)
85 85
diff --git a/tools/perf/Documentation/perf-buildid-cache.txt b/tools/perf/Documentation/perf-buildid-cache.txt
new file mode 100644
index 000000000000..c1057701a7dc
--- /dev/null
+++ b/tools/perf/Documentation/perf-buildid-cache.txt
@@ -0,0 +1,33 @@
1perf-buildid-cache(1)
2=====================
3
4NAME
5----
6perf-buildid-cache - Manage build-id cache.
7
8SYNOPSIS
9--------
10[verse]
11'perf buildid-cache <options>'
12
13DESCRIPTION
14-----------
15This command manages the build-id cache. It can add and remove files to/from
16the cache. In the future it should as well purge older entries, set upper
17limits for the space used by the cache, etc.
18
19OPTIONS
20-------
21-a::
22--add=::
23 Add specified file to the cache.
24-r::
25--remove=::
26 Remove specified file from the cache.
27-v::
28--verbose::
29 Be more verbose.
30
31SEE ALSO
32--------
33linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-buildid-list[1]
diff --git a/tools/perf/Documentation/perf-buildid-list.txt b/tools/perf/Documentation/perf-buildid-list.txt
index 01b642c0bf8f..5eaac6f26d51 100644
--- a/tools/perf/Documentation/perf-buildid-list.txt
+++ b/tools/perf/Documentation/perf-buildid-list.txt
@@ -18,6 +18,9 @@ perf report.
18 18
19OPTIONS 19OPTIONS
20------- 20-------
21-H::
22--with-hits::
23 Show only DSOs with hits.
21-i:: 24-i::
22--input=:: 25--input=::
23 Input file name. (default: perf.data) 26 Input file name. (default: perf.data)
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 8974e208cba6..74d7481ed7a6 100644
--- a/tools/perf/Documentation/perf-diff.txt
+++ b/tools/perf/Documentation/perf-diff.txt
@@ -1,5 +1,5 @@
1perf-diff(1) 1perf-diff(1)
2============== 2============
3 3
4NAME 4NAME
5---- 5----
@@ -19,6 +19,18 @@ If no parameters are passed it will assume perf.data.old and perf.data.
19 19
20OPTIONS 20OPTIONS
21------- 21-------
22-M::
23--displacement::
24 Show position displacement relative to baseline.
25
26-D::
27--dump-raw-trace::
28 Dump raw trace in ASCII.
29
30-m::
31--modules::
32 Load module symbols. WARNING: use only with -k and LIVE kernel
33
22-d:: 34-d::
23--dsos=:: 35--dsos=::
24 Only consider symbols in these dsos. CSV that understands 36 Only consider symbols in these dsos. CSV that understands
@@ -42,7 +54,7 @@ OPTIONS
42--field-separator=:: 54--field-separator=::
43 55
44 Use a special separator character and don't pad with spaces, replacing 56 Use a special separator character and don't pad with spaces, replacing
45 all occurances of this separator in symbol names (and other output) 57 all occurrences of this separator in symbol names (and other output)
46 with a '.' character, that thus it's the only non valid separator. 58 with a '.' character, that thus it's the only non valid separator.
47 59
48-v:: 60-v::
@@ -50,6 +62,13 @@ OPTIONS
50 Be verbose, for instance, show the raw counts in addition to the 62 Be verbose, for instance, show the raw counts in addition to the
51 diff. 63 diff.
52 64
65-f::
66--force::
67 Don't complain, do it.
68
69--symfs=<directory>::
70 Look for files with symbols relative to this directory.
71
53SEE ALSO 72SEE ALSO
54-------- 73--------
55linkperf:perf-record[1] 74linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
new file mode 100644
index 000000000000..025630d43cd2
--- /dev/null
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -0,0 +1,35 @@
1perf-inject(1)
2==============
3
4NAME
5----
6perf-inject - Filter to augment the events stream with additional information
7
8SYNOPSIS
9--------
10[verse]
11'perf inject <options>'
12
13DESCRIPTION
14-----------
15perf-inject reads a perf-record event stream and repipes it to stdout. At any
16point the processing code can inject other events into the event stream - in
17this case build-ids (-b option) are read and injected as needed into the event
18stream.
19
20Build-ids are just the first user of perf-inject - potentially anything that
21needs userspace processing to augment the events stream with additional
22information could make use of this facility.
23
24OPTIONS
25-------
26-b::
27--build-ids=::
28 Inject build-ids into the output stream
29-v::
30--verbose::
31 Be more verbose.
32
33SEE ALSO
34--------
35linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
diff --git a/tools/perf/Documentation/perf-kmem.txt b/tools/perf/Documentation/perf-kmem.txt
index eac4d852e7cd..a52fcde894c7 100644
--- a/tools/perf/Documentation/perf-kmem.txt
+++ b/tools/perf/Documentation/perf-kmem.txt
@@ -1,5 +1,5 @@
1perf-kmem(1) 1perf-kmem(1)
2============== 2============
3 3
4NAME 4NAME
5---- 5----
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt
new file mode 100644
index 000000000000..dd84cb2f0a88
--- /dev/null
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -0,0 +1,74 @@
1perf-kvm(1)
2===========
3
4NAME
5----
6perf-kvm - Tool to trace/measure kvm guest os
7
8SYNOPSIS
9--------
10[verse]
11'perf kvm' [--host] [--guest] [--guestmount=<path>
12 [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]]
13 {top|record|report|diff|buildid-list}
14'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
15 | --guestvmlinux=<path>] {top|record|report|diff|buildid-list}
16
17DESCRIPTION
18-----------
19There are a couple of variants of perf kvm:
20
21 'perf kvm [options] top <command>' to generates and displays
22 a performance counter profile of guest os in realtime
23 of an arbitrary workload.
24
25 'perf kvm record <command>' to record the performance counter profile
26 of an arbitrary workload and save it into a perf data file. If both
27 --host and --guest are input, the perf data file name is perf.data.kvm.
28 If there is no --host but --guest, the file name is perf.data.guest.
29 If there is no --guest but --host, the file name is perf.data.host.
30
31 'perf kvm report' to display the performance counter profile information
32 recorded via perf kvm record.
33
34 'perf kvm diff' to displays the performance difference amongst two perf.data
35 files captured via perf record.
36
37 'perf kvm buildid-list' to display the buildids found in a perf data file,
38 so that other tools can be used to fetch packages with matching symbol tables
39 for use by perf report.
40
41OPTIONS
42-------
43-i::
44--input=::
45 Input file name.
46-o::
47--output::
48 Output file name.
49--host=::
50 Collect host side performance profile.
51--guest=::
52 Collect guest side performance profile.
53--guestmount=<path>::
54 Guest os root file system mount directory. Users mounts guest os
55 root directories under <path> by a specific filesystem access method,
56 typically, sshfs. For example, start 2 guest os. The one's pid is 8888
57 and the other's is 9999.
58 #mkdir ~/guestmount; cd ~/guestmount
59 #sshfs -o allow_other,direct_io -p 5551 localhost:/ 8888/
60 #sshfs -o allow_other,direct_io -p 5552 localhost:/ 9999/
61 #perf kvm --host --guest --guestmount=~/guestmount top
62--guestkallsyms=<path>::
63 Guest os /proc/kallsyms file copy. 'perf' kvm' reads it to get guest
64 kernel symbols. Users copy it out from guest os.
65--guestmodules=<path>::
66 Guest os /proc/modules file copy. 'perf' kvm' reads it to get guest
67 kernel module information. Users copy it out from guest os.
68--guestvmlinux=<path>::
69 Guest os kernel vmlinux.
70
71SEE ALSO
72--------
73linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1],
74linkperf:perf-diff[1], linkperf:perf-buildid-list[1]
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 8290b9422668..399751befeed 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -15,6 +15,52 @@ DESCRIPTION
15This command displays the symbolic event types which can be selected in the 15This command displays the symbolic event types which can be selected in the
16various perf commands with the -e option. 16various perf commands with the -e option.
17 17
18EVENT MODIFIERS
19---------------
20
21Events can optionally have a modifer by appending a colon and one or
22more modifiers. Modifiers allow the user to restrict when events are
23counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
24
25The 'p' modifier can be used for specifying how precise the instruction
26address should be. The 'p' modifier is currently only implemented for
27Intel PEBS and can be specified multiple times:
28 0 - SAMPLE_IP can have arbitrary skid
29 1 - SAMPLE_IP must have constant skid
30 2 - SAMPLE_IP requested to have 0 skid
31 3 - SAMPLE_IP must have 0 skid
32
33The PEBS implementation now supports up to 2.
34
35RAW HARDWARE EVENT DESCRIPTOR
36-----------------------------
37Even when an event is not available in a symbolic form within perf right now,
38it can be encoded in a per processor specific way.
39
40For instance For x86 CPUs NNN represents the raw register encoding with the
41layout of IA32_PERFEVTSELx MSRs (see [Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide] Figure 30-1 Layout
42of IA32_PERFEVTSELx MSRs) or AMD's PerfEvtSeln (see [AMD64 Architecture Programmer’s Manual Volume 2: System Programming], Page 344,
43Figure 13-7 Performance Event-Select Register (PerfEvtSeln)).
44
45Example:
46
47If the Intel docs for a QM720 Core i7 describe an event as:
48
49 Event Umask Event Mask
50 Num. Value Mnemonic Description Comment
51
52 A8H 01H LSD.UOPS Counts the number of micro-ops Use cmask=1 and
53 delivered by loop stream detector invert to count
54 cycles
55
56raw encoding of 0x1A8 can be used:
57
58 perf stat -e r1a8 -a sleep 1
59 perf record -e r1a8 ...
60
61You should refer to the processor specific documentation for getting these
62details. Some of them are referenced in the SEE ALSO section below.
63
18OPTIONS 64OPTIONS
19------- 65-------
20None 66None
@@ -22,4 +68,6 @@ None
22SEE ALSO 68SEE ALSO
23-------- 69--------
24linkperf:perf-stat[1], linkperf:perf-top[1], 70linkperf:perf-stat[1], linkperf:perf-top[1],
25linkperf:perf-record[1] 71linkperf:perf-record[1],
72http://www.intel.com/Assets/PDF/manual/253669.pdf[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide],
73http://support.amd.com/us/Processor_TechDocs/24593.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming]
diff --git a/tools/perf/Documentation/perf-lock.txt b/tools/perf/Documentation/perf-lock.txt
new file mode 100644
index 000000000000..921de259ea10
--- /dev/null
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -0,0 +1,44 @@
1perf-lock(1)
2============
3
4NAME
5----
6perf-lock - Analyze lock events
7
8SYNOPSIS
9--------
10[verse]
11'perf lock' {record|report|trace}
12
13DESCRIPTION
14-----------
15You can analyze various lock behaviours
16and statistics with this 'perf lock' command.
17
18 'perf lock record <command>' records lock events
19 between start and end <command>. And this command
20 produces the file "perf.data" which contains tracing
21 results of lock events.
22
23 'perf lock trace' shows raw lock events.
24
25 'perf lock report' reports statistical data.
26
27OPTIONS
28-------
29
30-i::
31--input=<file>::
32 Input file name.
33
34-v::
35--verbose::
36 Be more verbose (show symbol address, etc).
37
38-D::
39--dump-raw-trace::
40 Dump raw trace in ASCII.
41
42SEE ALSO
43--------
44linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 250e391b4bc8..86b797a35aa6 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -15,6 +15,10 @@ or
15'perf probe' [options] --del='[GROUP:]EVENT' [...] 15'perf probe' [options] --del='[GROUP:]EVENT' [...]
16or 16or
17'perf probe' --list 17'perf probe' --list
18or
19'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
20or
21'perf probe' [options] --vars='PROBEPOINT'
18 22
19DESCRIPTION 23DESCRIPTION
20----------- 24-----------
@@ -29,6 +33,15 @@ OPTIONS
29--vmlinux=PATH:: 33--vmlinux=PATH::
30 Specify vmlinux path which has debuginfo (Dwarf binary). 34 Specify vmlinux path which has debuginfo (Dwarf binary).
31 35
36-m::
37--module=MODNAME::
38 Specify module name in which perf-probe searches probe points
39 or lines.
40
41-s::
42--source=PATH::
43 Specify path to kernel source.
44
32-v:: 45-v::
33--verbose:: 46--verbose::
34 Be more verbose (show parsed arguments, etc). 47 Be more verbose (show parsed arguments, etc).
@@ -39,22 +52,114 @@ OPTIONS
39 52
40-d:: 53-d::
41--del=:: 54--del=::
42 Delete a probe event. 55 Delete probe events. This accepts glob wildcards('*', '?') and character
56 classes(e.g. [a-z], [!A-Z]).
43 57
44-l:: 58-l::
45--list:: 59--list::
46 List up current probe events. 60 List up current probe events.
47 61
62-L::
63--line=::
64 Show source code lines which can be probed. This needs an argument
65 which specifies a range of the source code. (see LINE SYNTAX for detail)
66
67-V::
68--vars=::
69 Show available local variables at given probe point. The argument
70 syntax is same as PROBE SYNTAX, but NO ARGs.
71
72--externs::
73 (Only for --vars) Show external defined variables in addition to local
74 variables.
75
76-f::
77--force::
78 Forcibly add events with existing name.
79
80-n::
81--dry-run::
82 Dry run. With this option, --add and --del doesn't execute actual
83 adding and removal operations.
84
85--max-probes::
86 Set the maximum number of probe points for an event. Default is 128.
87
48PROBE SYNTAX 88PROBE SYNTAX
49------------ 89------------
50Probe points are defined by following syntax. 90Probe points are defined by following syntax.
51 91
52 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 92 1) Define event based on function name
93 [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
94
95 2) Define event based on source file with line number
96 [EVENT=]SRC:ALN [ARG ...]
97
98 3) Define event based on source file with lazy pattern
99 [EVENT=]SRC;PTN [ARG ...]
100
53 101
54'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. 102'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
55'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function. 103'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function.
56It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 104It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
57'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). 105'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT).
106
107PROBE ARGUMENT
108--------------
109Each probe argument follows below syntax.
110
111 [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
112
113'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
114'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
115
116LINE SYNTAX
117-----------
118Line range is described by following syntax.
119
120 "FUNC[:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
121
122FUNC specifies the function name of showing lines. 'RLN' is the start line
123number from function entry line, and 'RLN2' is the end line number. As same as
124probe syntax, 'SRC' means the source file path, 'ALN' is start line number,
125and 'ALN2' is end line number in the file. It is also possible to specify how
126many lines to show by using 'NUM'.
127So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
128
129LAZY MATCHING
130-------------
131 The lazy line matching is similar to glob matching but ignoring spaces in both of pattern and target. So this accepts wildcards('*', '?') and character classes(e.g. [a-z], [!A-Z]).
132
133e.g.
134 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on.
135
136This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
137
138
139EXAMPLES
140--------
141Display which lines in schedule() can be probed:
142
143 ./perf probe --line schedule
144
145Add a probe on schedule() function 12th line with recording cpu local variable:
146
147 ./perf probe schedule:12 cpu
148 or
149 ./perf probe --add='schedule:12 cpu'
150
151 this will add one or more probes which has the name start with "schedule".
152
153 Add probes on lines in schedule() function which calls update_rq_clock().
154
155 ./perf probe 'schedule;update_rq_clock*'
156 or
157 ./perf probe --add='schedule;update_rq_clock*'
158
159Delete all probes on schedule().
160
161 ./perf probe --del='schedule*'
162
58 163
59SEE ALSO 164SEE ALSO
60-------- 165--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index fc46c0b40f6e..e032716c839b 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -39,26 +39,38 @@ OPTIONS
39 be passed as follows: '\mem:addr[:[r][w][x]]'. 39 be passed as follows: '\mem:addr[:[r][w][x]]'.
40 If you want to profile read-write accesses in 0x1000, just set 40 If you want to profile read-write accesses in 0x1000, just set
41 'mem:0x1000:rw'. 41 'mem:0x1000:rw'.
42
43--filter=<filter>::
44 Event filter.
45
42-a:: 46-a::
43 System-wide collection. 47--all-cpus::
48 System-wide collection from all CPUs.
44 49
45-l:: 50-l::
46 Scale counter values. 51 Scale counter values.
47 52
48-p:: 53-p::
49--pid=:: 54--pid=::
50 Record events on existing pid. 55 Record events on existing process ID.
56
57-t::
58--tid=::
59 Record events on existing thread ID.
51 60
52-r:: 61-r::
53--realtime=:: 62--realtime=::
54 Collect data with this RT SCHED_FIFO priority. 63 Collect data with this RT SCHED_FIFO priority.
64-D::
65--no-delay::
66 Collect data without buffering.
55-A:: 67-A::
56--append:: 68--append::
57 Append to the output file to do incremental profiling. 69 Append to the output file to do incremental profiling.
58 70
59-f:: 71-f::
60--force:: 72--force::
61 Overwrite existing data file. 73 Overwrite existing data file. (deprecated)
62 74
63-c:: 75-c::
64--count=:: 76--count=::
@@ -69,8 +81,8 @@ OPTIONS
69 Output file name. 81 Output file name.
70 82
71-i:: 83-i::
72--inherit:: 84--no-inherit::
73 Child tasks inherit counters. 85 Child tasks do not inherit counters.
74-F:: 86-F::
75--freq=:: 87--freq=::
76 Profile at this frequency. 88 Profile at this frequency.
@@ -83,6 +95,10 @@ OPTIONS
83--call-graph:: 95--call-graph::
84 Do call-graph (stack chain/backtrace) recording. 96 Do call-graph (stack chain/backtrace) recording.
85 97
98-q::
99--quiet::
100 Don't print any message, useful for scripting.
101
86-v:: 102-v::
87--verbose:: 103--verbose::
88 Be more verbose (show counter open errors, etc). 104 Be more verbose (show counter open errors, etc).
@@ -95,13 +111,31 @@ OPTIONS
95--data:: 111--data::
96 Sample addresses. 112 Sample addresses.
97 113
114-T::
115--timestamp::
116 Sample timestamps. Use it with 'perf report -D' to see the timestamps,
117 for instance.
118
98-n:: 119-n::
99--no-samples:: 120--no-samples::
100 Don't sample. 121 Don't sample.
101 122
102-R:: 123-R::
103--raw-samples:: 124--raw-samples::
104Collect raw sample records from all opened counters (typically for tracepoint counters). 125Collect raw sample records from all opened counters (default for tracepoint counters).
126
127-C::
128--cpu::
129Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a
130comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
131In per-thread mode with inheritance mode on (default), samples are captured only when
132the thread executes on the designated CPUs. Default is to monitor all CPUs.
133
134-N::
135--no-buildid-cache::
136Do not update the builid cache. This saves some overhead in situations
137where the information in the perf.data file (which includes buildids)
138is sufficient.
105 139
106SEE ALSO 140SEE ALSO
107-------- 141--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index abfabe9147a4..8ba03d6e5398 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -20,6 +20,11 @@ OPTIONS
20-i:: 20-i::
21--input=:: 21--input=::
22 Input file name. (default: perf.data) 22 Input file name. (default: perf.data)
23
24-v::
25--verbose::
26 Be more verbose. (show symbol address, etc)
27
23-d:: 28-d::
24--dsos=:: 29--dsos=::
25 Only consider symbols in these dsos. CSV that understands 30 Only consider symbols in these dsos. CSV that understands
@@ -27,6 +32,10 @@ OPTIONS
27-n:: 32-n::
28--show-nr-samples:: 33--show-nr-samples::
29 Show the number of samples for each symbol 34 Show the number of samples for each symbol
35
36--showcpuutilization::
37 Show sample percentage for different cpu modes.
38
30-T:: 39-T::
31--threads:: 40--threads::
32 Show per-thread event counters 41 Show per-thread event counters
@@ -39,12 +48,24 @@ OPTIONS
39 Only consider these symbols. CSV that understands 48 Only consider these symbols. CSV that understands
40 file://filename entries. 49 file://filename entries.
41 50
51-U::
52--hide-unresolved::
53 Only display entries resolved to a symbol.
54
42-s:: 55-s::
43--sort=:: 56--sort=::
44 Sort by key(s): pid, comm, dso, symbol, parent. 57 Sort by key(s): pid, comm, dso, symbol, parent.
45 58
59-p::
60--parent=<regex>::
61 regex filter to identify parent, see: '--sort parent'
62
63-x::
64--exclude-other::
65 Only display entries with parent-match.
66
46-w:: 67-w::
47--field-width=:: 68--column-widths=<width[,width...]>::
48 Force each column width to the provided list, for large terminal 69 Force each column width to the provided list, for large terminal
49 readability. 70 readability.
50 71
@@ -52,19 +73,52 @@ OPTIONS
52--field-separator=:: 73--field-separator=::
53 74
54 Use a special separator character and don't pad with spaces, replacing 75 Use a special separator character and don't pad with spaces, replacing
55 all occurances of this separator in symbol names (and other output) 76 all occurrences of this separator in symbol names (and other output)
56 with a '.' character, that thus it's the only non valid separator. 77 with a '.' character, that thus it's the only non valid separator.
57 78
79-D::
80--dump-raw-trace::
81 Dump raw trace in ASCII.
82
58-g [type,min]:: 83-g [type,min]::
59--call-graph:: 84--call-graph::
60 Display callchains using type and min percent threshold. 85 Display call chains using type and min percent threshold.
61 type can be either: 86 type can be either:
62 - flat: single column, linear exposure of callchains. 87 - flat: single column, linear exposure of call chains.
63 - graph: use a graph tree, displaying absolute overhead rates. 88 - graph: use a graph tree, displaying absolute overhead rates.
64 - fractal: like graph, but displays relative rates. Each branch of 89 - fractal: like graph, but displays relative rates. Each branch of
65 the tree is considered as a new profiled object. + 90 the tree is considered as a new profiled object. +
66 Default: fractal,0.5. 91 Default: fractal,0.5.
67 92
93--pretty=<key>::
94 Pretty printing style. key: normal, raw
95
96--stdio:: Use the stdio interface.
97
98--tui:: Use the TUI interface, that is integrated with annotate and allows
99 zooming into DSOs or threads, among other features. Use of --tui
100 requires a tty, if one is not present, as when piping to other
101 commands, the stdio interface is used.
102
103-k::
104--vmlinux=<file>::
105 vmlinux pathname
106
107--kallsyms=<file>::
108 kallsyms pathname
109
110-m::
111--modules::
112 Load module symbols. WARNING: This should only be used with -k and
113 a LIVE kernel.
114
115-f::
116--force::
117 Don't complain, do it.
118
119--symfs=<directory>::
120 Look for files with symbols relative to this directory.
121
68SEE ALSO 122SEE ALSO
69-------- 123--------
70linkperf:perf-stat[1] 124linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 1ce79198997b..46822d5fde1c 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -8,11 +8,11 @@ perf-sched - Tool to trace/measure scheduler properties (latencies)
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf sched' {record|latency|replay|trace} 11'perf sched' {record|latency|map|replay|trace}
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15There's four variants of perf sched: 15There are five variants of perf sched:
16 16
17 'perf sched record <command>' to record the scheduling events 17 'perf sched record <command>' to record the scheduling events
18 of an arbitrary workload. 18 of an arbitrary workload.
@@ -27,11 +27,25 @@ There's four variants of perf sched:
27 via perf sched record. (this is done by starting up mockup threads 27 via perf sched record. (this is done by starting up mockup threads
28 that mimic the workload based on the events in the trace. These 28 that mimic the workload based on the events in the trace. These
29 threads can then replay the timings (CPU runtime and sleep patterns) 29 threads can then replay the timings (CPU runtime and sleep patterns)
30 of the workload as it occured when it was recorded - and can repeat 30 of the workload as it occurred when it was recorded - and can repeat
31 it a number of times, measuring its performance.) 31 it a number of times, measuring its performance.)
32 32
33 'perf sched map' to print a textual context-switching outline of
34 workload captured via perf sched record. Columns stand for
35 individual CPUs, and the two-letter shortcuts stand for tasks that
36 are running on a CPU. A '*' denotes the CPU that had the event, and
37 a dot signals an idle CPU.
38
33OPTIONS 39OPTIONS
34------- 40-------
41-i::
42--input=<file>::
43 Input file name. (default: perf.data)
44
45-v::
46--verbose::
47 Be more verbose. (show symbol address, etc)
48
35-D:: 49-D::
36--dump-raw-trace=:: 50--dump-raw-trace=::
37 Display verbose dump of the sched data. 51 Display verbose dump of the sched data.
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-script-perl.txt
index c5f55f439091..5bb41e55a3ac 100644
--- a/tools/perf/Documentation/perf-trace-perl.txt
+++ b/tools/perf/Documentation/perf-script-perl.txt
@@ -1,19 +1,19 @@
1perf-trace-perl(1) 1perf-script-perl(1)
2================== 2==================
3 3
4NAME 4NAME
5---- 5----
6perf-trace-perl - Process trace data with a Perl script 6perf-script-perl - Process trace data with a Perl script
7 7
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-s [lang]:script[.ext] ] 11'perf script' [-s [Perl]:script[.pl] ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15 15
16This perf trace option is used to process perf trace data using perf's 16This perf script option is used to process perf script data using perf's
17built-in Perl interpreter. It reads and processes the input file and 17built-in Perl interpreter. It reads and processes the input file and
18displays the results of the trace analysis implemented in the given 18displays the results of the trace analysis implemented in the given
19Perl script, if any. 19Perl script, if any.
@@ -21,7 +21,7 @@ Perl script, if any.
21STARTER SCRIPTS 21STARTER SCRIPTS
22--------------- 22---------------
23 23
24You can avoid reading the rest of this document by running 'perf trace 24You can avoid reading the rest of this document by running 'perf script
25-g perl' in the same directory as an existing perf.data trace file. 25-g perl' in the same directory as an existing perf.data trace file.
26That will generate a starter script containing a handler for each of 26That will generate a starter script containing a handler for each of
27the event types in the trace file; it simply prints every available 27the event types in the trace file; it simply prints every available
@@ -30,13 +30,13 @@ field for each event in the trace file.
30You can also look at the existing scripts in 30You can also look at the existing scripts in
31~/libexec/perf-core/scripts/perl for typical examples showing how to 31~/libexec/perf-core/scripts/perl for typical examples showing how to
32do basic things like aggregate event data, print results, etc. Also, 32do basic things like aggregate event data, print results, etc. Also,
33the check-perf-trace.pl script, while not interesting for its results, 33the check-perf-script.pl script, while not interesting for its results,
34attempts to exercise all of the main scripting features. 34attempts to exercise all of the main scripting features.
35 35
36EVENT HANDLERS 36EVENT HANDLERS
37-------------- 37--------------
38 38
39When perf trace is invoked using a trace script, a user-defined 39When perf script is invoked using a trace script, a user-defined
40'handler function' is called for each event in the trace. If there's 40'handler function' is called for each event in the trace. If there's
41no handler function defined for a given event type, the event is 41no handler function defined for a given event type, the event is
42ignored (or passed to a 'trace_handled' function, see below) and the 42ignored (or passed to a 'trace_handled' function, see below) and the
@@ -49,12 +49,10 @@ available as calls back into the perf executable (see below).
49As an example, the following perf record command can be used to record 49As an example, the following perf record command can be used to record
50all sched_wakeup events in the system: 50all sched_wakeup events in the system:
51 51
52 # perf record -c 1 -f -a -M -R -e sched:sched_wakeup 52 # perf record -a -e sched:sched_wakeup
53 53
54Traces meant to be processed using a script should be recorded with 54Traces meant to be processed using a script should be recorded with
55the above options: -c 1 says to sample every event, -a to enable 55the above option: -a to enable system-wide collection.
56system-wide collection, -M to multiplex the output, and -R to collect
57raw samples.
58 56
59The format file for the sched_wakep event defines the following fields 57The format file for the sched_wakep event defines the following fields
60(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format): 58(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
@@ -114,13 +112,13 @@ write a useful trace script. The sections below cover the rest.
114SCRIPT LAYOUT 112SCRIPT LAYOUT
115------------- 113-------------
116 114
117Every perf trace Perl script should start by setting up a Perl module 115Every perf script Perl script should start by setting up a Perl module
118search path and 'use'ing a few support modules (see module 116search path and 'use'ing a few support modules (see module
119descriptions below): 117descriptions below):
120 118
121---- 119----
122 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; 120 use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/perf-script-Util/lib";
123 use lib "./Perf-Trace-Util/lib"; 121 use lib "./perf-script-Util/lib";
124 use Perf::Trace::Core; 122 use Perf::Trace::Core;
125 use Perf::Trace::Context; 123 use Perf::Trace::Context;
126 use Perf::Trace::Util; 124 use Perf::Trace::Util;
@@ -164,7 +162,7 @@ sub trace_unhandled
164---- 162----
165 163
166The remaining sections provide descriptions of each of the available 164The remaining sections provide descriptions of each of the available
167built-in perf trace Perl modules and their associated functions. 165built-in perf script Perl modules and their associated functions.
168 166
169AVAILABLE MODULES AND FUNCTIONS 167AVAILABLE MODULES AND FUNCTIONS
170------------------------------- 168-------------------------------
@@ -172,7 +170,7 @@ AVAILABLE MODULES AND FUNCTIONS
172The following sections describe the functions and variables available 170The following sections describe the functions and variables available
173via the various Perf::Trace::* Perl modules. To use the functions and 171via the various Perf::Trace::* Perl modules. To use the functions and
174variables from the given module, add the corresponding 'use 172variables from the given module, add the corresponding 'use
175Perf::Trace::XXX' line to your perf trace script. 173Perf::Trace::XXX' line to your perf script script.
176 174
177Perf::Trace::Core Module 175Perf::Trace::Core Module
178~~~~~~~~~~~~~~~~~~~~~~~~ 176~~~~~~~~~~~~~~~~~~~~~~~~
@@ -206,7 +204,7 @@ argument.
206Perf::Trace::Util Module 204Perf::Trace::Util Module
207~~~~~~~~~~~~~~~~~~~~~~~~ 205~~~~~~~~~~~~~~~~~~~~~~~~
208 206
209Various utility functions for use with perf trace: 207Various utility functions for use with perf script:
210 208
211 nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair 209 nsecs($secs, $nsecs) - returns total nsecs given secs/nsecs pair
212 nsecs_secs($nsecs) - returns whole secs portion given nsecs 210 nsecs_secs($nsecs) - returns whole secs portion given nsecs
@@ -216,4 +214,4 @@ Various utility functions for use with perf trace:
216 214
217SEE ALSO 215SEE ALSO
218-------- 216--------
219linkperf:perf-trace[1] 217linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt
new file mode 100644
index 000000000000..36b38277422c
--- /dev/null
+++ b/tools/perf/Documentation/perf-script-python.txt
@@ -0,0 +1,623 @@
1perf-script-python(1)
2====================
3
4NAME
5----
6perf-script-python - Process trace data with a Python script
7
8SYNOPSIS
9--------
10[verse]
11'perf script' [-s [Python]:script[.py] ]
12
13DESCRIPTION
14-----------
15
16This perf script option is used to process perf script data using perf's
17built-in Python interpreter. It reads and processes the input file and
18displays the results of the trace analysis implemented in the given
19Python script, if any.
20
21A QUICK EXAMPLE
22---------------
23
24This section shows the process, start to finish, of creating a working
25Python script that aggregates and extracts useful information from a
26raw perf script stream. You can avoid reading the rest of this
27document if an example is enough for you; the rest of the document
28provides more details on each step and lists the library functions
29available to script writers.
30
31This example actually details the steps that were used to create the
32'syscall-counts' script you see when you list the available perf script
33scripts via 'perf script -l'. As such, this script also shows how to
34integrate your script into the list of general-purpose 'perf script'
35scripts listed by that command.
36
37The syscall-counts script is a simple script, but demonstrates all the
38basic ideas necessary to create a useful script. Here's an example
39of its output (syscall names are not yet supported, they will appear
40as numbers):
41
42----
43syscall events:
44
45event count
46---------------------------------------- -----------
47sys_write 455067
48sys_getdents 4072
49sys_close 3037
50sys_swapoff 1769
51sys_read 923
52sys_sched_setparam 826
53sys_open 331
54sys_newfstat 326
55sys_mmap 217
56sys_munmap 216
57sys_futex 141
58sys_select 102
59sys_poll 84
60sys_setitimer 12
61sys_writev 8
6215 8
63sys_lseek 7
64sys_rt_sigprocmask 6
65sys_wait4 3
66sys_ioctl 3
67sys_set_robust_list 1
68sys_exit 1
6956 1
70sys_access 1
71----
72
73Basically our task is to keep a per-syscall tally that gets updated
74every time a system call occurs in the system. Our script will do
75that, but first we need to record the data that will be processed by
76that script. Theoretically, there are a couple of ways we could do
77that:
78
79- we could enable every event under the tracing/events/syscalls
80 directory, but this is over 600 syscalls, well beyond the number
81 allowable by perf. These individual syscall events will however be
82 useful if we want to later use the guidance we get from the
83 general-purpose scripts to drill down and get more detail about
84 individual syscalls of interest.
85
86- we can enable the sys_enter and/or sys_exit syscalls found under
87 tracing/events/raw_syscalls. These are called for all syscalls; the
88 'id' field can be used to distinguish between individual syscall
89 numbers.
90
91For this script, we only need to know that a syscall was entered; we
92don't care how it exited, so we'll use 'perf record' to record only
93the sys_enter events:
94
95----
96# perf record -a -e raw_syscalls:sys_enter
97
98^C[ perf record: Woken up 1 times to write data ]
99[ perf record: Captured and wrote 56.545 MB perf.data (~2470503 samples) ]
100----
101
102The options basically say to collect data for every syscall event
103system-wide and multiplex the per-cpu output into a single stream.
104That single stream will be recorded in a file in the current directory
105called perf.data.
106
107Once we have a perf.data file containing our data, we can use the -g
108'perf script' option to generate a Python script that will contain a
109callback handler for each event type found in the perf.data trace
110stream (for more details, see the STARTER SCRIPTS section).
111
112----
113# perf script -g python
114generated Python script: perf-script.py
115
116The output file created also in the current directory is named
117perf-script.py. Here's the file in its entirety:
118
119# perf script event handlers, generated by perf script -g python
120# Licensed under the terms of the GNU GPL License version 2
121
122# The common_* event handler fields are the most useful fields common to
123# all events. They don't necessarily correspond to the 'common_*' fields
124# in the format files. Those fields not available as handler params can
125# be retrieved using Python functions of the form common_*(context).
126# See the perf-script-python Documentation for the list of available functions.
127
128import os
129import sys
130
131sys.path.append(os.environ['PERF_EXEC_PATH'] + \
132 '/scripts/python/perf-script-Util/lib/Perf/Trace')
133
134from perf_trace_context import *
135from Core import *
136
137def trace_begin():
138 print "in trace_begin"
139
140def trace_end():
141 print "in trace_end"
142
143def raw_syscalls__sys_enter(event_name, context, common_cpu,
144 common_secs, common_nsecs, common_pid, common_comm,
145 id, args):
146 print_header(event_name, common_cpu, common_secs, common_nsecs,
147 common_pid, common_comm)
148
149 print "id=%d, args=%s\n" % \
150 (id, args),
151
152def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
153 common_pid, common_comm):
154 print_header(event_name, common_cpu, common_secs, common_nsecs,
155 common_pid, common_comm)
156
157def print_header(event_name, cpu, secs, nsecs, pid, comm):
158 print "%-20s %5u %05u.%09u %8u %-20s " % \
159 (event_name, cpu, secs, nsecs, pid, comm),
160----
161
162At the top is a comment block followed by some import statements and a
163path append which every perf script script should include.
164
165Following that are a couple generated functions, trace_begin() and
166trace_end(), which are called at the beginning and the end of the
167script respectively (for more details, see the SCRIPT_LAYOUT section
168below).
169
170Following those are the 'event handler' functions generated one for
171every event in the 'perf record' output. The handler functions take
172the form subsystem__event_name, and contain named parameters, one for
173each field in the event; in this case, there's only one event,
174raw_syscalls__sys_enter(). (see the EVENT HANDLERS section below for
175more info on event handlers).
176
177The final couple of functions are, like the begin and end functions,
178generated for every script. The first, trace_unhandled(), is called
179every time the script finds an event in the perf.data file that
180doesn't correspond to any event handler in the script. This could
181mean either that the record step recorded event types that it wasn't
182really interested in, or the script was run against a trace file that
183doesn't correspond to the script.
184
185The script generated by -g option simply prints a line for each
186event found in the trace stream i.e. it basically just dumps the event
187and its parameter values to stdout. The print_header() function is
188simply a utility function used for that purpose. Let's rename the
189script and run it to see the default output:
190
191----
192# mv perf-script.py syscall-counts.py
193# perf script -s syscall-counts.py
194
195raw_syscalls__sys_enter 1 00840.847582083 7506 perf id=1, args=
196raw_syscalls__sys_enter 1 00840.847595764 7506 perf id=1, args=
197raw_syscalls__sys_enter 1 00840.847620860 7506 perf id=1, args=
198raw_syscalls__sys_enter 1 00840.847710478 6533 npviewer.bin id=78, args=
199raw_syscalls__sys_enter 1 00840.847719204 6533 npviewer.bin id=142, args=
200raw_syscalls__sys_enter 1 00840.847755445 6533 npviewer.bin id=3, args=
201raw_syscalls__sys_enter 1 00840.847775601 6533 npviewer.bin id=3, args=
202raw_syscalls__sys_enter 1 00840.847781820 6533 npviewer.bin id=3, args=
203.
204.
205.
206----
207
208Of course, for this script, we're not interested in printing every
209trace event, but rather aggregating it in a useful way. So we'll get
210rid of everything to do with printing as well as the trace_begin() and
211trace_unhandled() functions, which we won't be using. That leaves us
212with this minimalistic skeleton:
213
214----
215import os
216import sys
217
218sys.path.append(os.environ['PERF_EXEC_PATH'] + \
219 '/scripts/python/perf-script-Util/lib/Perf/Trace')
220
221from perf_trace_context import *
222from Core import *
223
224def trace_end():
225 print "in trace_end"
226
227def raw_syscalls__sys_enter(event_name, context, common_cpu,
228 common_secs, common_nsecs, common_pid, common_comm,
229 id, args):
230----
231
232In trace_end(), we'll simply print the results, but first we need to
233generate some results to print. To do that we need to have our
234sys_enter() handler do the necessary tallying until all events have
235been counted. A hash table indexed by syscall id is a good way to
236store that information; every time the sys_enter() handler is called,
237we simply increment a count associated with that hash entry indexed by
238that syscall id:
239
240----
241 syscalls = autodict()
242
243 try:
244 syscalls[id] += 1
245 except TypeError:
246 syscalls[id] = 1
247----
248
249The syscalls 'autodict' object is a special kind of Python dictionary
250(implemented in Core.py) that implements Perl's 'autovivifying' hashes
251in Python i.e. with autovivifying hashes, you can assign nested hash
252values without having to go to the trouble of creating intermediate
253levels if they don't exist e.g syscalls[comm][pid][id] = 1 will create
254the intermediate hash levels and finally assign the value 1 to the
255hash entry for 'id' (because the value being assigned isn't a hash
256object itself, the initial value is assigned in the TypeError
257exception. Well, there may be a better way to do this in Python but
258that's what works for now).
259
260Putting that code into the raw_syscalls__sys_enter() handler, we
261effectively end up with a single-level dictionary keyed on syscall id
262and having the counts we've tallied as values.
263
264The print_syscall_totals() function iterates over the entries in the
265dictionary and displays a line for each entry containing the syscall
266name (the dictonary keys contain the syscall ids, which are passed to
267the Util function syscall_name(), which translates the raw syscall
268numbers to the corresponding syscall name strings). The output is
269displayed after all the events in the trace have been processed, by
270calling the print_syscall_totals() function from the trace_end()
271handler called at the end of script processing.
272
273The final script producing the output shown above is shown in its
274entirety below (syscall_name() helper is not yet available, you can
275only deal with id's for now):
276
277----
278import os
279import sys
280
281sys.path.append(os.environ['PERF_EXEC_PATH'] + \
282 '/scripts/python/perf-script-Util/lib/Perf/Trace')
283
284from perf_trace_context import *
285from Core import *
286from Util import *
287
288syscalls = autodict()
289
290def trace_end():
291 print_syscall_totals()
292
293def raw_syscalls__sys_enter(event_name, context, common_cpu,
294 common_secs, common_nsecs, common_pid, common_comm,
295 id, args):
296 try:
297 syscalls[id] += 1
298 except TypeError:
299 syscalls[id] = 1
300
301def print_syscall_totals():
302 if for_comm is not None:
303 print "\nsyscall events for %s:\n\n" % (for_comm),
304 else:
305 print "\nsyscall events:\n\n",
306
307 print "%-40s %10s\n" % ("event", "count"),
308 print "%-40s %10s\n" % ("----------------------------------------", \
309 "-----------"),
310
311 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
312 reverse = True):
313 print "%-40s %10d\n" % (syscall_name(id), val),
314----
315
316The script can be run just as before:
317
318 # perf script -s syscall-counts.py
319
320So those are the essential steps in writing and running a script. The
321process can be generalized to any tracepoint or set of tracepoints
322you're interested in - basically find the tracepoint(s) you're
323interested in by looking at the list of available events shown by
324'perf list' and/or look in /sys/kernel/debug/tracing events for
325detailed event and field info, record the corresponding trace data
326using 'perf record', passing it the list of interesting events,
327generate a skeleton script using 'perf script -g python' and modify the
328code to aggregate and display it for your particular needs.
329
330After you've done that you may end up with a general-purpose script
331that you want to keep around and have available for future use. By
332writing a couple of very simple shell scripts and putting them in the
333right place, you can have your script listed alongside the other
334scripts listed by the 'perf script -l' command e.g.:
335
336----
337root@tropicana:~# perf script -l
338List of available trace scripts:
339 workqueue-stats workqueue stats (ins/exe/create/destroy)
340 wakeup-latency system-wide min/max/avg wakeup latency
341 rw-by-file <comm> r/w activity for a program, by file
342 rw-by-pid system-wide r/w activity
343----
344
345A nice side effect of doing this is that you also then capture the
346probably lengthy 'perf record' command needed to record the events for
347the script.
348
349To have the script appear as a 'built-in' script, you write two simple
350scripts, one for recording and one for 'reporting'.
351
352The 'record' script is a shell script with the same base name as your
353script, but with -record appended. The shell script should be put
354into the perf/scripts/python/bin directory in the kernel source tree.
355In that script, you write the 'perf record' command-line needed for
356your script:
357
358----
359# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-record
360
361#!/bin/bash
362perf record -a -e raw_syscalls:sys_enter
363----
364
365The 'report' script is also a shell script with the same base name as
366your script, but with -report appended. It should also be located in
367the perf/scripts/python/bin directory. In that script, you write the
368'perf script -s' command-line needed for running your script:
369
370----
371# cat kernel-source/tools/perf/scripts/python/bin/syscall-counts-report
372
373#!/bin/bash
374# description: system-wide syscall counts
375perf script -s ~/libexec/perf-core/scripts/python/syscall-counts.py
376----
377
378Note that the location of the Python script given in the shell script
379is in the libexec/perf-core/scripts/python directory - this is where
380the script will be copied by 'make install' when you install perf.
381For the installation to install your script there, your script needs
382to be located in the perf/scripts/python directory in the kernel
383source tree:
384
385----
386# ls -al kernel-source/tools/perf/scripts/python
387
388root@tropicana:/home/trz/src/tip# ls -al tools/perf/scripts/python
389total 32
390drwxr-xr-x 4 trz trz 4096 2010-01-26 22:30 .
391drwxr-xr-x 4 trz trz 4096 2010-01-26 22:29 ..
392drwxr-xr-x 2 trz trz 4096 2010-01-26 22:29 bin
393-rw-r--r-- 1 trz trz 2548 2010-01-26 22:29 check-perf-script.py
394drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 perf-script-Util
395-rw-r--r-- 1 trz trz 1462 2010-01-26 22:30 syscall-counts.py
396----
397
398Once you've done that (don't forget to do a new 'make install',
399otherwise your script won't show up at run-time), 'perf script -l'
400should show a new entry for your script:
401
402----
403root@tropicana:~# perf script -l
404List of available trace scripts:
405 workqueue-stats workqueue stats (ins/exe/create/destroy)
406 wakeup-latency system-wide min/max/avg wakeup latency
407 rw-by-file <comm> r/w activity for a program, by file
408 rw-by-pid system-wide r/w activity
409 syscall-counts system-wide syscall counts
410----
411
412You can now perform the record step via 'perf script record':
413
414 # perf script record syscall-counts
415
416and display the output using 'perf script report':
417
418 # perf script report syscall-counts
419
420STARTER SCRIPTS
421---------------
422
423You can quickly get started writing a script for a particular set of
424trace data by generating a skeleton script using 'perf script -g
425python' in the same directory as an existing perf.data trace file.
426That will generate a starter script containing a handler for each of
427the event types in the trace file; it simply prints every available
428field for each event in the trace file.
429
430You can also look at the existing scripts in
431~/libexec/perf-core/scripts/python for typical examples showing how to
432do basic things like aggregate event data, print results, etc. Also,
433the check-perf-script.py script, while not interesting for its results,
434attempts to exercise all of the main scripting features.
435
436EVENT HANDLERS
437--------------
438
439When perf script is invoked using a trace script, a user-defined
440'handler function' is called for each event in the trace. If there's
441no handler function defined for a given event type, the event is
442ignored (or passed to a 'trace_handled' function, see below) and the
443next event is processed.
444
445Most of the event's field values are passed as arguments to the
446handler function; some of the less common ones aren't - those are
447available as calls back into the perf executable (see below).
448
449As an example, the following perf record command can be used to record
450all sched_wakeup events in the system:
451
452 # perf record -a -e sched:sched_wakeup
453
454Traces meant to be processed using a script should be recorded with
455the above option: -a to enable system-wide collection.
456
457The format file for the sched_wakep event defines the following fields
458(see /sys/kernel/debug/tracing/events/sched/sched_wakeup/format):
459
460----
461 format:
462 field:unsigned short common_type;
463 field:unsigned char common_flags;
464 field:unsigned char common_preempt_count;
465 field:int common_pid;
466 field:int common_lock_depth;
467
468 field:char comm[TASK_COMM_LEN];
469 field:pid_t pid;
470 field:int prio;
471 field:int success;
472 field:int target_cpu;
473----
474
475The handler function for this event would be defined as:
476
477----
478def sched__sched_wakeup(event_name, context, common_cpu, common_secs,
479 common_nsecs, common_pid, common_comm,
480 comm, pid, prio, success, target_cpu):
481 pass
482----
483
484The handler function takes the form subsystem__event_name.
485
486The common_* arguments in the handler's argument list are the set of
487arguments passed to all event handlers; some of the fields correspond
488to the common_* fields in the format file, but some are synthesized,
489and some of the common_* fields aren't common enough to to be passed
490to every event as arguments but are available as library functions.
491
492Here's a brief description of each of the invariant event args:
493
494 event_name the name of the event as text
495 context an opaque 'cookie' used in calls back into perf
496 common_cpu the cpu the event occurred on
497 common_secs the secs portion of the event timestamp
498 common_nsecs the nsecs portion of the event timestamp
499 common_pid the pid of the current task
500 common_comm the name of the current process
501
502All of the remaining fields in the event's format file have
503counterparts as handler function arguments of the same name, as can be
504seen in the example above.
505
506The above provides the basics needed to directly access every field of
507every event in a trace, which covers 90% of what you need to know to
508write a useful trace script. The sections below cover the rest.
509
510SCRIPT LAYOUT
511-------------
512
513Every perf script Python script should start by setting up a Python
514module search path and 'import'ing a few support modules (see module
515descriptions below):
516
517----
518 import os
519 import sys
520
521 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
522 '/scripts/python/perf-script-Util/lib/Perf/Trace')
523
524 from perf_trace_context import *
525 from Core import *
526----
527
528The rest of the script can contain handler functions and support
529functions in any order.
530
531Aside from the event handler functions discussed above, every script
532can implement a set of optional functions:
533
534*trace_begin*, if defined, is called before any event is processed and
535gives scripts a chance to do setup tasks:
536
537----
538def trace_begin:
539 pass
540----
541
542*trace_end*, if defined, is called after all events have been
543 processed and gives scripts a chance to do end-of-script tasks, such
544 as display results:
545
546----
547def trace_end:
548 pass
549----
550
551*trace_unhandled*, if defined, is called after for any event that
552 doesn't have a handler explicitly defined for it. The standard set
553 of common arguments are passed into it:
554
555----
556def trace_unhandled(event_name, context, common_cpu, common_secs,
557 common_nsecs, common_pid, common_comm):
558 pass
559----
560
561The remaining sections provide descriptions of each of the available
562built-in perf script Python modules and their associated functions.
563
564AVAILABLE MODULES AND FUNCTIONS
565-------------------------------
566
567The following sections describe the functions and variables available
568via the various perf script Python modules. To use the functions and
569variables from the given module, add the corresponding 'from XXXX
570import' line to your perf script script.
571
572Core.py Module
573~~~~~~~~~~~~~~
574
575These functions provide some essential functions to user scripts.
576
577The *flag_str* and *symbol_str* functions provide human-readable
578strings for flag and symbolic fields. These correspond to the strings
579and values parsed from the 'print fmt' fields of the event format
580files:
581
582 flag_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the flag field field_name of event event_name
583 symbol_str(event_name, field_name, field_value) - returns the string represention corresponding to field_value for the symbolic field field_name of event event_name
584
585The *autodict* function returns a special kind of Python
586dictionary that implements Perl's 'autovivifying' hashes in Python
587i.e. with autovivifying hashes, you can assign nested hash values
588without having to go to the trouble of creating intermediate levels if
589they don't exist.
590
591 autodict() - returns an autovivifying dictionary instance
592
593
594perf_trace_context Module
595~~~~~~~~~~~~~~~~~~~~~~~~~
596
597Some of the 'common' fields in the event format file aren't all that
598common, but need to be made accessible to user scripts nonetheless.
599
600perf_trace_context defines a set of functions that can be used to
601access this data in the context of the current event. Each of these
602functions expects a context variable, which is the same as the
603context variable passed into every event handler as the second
604argument.
605
606 common_pc(context) - returns common_preempt count for the current event
607 common_flags(context) - returns common_flags for the current event
608 common_lock_depth(context) - returns common_lock_depth for the current event
609
610Util.py Module
611~~~~~~~~~~~~~~
612
613Various utility functions for use with perf script:
614
615 nsecs(secs, nsecs) - returns total nsecs given secs/nsecs pair
616 nsecs_secs(nsecs) - returns whole secs portion given nsecs
617 nsecs_nsecs(nsecs) - returns nsecs remainder given nsecs
618 nsecs_str(nsecs) - returns printable string in the form secs.nsecs
619 avg(total, n) - returns average given a sum and a total number of values
620
621SEE ALSO
622--------
623linkperf:perf-script[1]
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
new file mode 100644
index 000000000000..29ad94293cd2
--- /dev/null
+++ b/tools/perf/Documentation/perf-script.txt
@@ -0,0 +1,118 @@
1perf-script(1)
2=============
3
4NAME
5----
6perf-script - Read perf.data (created by perf record) and display trace output
7
8SYNOPSIS
9--------
10[verse]
11'perf script' [<options>]
12'perf script' [<options>] record <script> [<record-options>] <command>
13'perf script' [<options>] report <script> [script-args]
14'perf script' [<options>] <script> <required-script-args> [<record-options>] <command>
15'perf script' [<options>] <top-script> [script-args]
16
17DESCRIPTION
18-----------
19This command reads the input file and displays the trace recorded.
20
21There are several variants of perf script:
22
23 'perf script' to see a detailed trace of the workload that was
24 recorded.
25
26 You can also run a set of pre-canned scripts that aggregate and
27 summarize the raw trace data in various ways (the list of scripts is
28 available via 'perf script -l'). The following variants allow you to
29 record and run those scripts:
30
31 'perf script record <script> <command>' to record the events required
32 for 'perf script report'. <script> is the name displayed in the
33 output of 'perf script --list' i.e. the actual script name minus any
34 language extension. If <command> is not specified, the events are
35 recorded using the -a (system-wide) 'perf record' option.
36
37 'perf script report <script> [args]' to run and display the results
38 of <script>. <script> is the name displayed in the output of 'perf
39 trace --list' i.e. the actual script name minus any language
40 extension. The perf.data output from a previous run of 'perf script
41 record <script>' is used and should be present for this command to
42 succeed. [args] refers to the (mainly optional) args expected by
43 the script.
44
45 'perf script <script> <required-script-args> <command>' to both
46 record the events required for <script> and to run the <script>
47 using 'live-mode' i.e. without writing anything to disk. <script>
48 is the name displayed in the output of 'perf script --list' i.e. the
49 actual script name minus any language extension. If <command> is
50 not specified, the events are recorded using the -a (system-wide)
51 'perf record' option. If <script> has any required args, they
52 should be specified before <command>. This mode doesn't allow for
53 optional script args to be specified; if optional script args are
54 desired, they can be specified using separate 'perf script record'
55 and 'perf script report' commands, with the stdout of the record step
56 piped to the stdin of the report script, using the '-o -' and '-i -'
57 options of the corresponding commands.
58
59 'perf script <top-script>' to both record the events required for
60 <top-script> and to run the <top-script> using 'live-mode'
61 i.e. without writing anything to disk. <top-script> is the name
62 displayed in the output of 'perf script --list' i.e. the actual
63 script name minus any language extension; a <top-script> is defined
64 as any script name ending with the string 'top'.
65
66 [<record-options>] can be passed to the record steps of 'perf script
67 record' and 'live-mode' variants; this isn't possible however for
68 <top-script> 'live-mode' or 'perf script report' variants.
69
70 See the 'SEE ALSO' section for links to language-specific
71 information on how to write and run your own trace scripts.
72
73OPTIONS
74-------
75<command>...::
76 Any command you can specify in a shell.
77
78-D::
79--dump-raw-script=::
80 Display verbose dump of the trace data.
81
82-L::
83--Latency=::
84 Show latency attributes (irqs/preemption disabled, etc).
85
86-l::
87--list=::
88 Display a list of available trace scripts.
89
90-s ['lang']::
91--script=::
92 Process trace data with the given script ([lang]:script[.ext]).
93 If the string 'lang' is specified in place of a script name, a
94 list of supported languages will be displayed instead.
95
96-g::
97--gen-script=::
98 Generate perf-script.[ext] starter script for given language,
99 using current perf.data.
100
101-a::
102 Force system-wide collection. Scripts run without a <command>
103 normally use -a by default, while scripts run with a <command>
104 normally don't - this option allows the latter to be run in
105 system-wide mode.
106
107-i::
108--input=::
109 Input file name.
110
111-d::
112--debug-mode::
113 Do various checks like samples ordering and lost events.
114
115SEE ALSO
116--------
117linkperf:perf-record[1], linkperf:perf-script-perl[1],
118linkperf:perf-script-python[1]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 484080dd5b6f..b6da7affbbee 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -8,8 +8,8 @@ perf-stat - Run a command and gather performance counter statistics
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] <command> 11'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command>
12'perf stat' [-e <EVENT> | --event=EVENT] [-S] [-a] -- <command> [<options>] 12'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>]
13 13
14DESCRIPTION 14DESCRIPTION
15----------- 15-----------
@@ -31,17 +31,57 @@ OPTIONS
31 hexadecimal event descriptor. 31 hexadecimal event descriptor.
32 32
33-i:: 33-i::
34--inherit:: 34--no-inherit::
35 child tasks inherit counters 35 child tasks do not inherit counters
36-p:: 36-p::
37--pid=<pid>:: 37--pid=<pid>::
38 stat events on existing pid 38 stat events on existing process id
39
40-t::
41--tid=<tid>::
42 stat events on existing thread id
43
39 44
40-a:: 45-a::
41 system-wide collection 46--all-cpus::
47 system-wide collection from all CPUs
42 48
43-c:: 49-c::
44 scale counter values 50--scale::
51 scale/normalize counter values
52
53-r::
54--repeat=<n>::
55 repeat command and print average + stddev (max: 100)
56
57-B::
58--big-num::
59 print large numbers with thousands' separators according to locale
60
61-C::
62--cpu=::
63Count only on the list of CPUs provided. Multiple CPUs can be provided as a
64comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
65In per-thread mode, this option is ignored. The -a option is still necessary
66to activate system-wide monitoring. Default is to count on all CPUs.
67
68-A::
69--no-aggr::
70Do not aggregate counts across all monitored CPUs in system-wide mode (-a).
71This option is only valid in system-wide mode.
72
73-n::
74--null::
75 null run - don't start any counters
76
77-v::
78--verbose::
79 be more verbose (show counter open errors, etc)
80
81-x SEP::
82--field-separator SEP::
83print counts using a CSV-style output to make it easy to import directly into
84spreadsheets. Columns are separated by the string specified in SEP.
45 85
46EXAMPLES 86EXAMPLES
47-------- 87--------
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
new file mode 100644
index 000000000000..2c3b462f64b0
--- /dev/null
+++ b/tools/perf/Documentation/perf-test.txt
@@ -0,0 +1,22 @@
1perf-test(1)
2============
3
4NAME
5----
6perf-test - Runs sanity tests.
7
8SYNOPSIS
9--------
10[verse]
11'perf test <options>'
12
13DESCRIPTION
14-----------
15This command does assorted sanity tests, initially through linked routines but
16also will look for a directory with more tests in the form of scripts.
17
18OPTIONS
19-------
20-v::
21--verbose::
22 Be more verbose.
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 4b1788355eca..d7b79e2ba2ad 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -38,6 +38,8 @@ OPTIONS
38--process:: 38--process::
39 Select the processes to display, by name or PID 39 Select the processes to display, by name or PID
40 40
41--symfs=<directory>::
42 Look for files with symbols relative to this directory.
41 43
42SEE ALSO 44SEE ALSO
43-------- 45--------
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 4a7d558dc309..f6eb1cdafb77 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command generates and displays a performance counter profile in realtime. 15This command generates and displays a performance counter profile in real time.
16 16
17 17
18OPTIONS 18OPTIONS
@@ -25,9 +25,11 @@ OPTIONS
25--count=<count>:: 25--count=<count>::
26 Event period to sample. 26 Event period to sample.
27 27
28-C <cpu>:: 28-C <cpu-list>::
29--CPU=<cpu>:: 29--cpu=<cpu>::
30 CPU to profile. 30Monitor only on the list of CPUs provided. Multiple CPUs can be provided as a
31comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
32Default is to monitor all CPUS.
31 33
32-d <seconds>:: 34-d <seconds>::
33--delay=<seconds>:: 35--delay=<seconds>::
@@ -48,6 +50,10 @@ OPTIONS
48--count-filter=<count>:: 50--count-filter=<count>::
49 Only display functions with more events than this. 51 Only display functions with more events than this.
50 52
53-g::
54--group::
55 Put the counters into a counter group.
56
51-F <freq>:: 57-F <freq>::
52--freq=<freq>:: 58--freq=<freq>::
53 Profile at this frequency. 59 Profile at this frequency.
@@ -66,7 +72,11 @@ OPTIONS
66 72
67-p <pid>:: 73-p <pid>::
68--pid=<pid>:: 74--pid=<pid>::
69 Profile events on existing pid. 75 Profile events on existing Process ID.
76
77-t <tid>::
78--tid=<tid>::
79 Profile events on existing thread ID.
70 80
71-r <priority>:: 81-r <priority>::
72--realtime=<priority>:: 82--realtime=<priority>::
@@ -74,7 +84,19 @@ OPTIONS
74 84
75-s <symbol>:: 85-s <symbol>::
76--sym-annotate=<symbol>:: 86--sym-annotate=<symbol>::
77 Annotate this symbol. Requires -k option. 87 Annotate this symbol.
88
89-K::
90--hide_kernel_symbols::
91 Hide kernel symbols.
92
93-U::
94--hide_user_symbols::
95 Hide user symbols.
96
97-D::
98--dump-symtab::
99 Dump the symbol table used for profiling.
78 100
79-v:: 101-v::
80--verbose:: 102--verbose::
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
deleted file mode 100644
index 60e5900da483..000000000000
--- a/tools/perf/Documentation/perf-trace.txt
+++ /dev/null
@@ -1,59 +0,0 @@
1perf-trace(1)
2==============
3
4NAME
5----
6perf-trace - Read perf.data (created by perf record) and display trace output
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' {record <script> | report <script> [args] }
12
13DESCRIPTION
14-----------
15This command reads the input file and displays the trace recorded.
16
17There are several variants of perf trace:
18
19 'perf trace' to see a detailed trace of the workload that was
20 recorded.
21
22 'perf trace record <script>' to record the events required for 'perf
23 trace report'. <script> is the name displayed in the output of
24 'perf trace --list' i.e. the actual script name minus any language
25 extension.
26
27 'perf trace report <script>' to run and display the results of
28 <script>. <script> is the name displayed in the output of 'perf
29 trace --list' i.e. the actual script name minus any language
30 extension. The perf.data output from a previous run of 'perf trace
31 record <script>' is used and should be present for this command to
32 succeed.
33
34OPTIONS
35-------
36-D::
37--dump-raw-trace=::
38 Display verbose dump of the trace data.
39
40-L::
41--Latency=::
42 Show latency attributes (irqs/preemption disabled, etc).
43
44-l::
45--list=::
46 Display a list of available trace scripts.
47
48-s::
49--script=::
50 Process trace data with the given script ([lang]:script[.ext]).
51
52-g::
53--gen-script=::
54 Generate perf-trace.[ext] starter script for given language,
55 using current perf.data.
56
57SEE ALSO
58--------
59linkperf:perf-record[1], linkperf:perf-trace-perl[1]
diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt
index 69c832557199..0eeb247dc7d2 100644
--- a/tools/perf/Documentation/perf.txt
+++ b/tools/perf/Documentation/perf.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15Performance counters for Linux are are a new kernel-based subsystem 15Performance counters for Linux are a new kernel-based subsystem
16that provide a framework for all things performance analysis. It 16that provide a framework for all things performance analysis. It
17covers hardware level (CPU/PMU, Performance Monitoring Unit) features 17covers hardware level (CPU/PMU, Performance Monitoring Unit) features
18and software features (software counters, tracepoints) as well. 18and software features (software counters, tracepoints) as well.
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
new file mode 100644
index 000000000000..c12659d8cb26
--- /dev/null
+++ b/tools/perf/MANIFEST
@@ -0,0 +1,13 @@
1tools/perf
2include/linux/perf_event.h
3include/linux/rbtree.h
4include/linux/list.h
5include/linux/hash.h
6include/linux/stringify.h
7lib/rbtree.c
8include/linux/swab.h
9arch/*/include/asm/unistd*.h
10arch/*/lib/memcpy*.S
11include/linux/poison.h
12include/linux/magic.h
13include/linux/hw_breakpoint.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 2e7fa3a06806..2b5387d53ba5 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,6 +1,16 @@
1ifeq ("$(origin O)", "command line")
2 OUTPUT := $(O)/
3endif
4
1# The default target of this Makefile is... 5# The default target of this Makefile is...
2all:: 6all::
3 7
8ifneq ($(OUTPUT),)
9# check that the output directory actually exists
10OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
11$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
12endif
13
4# Define V=1 to have a more verbose compile. 14# Define V=1 to have a more verbose compile.
5# Define V=2 to have an even more verbose compile. 15# Define V=2 to have an even more verbose compile.
6# 16#
@@ -150,10 +160,12 @@ all::
150# Define LDFLAGS=-static to build a static binary. 160# Define LDFLAGS=-static to build a static binary.
151# 161#
152# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. 162# Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds.
163#
164# Define NO_DWARF if you do not want debug-info analysis feature at all.
153 165
154PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE 166$(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
155 @$(SHELL_PATH) util/PERF-VERSION-GEN 167 @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT)
156-include PERF-VERSION-FILE 168-include $(OUTPUT)PERF-VERSION-FILE
157 169
158uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 170uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
159uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not') 171uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
@@ -162,6 +174,23 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
162uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') 174uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
163uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') 175uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
164 176
177ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
178 -e s/arm.*/arm/ -e s/sa110/arm/ \
179 -e s/s390x/s390/ -e s/parisc64/parisc/ \
180 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
181 -e s/sh[234].*/sh/ )
182
183# Additional ARCH settings for x86
184ifeq ($(ARCH),i386)
185 ARCH := x86
186endif
187ifeq ($(ARCH),x86_64)
188 RAW_ARCH := x86_64
189 ARCH := x86
190 ARCH_CFLAGS := -DARCH_X86_64
191 ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
192endif
193
165# CFLAGS and LDFLAGS are for the users to override from the command line. 194# CFLAGS and LDFLAGS are for the users to override from the command line.
166 195
167# 196#
@@ -198,9 +227,9 @@ ifndef PERF_DEBUG
198 CFLAGS_OPTIMIZE = -O6 227 CFLAGS_OPTIMIZE = -O6
199endif 228endif
200 229
201CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 230CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
202EXTLIBS = -lpthread -lrt -lelf -lm 231EXTLIBS = -lpthread -lrt -lelf -lm
203ALL_CFLAGS = $(CFLAGS) 232ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
204ALL_LDFLAGS = $(LDFLAGS) 233ALL_LDFLAGS = $(LDFLAGS)
205STRIP ?= strip 234STRIP ?= strip
206 235
@@ -216,7 +245,10 @@ STRIP ?= strip
216# runtime figures out where they are based on the path to the executable. 245# runtime figures out where they are based on the path to the executable.
217# This can help installing the suite in a relocatable way. 246# This can help installing the suite in a relocatable way.
218 247
248# Make the path relative to DESTDIR, not to prefix
249ifndef DESTDIR
219prefix = $(HOME) 250prefix = $(HOME)
251endif
220bindir_relative = bin 252bindir_relative = bin
221bindir = $(prefix)/$(bindir_relative) 253bindir = $(prefix)/$(bindir_relative)
222mandir = share/man 254mandir = share/man
@@ -233,13 +265,13 @@ sysconfdir = $(prefix)/etc
233ETC_PERFCONFIG = etc/perfconfig 265ETC_PERFCONFIG = etc/perfconfig
234endif 266endif
235lib = lib 267lib = lib
236# DESTDIR=
237 268
238export prefix bindir sharedir sysconfdir 269export prefix bindir sharedir sysconfdir
239 270
240CC = $(CROSS_COMPILE)gcc 271CC = $(CROSS_COMPILE)gcc
241AR = $(CROSS_COMPILE)ar 272AR = $(CROSS_COMPILE)ar
242RM = rm -f 273RM = rm -f
274MKDIR = mkdir
243TAR = tar 275TAR = tar
244FIND = find 276FIND = find
245INSTALL = install 277INSTALL = install
@@ -256,14 +288,10 @@ else
256 QUIET_STDERR = ">/dev/null 2>&1" 288 QUIET_STDERR = ">/dev/null 2>&1"
257endif 289endif
258 290
259BITBUCKET = "/dev/null" 291-include feature-tests.mak
260
261ifneq ($(shell sh -c "(echo '\#include <stdio.h>'; echo 'int main(void) { return puts(\"hi\"); }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y)
262 BITBUCKET = .perf.dev.null
263endif
264 292
265ifeq ($(shell sh -c "echo 'int foo(void) {char X[2]; return 3;}' | $(CC) -x c -c -Werror -fstack-protector-all - -o $(BITBUCKET) "$(QUIET_STDERR)" && echo y"), y) 293ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
266 CFLAGS := $(CFLAGS) -fstack-protector-all 294 CFLAGS := $(CFLAGS) -fstack-protector-all
267endif 295endif
268 296
269 297
@@ -272,7 +300,7 @@ endif
272# Those must not be GNU-specific; they are shared with perl/ which may 300# Those must not be GNU-specific; they are shared with perl/ which may
273# be built by a different compiler. (Note that this is an artifact now 301# be built by a different compiler. (Note that this is an artifact now
274# but it still might be nice to keep that distinction.) 302# but it still might be nice to keep that distinction.)
275BASIC_CFLAGS = -Iutil/include 303BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include
276BASIC_LDFLAGS = 304BASIC_LDFLAGS =
277 305
278# Guard against environment variables 306# Guard against environment variables
@@ -286,11 +314,10 @@ SCRIPT_PERL =
286SCRIPT_SH = 314SCRIPT_SH =
287TEST_PROGRAMS = 315TEST_PROGRAMS =
288 316
289# 317SCRIPT_SH += perf-archive.sh
290# No scripts right now:
291#
292 318
293# SCRIPT_SH += perf-am.sh 319grep-libs = $(filter -l%,$(1))
320strip-libs = $(filter-out -l%,$(1))
294 321
295# 322#
296# No Perl scripts right now: 323# No Perl scripts right now:
@@ -310,20 +337,17 @@ PROGRAMS += $(EXTRA_PROGRAMS)
310# 337#
311# Single 'perf' binary right now: 338# Single 'perf' binary right now:
312# 339#
313PROGRAMS += perf 340PROGRAMS += $(OUTPUT)perf
314 341
315# List built-in command $C whose implementation cmd_$C() is not in 342# List built-in command $C whose implementation cmd_$C() is not in
316# builtin-$C.o but is linked in as part of some other command. 343# builtin-$C.o but is linked in as part of some other command.
317# 344#
318# None right now:
319#
320# BUILT_INS += perf-init $X
321 345
322# what 'all' will build and 'install' will install, in perfexecdir 346# what 'all' will build and 'install' will install, in perfexecdir
323ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 347ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
324 348
325# what 'all' will build but not install in perfexecdir 349# what 'all' will build but not install in perfexecdir
326OTHER_PROGRAMS = perf$X 350OTHER_PROGRAMS = $(OUTPUT)perf$X
327 351
328# Set paths to tools early so that they can be used for version tests. 352# Set paths to tools early so that they can be used for version tests.
329ifndef SHELL_PATH 353ifndef SHELL_PATH
@@ -335,11 +359,12 @@ endif
335 359
336export PERL_PATH 360export PERL_PATH
337 361
338LIB_FILE=libperf.a 362LIB_FILE=$(OUTPUT)libperf.a
339 363
340LIB_H += ../../include/linux/perf_event.h 364LIB_H += ../../include/linux/perf_event.h
341LIB_H += ../../include/linux/rbtree.h 365LIB_H += ../../include/linux/rbtree.h
342LIB_H += ../../include/linux/list.h 366LIB_H += ../../include/linux/list.h
367LIB_H += ../../include/linux/hash.h
343LIB_H += ../../include/linux/stringify.h 368LIB_H += ../../include/linux/stringify.h
344LIB_H += util/include/linux/bitmap.h 369LIB_H += util/include/linux/bitmap.h
345LIB_H += util/include/linux/bitops.h 370LIB_H += util/include/linux/bitops.h
@@ -353,31 +378,38 @@ LIB_H += util/include/linux/prefetch.h
353LIB_H += util/include/linux/rbtree.h 378LIB_H += util/include/linux/rbtree.h
354LIB_H += util/include/linux/string.h 379LIB_H += util/include/linux/string.h
355LIB_H += util/include/linux/types.h 380LIB_H += util/include/linux/types.h
381LIB_H += util/include/linux/linkage.h
356LIB_H += util/include/asm/asm-offsets.h 382LIB_H += util/include/asm/asm-offsets.h
357LIB_H += util/include/asm/bitops.h
358LIB_H += util/include/asm/bug.h 383LIB_H += util/include/asm/bug.h
359LIB_H += util/include/asm/byteorder.h 384LIB_H += util/include/asm/byteorder.h
385LIB_H += util/include/asm/hweight.h
360LIB_H += util/include/asm/swab.h 386LIB_H += util/include/asm/swab.h
361LIB_H += util/include/asm/system.h 387LIB_H += util/include/asm/system.h
362LIB_H += util/include/asm/uaccess.h 388LIB_H += util/include/asm/uaccess.h
389LIB_H += util/include/dwarf-regs.h
390LIB_H += util/include/asm/dwarf2.h
391LIB_H += util/include/asm/cpufeature.h
363LIB_H += perf.h 392LIB_H += perf.h
364LIB_H += util/cache.h 393LIB_H += util/cache.h
365LIB_H += util/callchain.h 394LIB_H += util/callchain.h
395LIB_H += util/build-id.h
366LIB_H += util/debug.h 396LIB_H += util/debug.h
367LIB_H += util/debugfs.h 397LIB_H += util/debugfs.h
368LIB_H += util/event.h 398LIB_H += util/event.h
399LIB_H += util/evsel.h
369LIB_H += util/exec_cmd.h 400LIB_H += util/exec_cmd.h
370LIB_H += util/types.h 401LIB_H += util/types.h
371LIB_H += util/levenshtein.h 402LIB_H += util/levenshtein.h
403LIB_H += util/map.h
372LIB_H += util/parse-options.h 404LIB_H += util/parse-options.h
373LIB_H += util/parse-events.h 405LIB_H += util/parse-events.h
374LIB_H += util/quote.h 406LIB_H += util/quote.h
375LIB_H += util/util.h 407LIB_H += util/util.h
408LIB_H += util/xyarray.h
376LIB_H += util/header.h 409LIB_H += util/header.h
377LIB_H += util/help.h 410LIB_H += util/help.h
378LIB_H += util/session.h 411LIB_H += util/session.h
379LIB_H += util/strbuf.h 412LIB_H += util/strbuf.h
380LIB_H += util/string.h
381LIB_H += util/strlist.h 413LIB_H += util/strlist.h
382LIB_H += util/svghelper.h 414LIB_H += util/svghelper.h
383LIB_H += util/run-command.h 415LIB_H += util/run-command.h
@@ -389,77 +421,91 @@ LIB_H += util/sort.h
389LIB_H += util/hist.h 421LIB_H += util/hist.h
390LIB_H += util/thread.h 422LIB_H += util/thread.h
391LIB_H += util/trace-event.h 423LIB_H += util/trace-event.h
392LIB_H += util/trace-event-perl.h
393LIB_H += util/probe-finder.h 424LIB_H += util/probe-finder.h
394LIB_H += util/probe-event.h 425LIB_H += util/probe-event.h
395 426LIB_H += util/pstack.h
396LIB_OBJS += util/abspath.o 427LIB_H += util/cpumap.h
397LIB_OBJS += util/alias.o 428LIB_H += $(ARCH_INCLUDE)
398LIB_OBJS += util/config.o 429
399LIB_OBJS += util/ctype.o 430LIB_OBJS += $(OUTPUT)util/abspath.o
400LIB_OBJS += util/debugfs.o 431LIB_OBJS += $(OUTPUT)util/alias.o
401LIB_OBJS += util/environment.o 432LIB_OBJS += $(OUTPUT)util/build-id.o
402LIB_OBJS += util/event.o 433LIB_OBJS += $(OUTPUT)util/config.o
403LIB_OBJS += util/exec_cmd.o 434LIB_OBJS += $(OUTPUT)util/ctype.o
404LIB_OBJS += util/help.o 435LIB_OBJS += $(OUTPUT)util/debugfs.o
405LIB_OBJS += util/levenshtein.o 436LIB_OBJS += $(OUTPUT)util/environment.o
406LIB_OBJS += util/parse-options.o 437LIB_OBJS += $(OUTPUT)util/event.o
407LIB_OBJS += util/parse-events.o 438LIB_OBJS += $(OUTPUT)util/evsel.o
408LIB_OBJS += util/path.o 439LIB_OBJS += $(OUTPUT)util/exec_cmd.o
409LIB_OBJS += util/rbtree.o 440LIB_OBJS += $(OUTPUT)util/help.o
410LIB_OBJS += util/bitmap.o 441LIB_OBJS += $(OUTPUT)util/levenshtein.o
411LIB_OBJS += util/hweight.o 442LIB_OBJS += $(OUTPUT)util/parse-options.o
412LIB_OBJS += util/find_next_bit.o 443LIB_OBJS += $(OUTPUT)util/parse-events.o
413LIB_OBJS += util/run-command.o 444LIB_OBJS += $(OUTPUT)util/path.o
414LIB_OBJS += util/quote.o 445LIB_OBJS += $(OUTPUT)util/rbtree.o
415LIB_OBJS += util/strbuf.o 446LIB_OBJS += $(OUTPUT)util/bitmap.o
416LIB_OBJS += util/string.o 447LIB_OBJS += $(OUTPUT)util/hweight.o
417LIB_OBJS += util/strlist.o 448LIB_OBJS += $(OUTPUT)util/run-command.o
418LIB_OBJS += util/usage.o 449LIB_OBJS += $(OUTPUT)util/quote.o
419LIB_OBJS += util/wrapper.o 450LIB_OBJS += $(OUTPUT)util/strbuf.o
420LIB_OBJS += util/sigchain.o 451LIB_OBJS += $(OUTPUT)util/string.o
421LIB_OBJS += util/symbol.o 452LIB_OBJS += $(OUTPUT)util/strlist.o
422LIB_OBJS += util/color.o 453LIB_OBJS += $(OUTPUT)util/usage.o
423LIB_OBJS += util/pager.o 454LIB_OBJS += $(OUTPUT)util/wrapper.o
424LIB_OBJS += util/header.o 455LIB_OBJS += $(OUTPUT)util/sigchain.o
425LIB_OBJS += util/callchain.o 456LIB_OBJS += $(OUTPUT)util/symbol.o
426LIB_OBJS += util/values.o 457LIB_OBJS += $(OUTPUT)util/color.o
427LIB_OBJS += util/debug.o 458LIB_OBJS += $(OUTPUT)util/pager.o
428LIB_OBJS += util/map.o 459LIB_OBJS += $(OUTPUT)util/header.o
429LIB_OBJS += util/session.o 460LIB_OBJS += $(OUTPUT)util/callchain.o
430LIB_OBJS += util/thread.o 461LIB_OBJS += $(OUTPUT)util/values.o
431LIB_OBJS += util/trace-event-parse.o 462LIB_OBJS += $(OUTPUT)util/debug.o
432LIB_OBJS += util/trace-event-read.o 463LIB_OBJS += $(OUTPUT)util/map.o
433LIB_OBJS += util/trace-event-info.o 464LIB_OBJS += $(OUTPUT)util/pstack.o
434LIB_OBJS += util/trace-event-perl.o 465LIB_OBJS += $(OUTPUT)util/session.o
435LIB_OBJS += util/svghelper.o 466LIB_OBJS += $(OUTPUT)util/thread.o
436LIB_OBJS += util/sort.o 467LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
437LIB_OBJS += util/hist.o 468LIB_OBJS += $(OUTPUT)util/trace-event-read.o
438LIB_OBJS += util/data_map.o 469LIB_OBJS += $(OUTPUT)util/trace-event-info.o
439LIB_OBJS += util/probe-event.o 470LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
440 471LIB_OBJS += $(OUTPUT)util/svghelper.o
441BUILTIN_OBJS += builtin-annotate.o 472LIB_OBJS += $(OUTPUT)util/sort.o
442 473LIB_OBJS += $(OUTPUT)util/hist.o
443BUILTIN_OBJS += builtin-bench.o 474LIB_OBJS += $(OUTPUT)util/probe-event.o
475LIB_OBJS += $(OUTPUT)util/util.o
476LIB_OBJS += $(OUTPUT)util/xyarray.o
477LIB_OBJS += $(OUTPUT)util/cpumap.o
478
479BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
480
481BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
444 482
445# Benchmark modules 483# Benchmark modules
446BUILTIN_OBJS += bench/sched-messaging.o 484BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
447BUILTIN_OBJS += bench/sched-pipe.o 485BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
448BUILTIN_OBJS += bench/mem-memcpy.o 486ifeq ($(RAW_ARCH),x86_64)
449 487BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
450BUILTIN_OBJS += builtin-diff.o 488endif
451BUILTIN_OBJS += builtin-help.o 489BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
452BUILTIN_OBJS += builtin-sched.o 490
453BUILTIN_OBJS += builtin-buildid-list.o 491BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
454BUILTIN_OBJS += builtin-list.o 492BUILTIN_OBJS += $(OUTPUT)builtin-help.o
455BUILTIN_OBJS += builtin-record.o 493BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
456BUILTIN_OBJS += builtin-report.o 494BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
457BUILTIN_OBJS += builtin-stat.o 495BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
458BUILTIN_OBJS += builtin-timechart.o 496BUILTIN_OBJS += $(OUTPUT)builtin-list.o
459BUILTIN_OBJS += builtin-top.o 497BUILTIN_OBJS += $(OUTPUT)builtin-record.o
460BUILTIN_OBJS += builtin-trace.o 498BUILTIN_OBJS += $(OUTPUT)builtin-report.o
461BUILTIN_OBJS += builtin-probe.o 499BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
462BUILTIN_OBJS += builtin-kmem.o 500BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
501BUILTIN_OBJS += $(OUTPUT)builtin-top.o
502BUILTIN_OBJS += $(OUTPUT)builtin-script.o
503BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
504BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
505BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
506BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
507BUILTIN_OBJS += $(OUTPUT)builtin-test.o
508BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
463 509
464PERFLIBS = $(LIB_FILE) 510PERFLIBS = $(LIB_FILE)
465 511
@@ -474,6 +520,16 @@ PERFLIBS = $(LIB_FILE)
474-include config.mak.autogen 520-include config.mak.autogen
475-include config.mak 521-include config.mak
476 522
523ifndef NO_DWARF
524FLAGS_DWARF=$(ALL_CFLAGS) -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
525ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
526 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);
527 NO_DWARF := 1
528endif # Dwarf support
529endif # NO_DWARF
530
531-include arch/$(ARCH)/Makefile
532
477ifeq ($(uname_S),Darwin) 533ifeq ($(uname_S),Darwin)
478 ifndef NO_FINK 534 ifndef NO_FINK
479 ifeq ($(shell test -d /sw/lib && echo y),y) 535 ifeq ($(shell test -d /sw/lib && echo y),y)
@@ -490,68 +546,145 @@ ifeq ($(uname_S),Darwin)
490 PTHREAD_LIBS = 546 PTHREAD_LIBS =
491endif 547endif
492 548
493ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 549ifneq ($(OUTPUT),)
494ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 550 BASIC_CFLAGS += -I$(OUTPUT)
495 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
496endif 551endif
497 552
498 ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 553FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
499 BASIC_CFLAGS += -DLIBELF_NO_MMAP 554ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
555 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
556 ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y)
557 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
558 else
559 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
500 endif 560 endif
501else
502 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
503endif 561endif
504 562
505ifneq ($(shell sh -c "(echo '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/libdwarf -ldwarf -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 563ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y)
506 msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); 564 BASIC_CFLAGS += -DLIBELF_NO_MMAP
507 BASIC_CFLAGS += -DNO_LIBDWARF
508else
509 BASIC_CFLAGS += -I/usr/include/libdwarf
510 EXTLIBS += -lelf -ldwarf
511 LIB_OBJS += util/probe-finder.o
512endif 565endif
513 566
514ifndef NO_LIBPERL 567ifndef NO_DWARF
515PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` 568ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
516PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 569 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
570else
571 BASIC_CFLAGS += -DDWARF_SUPPORT
572 EXTLIBS += -lelf -ldw
573 LIB_OBJS += $(OUTPUT)util/probe-finder.o
574endif # PERF_HAVE_DWARF_REGS
575endif # NO_DWARF
576
577ifdef NO_NEWT
578 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
579else
580 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
581 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y)
582 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
583 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
584 else
585 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
586 BASIC_CFLAGS += -I/usr/include/slang
587 EXTLIBS += -lnewt -lslang
588 LIB_OBJS += $(OUTPUT)util/ui/setup.o
589 LIB_OBJS += $(OUTPUT)util/ui/browser.o
590 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
591 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
592 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
593 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
594 LIB_OBJS += $(OUTPUT)util/ui/progress.o
595 LIB_OBJS += $(OUTPUT)util/ui/util.o
596 LIB_H += util/ui/browser.h
597 LIB_H += util/ui/browsers/map.h
598 LIB_H += util/ui/helpline.h
599 LIB_H += util/ui/libslang.h
600 LIB_H += util/ui/progress.h
601 LIB_H += util/ui/util.h
602 endif
517endif 603endif
518 604
519ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o $(BITBUCKET) $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y) 605ifdef NO_LIBPERL
520 BASIC_CFLAGS += -DNO_LIBPERL 606 BASIC_CFLAGS += -DNO_LIBPERL
521else 607else
522 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) 608 PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
523 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o 609 PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
610 PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
611 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
612 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
613
614 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y)
615 BASIC_CFLAGS += -DNO_LIBPERL
616 else
617 ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
618 EXTLIBS += $(PERL_EMBED_LIBADD)
619 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
620 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
621 endif
622endif
623
624ifdef NO_LIBPYTHON
625 BASIC_CFLAGS += -DNO_LIBPYTHON
626else
627 PYTHON_EMBED_LDOPTS = $(shell python-config --ldflags 2>/dev/null)
628 PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
629 PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
630 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
631 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
632 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
633 BASIC_CFLAGS += -DNO_LIBPYTHON
634 else
635 ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
636 EXTLIBS += $(PYTHON_EMBED_LIBADD)
637 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
638 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
639 endif
524endif 640endif
525 641
526ifdef NO_DEMANGLE 642ifdef NO_DEMANGLE
527 BASIC_CFLAGS += -DNO_DEMANGLE 643 BASIC_CFLAGS += -DNO_DEMANGLE
528else 644else
529 has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y") 645 ifdef HAVE_CPLUS_DEMANGLE
530 646 EXTLIBS += -liberty
531 ifeq ($(has_bfd),y) 647 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
532 EXTLIBS += -lbfd 648 else
533 else 649 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd
534 has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y") 650 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
535 ifeq ($(has_bfd_iberty),y) 651 ifeq ($(has_bfd),y)
536 EXTLIBS += -lbfd -liberty 652 EXTLIBS += -lbfd
537 else 653 else
538 has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y") 654 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
539 ifeq ($(has_bfd_iberty_z),y) 655 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY))
540 EXTLIBS += -lbfd -liberty -lz 656 ifeq ($(has_bfd_iberty),y)
657 EXTLIBS += -lbfd -liberty
541 else 658 else
542 has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y") 659 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
543 ifeq ($(has_cplus_demangle),y) 660 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z))
544 EXTLIBS += -liberty 661 ifeq ($(has_bfd_iberty_z),y)
545 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 662 EXTLIBS += -lbfd -liberty -lz
546 else 663 else
547 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) 664 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
548 BASIC_CFLAGS += -DNO_DEMANGLE 665 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE))
666 ifeq ($(has_cplus_demangle),y)
667 EXTLIBS += -liberty
668 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
669 else
670 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
671 BASIC_CFLAGS += -DNO_DEMANGLE
672 endif
549 endif 673 endif
550 endif 674 endif
551 endif 675 endif
552 endif 676 endif
553endif 677endif
554 678
679
680ifdef NO_STRLCPY
681 BASIC_CFLAGS += -DNO_STRLCPY
682else
683 ifneq ($(call try-cc,$(SOURCE_STRLCPY),),y)
684 BASIC_CFLAGS += -DNO_STRLCPY
685 endif
686endif
687
555ifndef CC_LD_DYNPATH 688ifndef CC_LD_DYNPATH
556 ifdef NO_R_TO_GCC_LINKER 689 ifdef NO_R_TO_GCC_LINKER
557 # Some gcc does not accept and pass -R to the linker to specify 690 # Some gcc does not accept and pass -R to the linker to specify
@@ -591,53 +724,53 @@ ifdef NO_C99_FORMAT
591endif 724endif
592ifdef SNPRINTF_RETURNS_BOGUS 725ifdef SNPRINTF_RETURNS_BOGUS
593 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS 726 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
594 COMPAT_OBJS += compat/snprintf.o 727 COMPAT_OBJS += $(OUTPUT)compat/snprintf.o
595endif 728endif
596ifdef FREAD_READS_DIRECTORIES 729ifdef FREAD_READS_DIRECTORIES
597 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES 730 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
598 COMPAT_OBJS += compat/fopen.o 731 COMPAT_OBJS += $(OUTPUT)compat/fopen.o
599endif 732endif
600ifdef NO_SYMLINK_HEAD 733ifdef NO_SYMLINK_HEAD
601 BASIC_CFLAGS += -DNO_SYMLINK_HEAD 734 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
602endif 735endif
603ifdef NO_STRCASESTR 736ifdef NO_STRCASESTR
604 COMPAT_CFLAGS += -DNO_STRCASESTR 737 COMPAT_CFLAGS += -DNO_STRCASESTR
605 COMPAT_OBJS += compat/strcasestr.o 738 COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o
606endif 739endif
607ifdef NO_STRTOUMAX 740ifdef NO_STRTOUMAX
608 COMPAT_CFLAGS += -DNO_STRTOUMAX 741 COMPAT_CFLAGS += -DNO_STRTOUMAX
609 COMPAT_OBJS += compat/strtoumax.o 742 COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o
610endif 743endif
611ifdef NO_STRTOULL 744ifdef NO_STRTOULL
612 COMPAT_CFLAGS += -DNO_STRTOULL 745 COMPAT_CFLAGS += -DNO_STRTOULL
613endif 746endif
614ifdef NO_SETENV 747ifdef NO_SETENV
615 COMPAT_CFLAGS += -DNO_SETENV 748 COMPAT_CFLAGS += -DNO_SETENV
616 COMPAT_OBJS += compat/setenv.o 749 COMPAT_OBJS += $(OUTPUT)compat/setenv.o
617endif 750endif
618ifdef NO_MKDTEMP 751ifdef NO_MKDTEMP
619 COMPAT_CFLAGS += -DNO_MKDTEMP 752 COMPAT_CFLAGS += -DNO_MKDTEMP
620 COMPAT_OBJS += compat/mkdtemp.o 753 COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o
621endif 754endif
622ifdef NO_UNSETENV 755ifdef NO_UNSETENV
623 COMPAT_CFLAGS += -DNO_UNSETENV 756 COMPAT_CFLAGS += -DNO_UNSETENV
624 COMPAT_OBJS += compat/unsetenv.o 757 COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o
625endif 758endif
626ifdef NO_SYS_SELECT_H 759ifdef NO_SYS_SELECT_H
627 BASIC_CFLAGS += -DNO_SYS_SELECT_H 760 BASIC_CFLAGS += -DNO_SYS_SELECT_H
628endif 761endif
629ifdef NO_MMAP 762ifdef NO_MMAP
630 COMPAT_CFLAGS += -DNO_MMAP 763 COMPAT_CFLAGS += -DNO_MMAP
631 COMPAT_OBJS += compat/mmap.o 764 COMPAT_OBJS += $(OUTPUT)compat/mmap.o
632else 765else
633 ifdef USE_WIN32_MMAP 766 ifdef USE_WIN32_MMAP
634 COMPAT_CFLAGS += -DUSE_WIN32_MMAP 767 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
635 COMPAT_OBJS += compat/win32mmap.o 768 COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o
636 endif 769 endif
637endif 770endif
638ifdef NO_PREAD 771ifdef NO_PREAD
639 COMPAT_CFLAGS += -DNO_PREAD 772 COMPAT_CFLAGS += -DNO_PREAD
640 COMPAT_OBJS += compat/pread.o 773 COMPAT_OBJS += $(OUTPUT)compat/pread.o
641endif 774endif
642ifdef NO_FAST_WORKING_DIRECTORY 775ifdef NO_FAST_WORKING_DIRECTORY
643 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY 776 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
@@ -659,10 +792,10 @@ else
659endif 792endif
660endif 793endif
661ifdef NO_INET_NTOP 794ifdef NO_INET_NTOP
662 LIB_OBJS += compat/inet_ntop.o 795 LIB_OBJS += $(OUTPUT)compat/inet_ntop.o
663endif 796endif
664ifdef NO_INET_PTON 797ifdef NO_INET_PTON
665 LIB_OBJS += compat/inet_pton.o 798 LIB_OBJS += $(OUTPUT)compat/inet_pton.o
666endif 799endif
667 800
668ifdef NO_ICONV 801ifdef NO_ICONV
@@ -679,15 +812,15 @@ endif
679 812
680ifdef PPC_SHA1 813ifdef PPC_SHA1
681 SHA1_HEADER = "ppc/sha1.h" 814 SHA1_HEADER = "ppc/sha1.h"
682 LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o 815 LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o
683else 816else
684ifdef ARM_SHA1 817ifdef ARM_SHA1
685 SHA1_HEADER = "arm/sha1.h" 818 SHA1_HEADER = "arm/sha1.h"
686 LIB_OBJS += arm/sha1.o arm/sha1_arm.o 819 LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o
687else 820else
688ifdef MOZILLA_SHA1 821ifdef MOZILLA_SHA1
689 SHA1_HEADER = "mozilla-sha1/sha1.h" 822 SHA1_HEADER = "mozilla-sha1/sha1.h"
690 LIB_OBJS += mozilla-sha1/sha1.o 823 LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o
691else 824else
692 SHA1_HEADER = <openssl/sha.h> 825 SHA1_HEADER = <openssl/sha.h>
693 EXTLIBS += $(LIB_4_CRYPTO) 826 EXTLIBS += $(LIB_4_CRYPTO)
@@ -699,15 +832,15 @@ ifdef NO_PERL_MAKEMAKER
699endif 832endif
700ifdef NO_HSTRERROR 833ifdef NO_HSTRERROR
701 COMPAT_CFLAGS += -DNO_HSTRERROR 834 COMPAT_CFLAGS += -DNO_HSTRERROR
702 COMPAT_OBJS += compat/hstrerror.o 835 COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o
703endif 836endif
704ifdef NO_MEMMEM 837ifdef NO_MEMMEM
705 COMPAT_CFLAGS += -DNO_MEMMEM 838 COMPAT_CFLAGS += -DNO_MEMMEM
706 COMPAT_OBJS += compat/memmem.o 839 COMPAT_OBJS += $(OUTPUT)compat/memmem.o
707endif 840endif
708ifdef INTERNAL_QSORT 841ifdef INTERNAL_QSORT
709 COMPAT_CFLAGS += -DINTERNAL_QSORT 842 COMPAT_CFLAGS += -DINTERNAL_QSORT
710 COMPAT_OBJS += compat/qsort.o 843 COMPAT_OBJS += $(OUTPUT)compat/qsort.o
711endif 844endif
712ifdef RUNTIME_PREFIX 845ifdef RUNTIME_PREFIX
713 COMPAT_CFLAGS += -DRUNTIME_PREFIX 846 COMPAT_CFLAGS += -DRUNTIME_PREFIX
@@ -738,6 +871,7 @@ ifndef V
738 QUIET_CC = @echo ' ' CC $@; 871 QUIET_CC = @echo ' ' CC $@;
739 QUIET_AR = @echo ' ' AR $@; 872 QUIET_AR = @echo ' ' AR $@;
740 QUIET_LINK = @echo ' ' LINK $@; 873 QUIET_LINK = @echo ' ' LINK $@;
874 QUIET_MKDIR = @echo ' ' MKDIR $@;
741 QUIET_BUILT_IN = @echo ' ' BUILTIN $@; 875 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
742 QUIET_GEN = @echo ' ' GEN $@; 876 QUIET_GEN = @echo ' ' GEN $@;
743 QUIET_SUBDIR0 = +@subdir= 877 QUIET_SUBDIR0 = +@subdir=
@@ -771,13 +905,14 @@ prefix_SQ = $(subst ','\'',$(prefix))
771SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) 905SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
772PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) 906PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
773 907
774LIBS = $(PERFLIBS) $(EXTLIBS) 908LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS)
775 909
776BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ 910BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
777 $(COMPAT_CFLAGS) 911 $(COMPAT_CFLAGS)
778LIB_OBJS += $(COMPAT_OBJS) 912LIB_OBJS += $(COMPAT_OBJS)
779 913
780ALL_CFLAGS += $(BASIC_CFLAGS) 914ALL_CFLAGS += $(BASIC_CFLAGS)
915ALL_CFLAGS += $(ARCH_CFLAGS)
781ALL_LDFLAGS += $(BASIC_LDFLAGS) 916ALL_LDFLAGS += $(BASIC_LDFLAGS)
782 917
783export TAR INSTALL DESTDIR SHELL_PATH 918export TAR INSTALL DESTDIR SHELL_PATH
@@ -787,7 +922,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
787 922
788SHELL = $(SHELL_PATH) 923SHELL = $(SHELL_PATH)
789 924
790all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS 925all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS
791ifneq (,$X) 926ifneq (,$X)
792 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) 927 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
793endif 928endif
@@ -799,51 +934,51 @@ please_set_SHELL_PATH_to_a_more_modern_shell:
799 934
800shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell 935shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
801 936
802strip: $(PROGRAMS) perf$X 937strip: $(PROGRAMS) $(OUTPUT)perf$X
803 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) perf$X 938 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X
804 939
805perf.o: perf.c common-cmds.h PERF-CFLAGS 940$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
806 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 941 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
807 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 942 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
808 $(ALL_CFLAGS) -c $(filter %.c,$^) 943 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
809 944
810perf$X: perf.o $(BUILTIN_OBJS) $(PERFLIBS) 945$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
811 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ perf.o \ 946 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
812 $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) 947 $(BUILTIN_OBJS) $(LIBS) -o $@
813 948
814builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS 949$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
815 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ 950 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
816 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 951 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
817 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 952 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
818 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 953 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
819 954
820builtin-timechart.o: builtin-timechart.c common-cmds.h PERF-CFLAGS 955$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
821 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ 956 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
822 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 957 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
823 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 958 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
824 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 959 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
825 960
826$(BUILT_INS): perf$X 961$(BUILT_INS): $(OUTPUT)perf$X
827 $(QUIET_BUILT_IN)$(RM) $@ && \ 962 $(QUIET_BUILT_IN)$(RM) $@ && \
828 ln perf$X $@ 2>/dev/null || \ 963 ln perf$X $@ 2>/dev/null || \
829 ln -s perf$X $@ 2>/dev/null || \ 964 ln -s perf$X $@ 2>/dev/null || \
830 cp perf$X $@ 965 cp perf$X $@
831 966
832common-cmds.h: util/generate-cmdlist.sh command-list.txt 967$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
833 968
834common-cmds.h: $(wildcard Documentation/perf-*.txt) 969$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
835 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ 970 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
836 971
837$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh 972$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
838 $(QUIET_GEN)$(RM) $@ $@+ && \ 973 $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \
839 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ 974 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
840 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ 975 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
841 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ 976 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
842 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ 977 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
843 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ 978 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
844 $@.sh >$@+ && \ 979 $@.sh > $(OUTPUT)$@+ && \
845 chmod +x $@+ && \ 980 chmod +x $(OUTPUT)$@+ && \
846 mv $@+ $@ 981 mv $(OUTPUT)$@+ $(OUTPUT)$@
847 982
848configure: configure.ac 983configure: configure.ac
849 $(QUIET_GEN)$(RM) $@ $<+ && \ 984 $(QUIET_GEN)$(RM) $@ $<+ && \
@@ -853,60 +988,73 @@ configure: configure.ac
853 $(RM) $<+ 988 $(RM) $<+
854 989
855# These can record PERF_VERSION 990# These can record PERF_VERSION
856perf.o perf.spec \ 991$(OUTPUT)perf.o perf.spec \
857 $(patsubst %.sh,%,$(SCRIPT_SH)) \ 992 $(patsubst %.sh,%,$(SCRIPT_SH)) \
858 $(patsubst %.perl,%,$(SCRIPT_PERL)) \ 993 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
859 : PERF-VERSION-FILE 994 : $(OUTPUT)PERF-VERSION-FILE
860 995
861%.o: %.c PERF-CFLAGS 996$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
862 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< 997 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
863%.s: %.c PERF-CFLAGS 998$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
864 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< 999 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
865%.o: %.S 1000$(OUTPUT)%.o: %.S
866 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< 1001 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
867 1002
868util/exec_cmd.o: util/exec_cmd.c PERF-CFLAGS 1003$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
869 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ 1004 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
870 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ 1005 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
871 '-DBINDIR="$(bindir_relative_SQ)"' \ 1006 '-DBINDIR="$(bindir_relative_SQ)"' \
872 '-DPREFIX="$(prefix_SQ)"' \ 1007 '-DPREFIX="$(prefix_SQ)"' \
873 $< 1008 $<
874 1009
875builtin-init-db.o: builtin-init-db.c PERF-CFLAGS 1010$(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS
876 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $< 1011 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
1012
1013$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
1014 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
877 1015
878util/config.o: util/config.c PERF-CFLAGS 1016$(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
879 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 1017 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
880 1018
881util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS 1019$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
882 $(QUIET_CC)$(CC) -o util/rbtree.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 1020 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
883 1021
884# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing 1022$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
885# from <string.h> that comes from kernel headers wrapping. 1023 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
886KBITMAP_FLAGS=`echo $(ALL_CFLAGS) | sed s/-Wshadow// | sed s/-Wswitch-default// | sed s/-Wextra//`
887 1024
888util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS 1025$(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
889 $(QUIET_CC)$(CC) -o util/bitmap.o -c $(KBITMAP_FLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 1026 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
890 1027
891util/hweight.o: ../../lib/hweight.c PERF-CFLAGS 1028$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
892 $(QUIET_CC)$(CC) -o util/hweight.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 1029 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
893 1030
894util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS 1031$(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS
895 $(QUIET_CC)$(CC) -o util/find_next_bit.o -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< 1032 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
896 1033
897util/trace-event-perl.o: util/trace-event-perl.c PERF-CFLAGS 1034$(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
898 $(QUIET_CC)$(CC) -o util/trace-event-perl.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< 1035 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
899 1036
900scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS 1037$(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/trace-event-python.c $(OUTPUT)PERF-CFLAGS
901 $(QUIET_CC)$(CC) -o scripts/perl/Perf-Trace-Util/Context.o -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< 1038 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
902 1039
903perf-%$X: %.o $(PERFLIBS) 1040$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1041 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
1042
1043$(OUTPUT)perf-%$X: %.o $(PERFLIBS)
904 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 1044 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
905 1045
906$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 1046$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
907$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 1047$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
908builtin-revert.o wt-status.o: wt-status.h 1048builtin-revert.o wt-status.o: wt-status.h
909 1049
1050# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
1051# we depend the various files onto their directories.
1052DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
1053$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
1054# In the second step, we make a rule to actually create these directories
1055$(sort $(dir $(DIRECTORY_DEPS))):
1056 $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
1057
910$(LIB_FILE): $(LIB_OBJS) 1058$(LIB_FILE): $(LIB_OBJS)
911 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 1059 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
912 1060
@@ -941,17 +1089,17 @@ cscope:
941TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ 1089TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
942 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) 1090 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
943 1091
944PERF-CFLAGS: .FORCE-PERF-CFLAGS 1092$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
945 @FLAGS='$(TRACK_CFLAGS)'; \ 1093 @FLAGS='$(TRACK_CFLAGS)'; \
946 if test x"$$FLAGS" != x"`cat PERF-CFLAGS 2>/dev/null`" ; then \ 1094 if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
947 echo 1>&2 " * new build flags or prefix"; \ 1095 echo 1>&2 " * new build flags or prefix"; \
948 echo "$$FLAGS" >PERF-CFLAGS; \ 1096 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
949 fi 1097 fi
950 1098
951# We need to apply sq twice, once to protect from the shell 1099# We need to apply sq twice, once to protect from the shell
952# that runs PERF-BUILD-OPTIONS, and then again to protect it 1100# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it
953# and the first level quoting from the shell that runs "echo". 1101# and the first level quoting from the shell that runs "echo".
954PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS 1102$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
955 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ 1103 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
956 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ 1104 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
957 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ 1105 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
@@ -972,7 +1120,7 @@ all:: $(TEST_PROGRAMS)
972 1120
973export NO_SVN_TESTS 1121export NO_SVN_TESTS
974 1122
975check: common-cmds.h 1123check: $(OUTPUT)common-cmds.h
976 if sparse; \ 1124 if sparse; \
977 then \ 1125 then \
978 for i in *.c */*.c; \ 1126 for i in *.c */*.c; \
@@ -1006,17 +1154,24 @@ export perfexec_instdir
1006 1154
1007install: all 1155install: all
1008 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 1156 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1009 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 1157 $(INSTALL) $(OUTPUT)perf$X '$(DESTDIR_SQ)$(bindir_SQ)'
1010 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1158 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1011 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 1159 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1160 $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1012 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' 1161 $(INSTALL) scripts/perl/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'
1013 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl' 1162 $(INSTALL) scripts/perl/*.pl -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl'
1014 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' 1163 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1164 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1165 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1166 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1167 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1168 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1169
1015ifdef BUILT_INS 1170ifdef BUILT_INS
1016 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1171 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1017 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1172 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1018ifneq (,$X) 1173ifneq (,$X)
1019 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';) 1174 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
1020endif 1175endif
1021endif 1176endif
1022 1177
@@ -1100,25 +1255,20 @@ clean:
1100 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) 1255 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
1101 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 1256 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
1102 $(RM) $(TEST_PROGRAMS) 1257 $(RM) $(TEST_PROGRAMS)
1103 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* 1258 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1104 $(RM) -r autom4te.cache 1259 $(RM) -r autom4te.cache
1105 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache 1260 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
1106 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir 1261 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
1107 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz 1262 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
1108 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz 1263 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
1109 $(MAKE) -C Documentation/ clean 1264 $(MAKE) -C Documentation/ clean
1110 $(RM) PERF-VERSION-FILE PERF-CFLAGS PERF-BUILD-OPTIONS 1265 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS
1111 1266
1112.PHONY: all install clean strip 1267.PHONY: all install clean strip
1113.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 1268.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
1114.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS 1269.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1115.PHONY: .FORCE-PERF-BUILD-OPTIONS 1270.PHONY: .FORCE-PERF-BUILD-OPTIONS
1116 1271
1117.perf.dev.null:
1118 touch .perf.dev.null
1119
1120.INTERMEDIATE: .perf.dev.null
1121
1122### Make sure built-ins do not have dups and listed in perf.c 1272### Make sure built-ins do not have dups and listed in perf.c
1123# 1273#
1124check-builtins:: 1274check-builtins::
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
new file mode 100644
index 000000000000..15130b50dfe3
--- /dev/null
+++ b/tools/perf/arch/arm/Makefile
@@ -0,0 +1,4 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
new file mode 100644
index 000000000000..fff6450c8c99
--- /dev/null
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -0,0 +1,64 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright (C) 2010 Will Deacon, ARM Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <libio.h>
12#include <dwarf-regs.h>
13
14struct pt_regs_dwarfnum {
15 const char *name;
16 unsigned int dwarfnum;
17};
18
19#define STR(s) #s
20#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
21#define GPR_DWARFNUM_NAME(num) \
22 {.name = STR(%r##num), .dwarfnum = num}
23#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
24
25/*
26 * Reference:
27 * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
28 */
29static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
30 GPR_DWARFNUM_NAME(0),
31 GPR_DWARFNUM_NAME(1),
32 GPR_DWARFNUM_NAME(2),
33 GPR_DWARFNUM_NAME(3),
34 GPR_DWARFNUM_NAME(4),
35 GPR_DWARFNUM_NAME(5),
36 GPR_DWARFNUM_NAME(6),
37 GPR_DWARFNUM_NAME(7),
38 GPR_DWARFNUM_NAME(8),
39 GPR_DWARFNUM_NAME(9),
40 GPR_DWARFNUM_NAME(10),
41 REG_DWARFNUM_NAME("%fp", 11),
42 REG_DWARFNUM_NAME("%ip", 12),
43 REG_DWARFNUM_NAME("%sp", 13),
44 REG_DWARFNUM_NAME("%lr", 14),
45 REG_DWARFNUM_NAME("%pc", 15),
46 REG_DWARFNUM_END,
47};
48
49/**
50 * get_arch_regstr() - lookup register name from it's DWARF register number
51 * @n: the DWARF register number
52 *
53 * get_arch_regstr() returns the name of the register in struct
54 * regdwarfnum_table from it's DWARF register number. If the register is not
55 * found in the table, this returns NULL;
56 */
57const char *get_arch_regstr(unsigned int n)
58{
59 const struct pt_regs_dwarfnum *roff;
60 for (roff = regdwarfnum_table; roff->name != NULL; roff++)
61 if (roff->dwarfnum == n)
62 return roff->name;
63 return NULL;
64}
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
new file mode 100644
index 000000000000..15130b50dfe3
--- /dev/null
+++ b/tools/perf/arch/powerpc/Makefile
@@ -0,0 +1,4 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c
new file mode 100644
index 000000000000..48ae0c5e3f73
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/dwarf-regs.c
@@ -0,0 +1,88 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright (C) 2010 Ian Munsie, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <libio.h>
13#include <dwarf-regs.h>
14
15
16struct pt_regs_dwarfnum {
17 const char *name;
18 unsigned int dwarfnum;
19};
20
21#define STR(s) #s
22#define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num}
23#define GPR_DWARFNUM_NAME(num) \
24 {.name = STR(%gpr##num), .dwarfnum = num}
25#define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0}
26
27/*
28 * Reference:
29 * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
30 */
31static const struct pt_regs_dwarfnum regdwarfnum_table[] = {
32 GPR_DWARFNUM_NAME(0),
33 GPR_DWARFNUM_NAME(1),
34 GPR_DWARFNUM_NAME(2),
35 GPR_DWARFNUM_NAME(3),
36 GPR_DWARFNUM_NAME(4),
37 GPR_DWARFNUM_NAME(5),
38 GPR_DWARFNUM_NAME(6),
39 GPR_DWARFNUM_NAME(7),
40 GPR_DWARFNUM_NAME(8),
41 GPR_DWARFNUM_NAME(9),
42 GPR_DWARFNUM_NAME(10),
43 GPR_DWARFNUM_NAME(11),
44 GPR_DWARFNUM_NAME(12),
45 GPR_DWARFNUM_NAME(13),
46 GPR_DWARFNUM_NAME(14),
47 GPR_DWARFNUM_NAME(15),
48 GPR_DWARFNUM_NAME(16),
49 GPR_DWARFNUM_NAME(17),
50 GPR_DWARFNUM_NAME(18),
51 GPR_DWARFNUM_NAME(19),
52 GPR_DWARFNUM_NAME(20),
53 GPR_DWARFNUM_NAME(21),
54 GPR_DWARFNUM_NAME(22),
55 GPR_DWARFNUM_NAME(23),
56 GPR_DWARFNUM_NAME(24),
57 GPR_DWARFNUM_NAME(25),
58 GPR_DWARFNUM_NAME(26),
59 GPR_DWARFNUM_NAME(27),
60 GPR_DWARFNUM_NAME(28),
61 GPR_DWARFNUM_NAME(29),
62 GPR_DWARFNUM_NAME(30),
63 GPR_DWARFNUM_NAME(31),
64 REG_DWARFNUM_NAME("%msr", 66),
65 REG_DWARFNUM_NAME("%ctr", 109),
66 REG_DWARFNUM_NAME("%link", 108),
67 REG_DWARFNUM_NAME("%xer", 101),
68 REG_DWARFNUM_NAME("%dar", 119),
69 REG_DWARFNUM_NAME("%dsisr", 118),
70 REG_DWARFNUM_END,
71};
72
73/**
74 * get_arch_regstr() - lookup register name from it's DWARF register number
75 * @n: the DWARF register number
76 *
77 * get_arch_regstr() returns the name of the register in struct
78 * regdwarfnum_table from it's DWARF register number. If the register is not
79 * found in the table, this returns NULL;
80 */
81const char *get_arch_regstr(unsigned int n)
82{
83 const struct pt_regs_dwarfnum *roff;
84 for (roff = regdwarfnum_table; roff->name != NULL; roff++)
85 if (roff->dwarfnum == n)
86 return roff->name;
87 return NULL;
88}
diff --git a/tools/perf/arch/s390/Makefile b/tools/perf/arch/s390/Makefile
new file mode 100644
index 000000000000..15130b50dfe3
--- /dev/null
+++ b/tools/perf/arch/s390/Makefile
@@ -0,0 +1,4 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c
new file mode 100644
index 000000000000..e19653e025fa
--- /dev/null
+++ b/tools/perf/arch/s390/util/dwarf-regs.c
@@ -0,0 +1,22 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright IBM Corp. 2010
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
6 *
7 */
8
9#include <libio.h>
10#include <dwarf-regs.h>
11
12#define NUM_GPRS 16
13
14static const char *gpr_names[NUM_GPRS] = {
15 "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
16 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
17};
18
19const char *get_arch_regstr(unsigned int n)
20{
21 return (n >= NUM_GPRS) ? NULL : gpr_names[n];
22}
diff --git a/tools/perf/arch/sh/Makefile b/tools/perf/arch/sh/Makefile
new file mode 100644
index 000000000000..15130b50dfe3
--- /dev/null
+++ b/tools/perf/arch/sh/Makefile
@@ -0,0 +1,4 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c
new file mode 100644
index 000000000000..a11edb007a6c
--- /dev/null
+++ b/tools/perf/arch/sh/util/dwarf-regs.c
@@ -0,0 +1,55 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright (C) 2010 Matt Fleming <matt@console-pimps.org>
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 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include <libio.h>
23#include <dwarf-regs.h>
24
25/*
26 * Generic dwarf analysis helpers
27 */
28
29#define SH_MAX_REGS 18
30const char *sh_regs_table[SH_MAX_REGS] = {
31 "r0",
32 "r1",
33 "r2",
34 "r3",
35 "r4",
36 "r5",
37 "r6",
38 "r7",
39 "r8",
40 "r9",
41 "r10",
42 "r11",
43 "r12",
44 "r13",
45 "r14",
46 "r15",
47 "pc",
48 "pr",
49};
50
51/* Return architecture dependent register string (for kprobe-tracer) */
52const char *get_arch_regstr(unsigned int n)
53{
54 return (n <= SH_MAX_REGS) ? sh_regs_table[n] : NULL;
55}
diff --git a/tools/perf/arch/sparc/Makefile b/tools/perf/arch/sparc/Makefile
new file mode 100644
index 000000000000..15130b50dfe3
--- /dev/null
+++ b/tools/perf/arch/sparc/Makefile
@@ -0,0 +1,4 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c
new file mode 100644
index 000000000000..0ab88483720c
--- /dev/null
+++ b/tools/perf/arch/sparc/util/dwarf-regs.c
@@ -0,0 +1,43 @@
1/*
2 * Mapping of DWARF debug register numbers into register names.
3 *
4 * Copyright (C) 2010 David S. Miller <davem@davemloft.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <libio.h>
13#include <dwarf-regs.h>
14
15#define SPARC_MAX_REGS 96
16
17const char *sparc_regs_table[SPARC_MAX_REGS] = {
18 "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
19 "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
20 "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
21 "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7",
22 "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
23 "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
24 "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
25 "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
26 "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39",
27 "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47",
28 "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55",
29 "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63",
30};
31
32/**
33 * get_arch_regstr() - lookup register name from it's DWARF register number
34 * @n: the DWARF register number
35 *
36 * get_arch_regstr() returns the name of the register in struct
37 * regdwarfnum_table from it's DWARF register number. If the register is not
38 * found in the table, this returns NULL;
39 */
40const char *get_arch_regstr(unsigned int n)
41{
42 return (n <= SPARC_MAX_REGS) ? sparc_regs_table[n] : NULL;
43}
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
new file mode 100644
index 000000000000..15130b50dfe3
--- /dev/null
+++ b/tools/perf/arch/x86/Makefile
@@ -0,0 +1,4 @@
1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1
3LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
4endif
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c
new file mode 100644
index 000000000000..a794d3081928
--- /dev/null
+++ b/tools/perf/arch/x86/util/dwarf-regs.c
@@ -0,0 +1,75 @@
1/*
2 * dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
3 * Extracted from probe-finder.c
4 *
5 * Written by Masami Hiramatsu <mhiramat@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 */
22
23#include <libio.h>
24#include <dwarf-regs.h>
25
26/*
27 * Generic dwarf analysis helpers
28 */
29
30#define X86_32_MAX_REGS 8
31const char *x86_32_regs_table[X86_32_MAX_REGS] = {
32 "%ax",
33 "%cx",
34 "%dx",
35 "%bx",
36 "$stack", /* Stack address instead of %sp */
37 "%bp",
38 "%si",
39 "%di",
40};
41
42#define X86_64_MAX_REGS 16
43const char *x86_64_regs_table[X86_64_MAX_REGS] = {
44 "%ax",
45 "%dx",
46 "%cx",
47 "%bx",
48 "%si",
49 "%di",
50 "%bp",
51 "%sp",
52 "%r8",
53 "%r9",
54 "%r10",
55 "%r11",
56 "%r12",
57 "%r13",
58 "%r14",
59 "%r15",
60};
61
62/* TODO: switching by dwarf address size */
63#ifdef __x86_64__
64#define ARCH_MAX_REGS X86_64_MAX_REGS
65#define arch_regs_table x86_64_regs_table
66#else
67#define ARCH_MAX_REGS X86_32_MAX_REGS
68#define arch_regs_table x86_32_regs_table
69#endif
70
71/* Return architecture dependent register string (for kprobe-tracer) */
72const char *get_arch_regstr(unsigned int n)
73{
74 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
75}
diff --git a/tools/perf/bench/mem-memcpy-arch.h b/tools/perf/bench/mem-memcpy-arch.h
new file mode 100644
index 000000000000..a72e36cb5394
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy-arch.h
@@ -0,0 +1,12 @@
1
2#ifdef ARCH_X86_64
3
4#define MEMCPY_FN(fn, name, desc) \
5 extern void *fn(void *, const void *, size_t);
6
7#include "mem-memcpy-x86-64-asm-def.h"
8
9#undef MEMCPY_FN
10
11#endif
12
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm-def.h b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
new file mode 100644
index 000000000000..d588b87696fc
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm-def.h
@@ -0,0 +1,4 @@
1
2MEMCPY_FN(__memcpy,
3 "x86-64-unrolled",
4 "unrolled memcpy() in arch/x86/lib/memcpy_64.S")
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S
new file mode 100644
index 000000000000..a57b66e853c2
--- /dev/null
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S
@@ -0,0 +1,2 @@
1
2#include "../../../arch/x86/lib/memcpy_64.S"
diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c
index 89773178e894..db82021f4b91 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -10,9 +10,9 @@
10#include "../perf.h" 10#include "../perf.h"
11#include "../util/util.h" 11#include "../util/util.h"
12#include "../util/parse-options.h" 12#include "../util/parse-options.h"
13#include "../util/string.h"
14#include "../util/header.h" 13#include "../util/header.h"
15#include "bench.h" 14#include "bench.h"
15#include "mem-memcpy-arch.h"
16 16
17#include <stdio.h> 17#include <stdio.h>
18#include <stdlib.h> 18#include <stdlib.h>
@@ -24,8 +24,10 @@
24 24
25static const char *length_str = "1MB"; 25static const char *length_str = "1MB";
26static const char *routine = "default"; 26static const char *routine = "default";
27static int use_clock = 0; 27static bool use_clock;
28static int clock_fd; 28static int clock_fd;
29static bool only_prefault;
30static bool no_prefault;
29 31
30static const struct option options[] = { 32static const struct option options[] = {
31 OPT_STRING('l', "length", &length_str, "1MB", 33 OPT_STRING('l', "length", &length_str, "1MB",
@@ -35,19 +37,33 @@ static const struct option options[] = {
35 "Specify routine to copy"), 37 "Specify routine to copy"),
36 OPT_BOOLEAN('c', "clock", &use_clock, 38 OPT_BOOLEAN('c', "clock", &use_clock,
37 "Use CPU clock for measuring"), 39 "Use CPU clock for measuring"),
40 OPT_BOOLEAN('o', "only-prefault", &only_prefault,
41 "Show only the result with page faults before memcpy()"),
42 OPT_BOOLEAN('n', "no-prefault", &no_prefault,
43 "Show only the result without page faults before memcpy()"),
38 OPT_END() 44 OPT_END()
39}; 45};
40 46
47typedef void *(*memcpy_t)(void *, const void *, size_t);
48
41struct routine { 49struct routine {
42 const char *name; 50 const char *name;
43 const char *desc; 51 const char *desc;
44 void * (*fn)(void *dst, const void *src, size_t len); 52 memcpy_t fn;
45}; 53};
46 54
47struct routine routines[] = { 55struct routine routines[] = {
48 { "default", 56 { "default",
49 "Default memcpy() provided by glibc", 57 "Default memcpy() provided by glibc",
50 memcpy }, 58 memcpy },
59#ifdef ARCH_X86_64
60
61#define MEMCPY_FN(fn, name, desc) { name, desc, fn },
62#include "mem-memcpy-x86-64-asm-def.h"
63#undef MEMCPY_FN
64
65#endif
66
51 { NULL, 67 { NULL,
52 NULL, 68 NULL,
53 NULL } 69 NULL }
@@ -90,29 +106,98 @@ static double timeval2double(struct timeval *ts)
90 (double)ts->tv_usec / (double)1000000; 106 (double)ts->tv_usec / (double)1000000;
91} 107}
92 108
109static void alloc_mem(void **dst, void **src, size_t length)
110{
111 *dst = zalloc(length);
112 if (!dst)
113 die("memory allocation failed - maybe length is too large?\n");
114
115 *src = zalloc(length);
116 if (!src)
117 die("memory allocation failed - maybe length is too large?\n");
118}
119
120static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
121{
122 u64 clock_start = 0ULL, clock_end = 0ULL;
123 void *src = NULL, *dst = NULL;
124
125 alloc_mem(&src, &dst, len);
126
127 if (prefault)
128 fn(dst, src, len);
129
130 clock_start = get_clock();
131 fn(dst, src, len);
132 clock_end = get_clock();
133
134 free(src);
135 free(dst);
136 return clock_end - clock_start;
137}
138
139static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
140{
141 struct timeval tv_start, tv_end, tv_diff;
142 void *src = NULL, *dst = NULL;
143
144 alloc_mem(&src, &dst, len);
145
146 if (prefault)
147 fn(dst, src, len);
148
149 BUG_ON(gettimeofday(&tv_start, NULL));
150 fn(dst, src, len);
151 BUG_ON(gettimeofday(&tv_end, NULL));
152
153 timersub(&tv_end, &tv_start, &tv_diff);
154
155 free(src);
156 free(dst);
157 return (double)((double)len / timeval2double(&tv_diff));
158}
159
160#define pf (no_prefault ? 0 : 1)
161
162#define print_bps(x) do { \
163 if (x < K) \
164 printf(" %14lf B/Sec", x); \
165 else if (x < K * K) \
166 printf(" %14lfd KB/Sec", x / K); \
167 else if (x < K * K * K) \
168 printf(" %14lf MB/Sec", x / K / K); \
169 else \
170 printf(" %14lf GB/Sec", x / K / K / K); \
171 } while (0)
172
93int bench_mem_memcpy(int argc, const char **argv, 173int bench_mem_memcpy(int argc, const char **argv,
94 const char *prefix __used) 174 const char *prefix __used)
95{ 175{
96 int i; 176 int i;
97 void *dst, *src; 177 size_t len;
98 size_t length; 178 double result_bps[2];
99 double bps = 0.0; 179 u64 result_clock[2];
100 struct timeval tv_start, tv_end, tv_diff;
101 u64 clock_start, clock_end, clock_diff;
102 180
103 clock_start = clock_end = clock_diff = 0ULL;
104 argc = parse_options(argc, argv, options, 181 argc = parse_options(argc, argv, options,
105 bench_mem_memcpy_usage, 0); 182 bench_mem_memcpy_usage, 0);
106 183
107 tv_diff.tv_sec = 0; 184 if (use_clock)
108 tv_diff.tv_usec = 0; 185 init_clock();
109 length = (size_t)perf_atoll((char *)length_str); 186
187 len = (size_t)perf_atoll((char *)length_str);
110 188
111 if ((s64)length <= 0) { 189 result_clock[0] = result_clock[1] = 0ULL;
190 result_bps[0] = result_bps[1] = 0.0;
191
192 if ((s64)len <= 0) {
112 fprintf(stderr, "Invalid length:%s\n", length_str); 193 fprintf(stderr, "Invalid length:%s\n", length_str);
113 return 1; 194 return 1;
114 } 195 }
115 196
197 /* same to without specifying either of prefault and no-prefault */
198 if (only_prefault && no_prefault)
199 only_prefault = no_prefault = false;
200
116 for (i = 0; routines[i].name; i++) { 201 for (i = 0; routines[i].name; i++) {
117 if (!strcmp(routines[i].name, routine)) 202 if (!strcmp(routines[i].name, routine))
118 break; 203 break;
@@ -127,61 +212,80 @@ int bench_mem_memcpy(int argc, const char **argv,
127 return 1; 212 return 1;
128 } 213 }
129 214
130 dst = zalloc(length); 215 if (bench_format == BENCH_FORMAT_DEFAULT)
131 if (!dst) 216 printf("# Copying %s Bytes ...\n\n", length_str);
132 die("memory allocation failed - maybe length is too large?\n");
133
134 src = zalloc(length);
135 if (!src)
136 die("memory allocation failed - maybe length is too large?\n");
137
138 if (bench_format == BENCH_FORMAT_DEFAULT) {
139 printf("# Copying %s Bytes from %p to %p ...\n\n",
140 length_str, src, dst);
141 }
142
143 if (use_clock) {
144 init_clock();
145 clock_start = get_clock();
146 } else {
147 BUG_ON(gettimeofday(&tv_start, NULL));
148 }
149
150 routines[i].fn(dst, src, length);
151 217
152 if (use_clock) { 218 if (!only_prefault && !no_prefault) {
153 clock_end = get_clock(); 219 /* show both of results */
154 clock_diff = clock_end - clock_start; 220 if (use_clock) {
221 result_clock[0] =
222 do_memcpy_clock(routines[i].fn, len, false);
223 result_clock[1] =
224 do_memcpy_clock(routines[i].fn, len, true);
225 } else {
226 result_bps[0] =
227 do_memcpy_gettimeofday(routines[i].fn,
228 len, false);
229 result_bps[1] =
230 do_memcpy_gettimeofday(routines[i].fn,
231 len, true);
232 }
155 } else { 233 } else {
156 BUG_ON(gettimeofday(&tv_end, NULL)); 234 if (use_clock) {
157 timersub(&tv_end, &tv_start, &tv_diff); 235 result_clock[pf] =
158 bps = (double)((double)length / timeval2double(&tv_diff)); 236 do_memcpy_clock(routines[i].fn,
237 len, only_prefault);
238 } else {
239 result_bps[pf] =
240 do_memcpy_gettimeofday(routines[i].fn,
241 len, only_prefault);
242 }
159 } 243 }
160 244
161 switch (bench_format) { 245 switch (bench_format) {
162 case BENCH_FORMAT_DEFAULT: 246 case BENCH_FORMAT_DEFAULT:
163 if (use_clock) { 247 if (!only_prefault && !no_prefault) {
164 printf(" %14lf Clock/Byte\n", 248 if (use_clock) {
165 (double)clock_diff / (double)length); 249 printf(" %14lf Clock/Byte\n",
166 } else { 250 (double)result_clock[0]
167 if (bps < K) 251 / (double)len);
168 printf(" %14lf B/Sec\n", bps); 252 printf(" %14lf Clock/Byte (with prefault)\n",
169 else if (bps < K * K) 253 (double)result_clock[1]
170 printf(" %14lfd KB/Sec\n", bps / 1024); 254 / (double)len);
171 else if (bps < K * K * K) 255 } else {
172 printf(" %14lf MB/Sec\n", bps / 1024 / 1024); 256 print_bps(result_bps[0]);
173 else { 257 printf("\n");
174 printf(" %14lf GB/Sec\n", 258 print_bps(result_bps[1]);
175 bps / 1024 / 1024 / 1024); 259 printf(" (with prefault)\n");
176 } 260 }
261 } else {
262 if (use_clock) {
263 printf(" %14lf Clock/Byte",
264 (double)result_clock[pf]
265 / (double)len);
266 } else
267 print_bps(result_bps[pf]);
268
269 printf("%s\n", only_prefault ? " (with prefault)" : "");
177 } 270 }
178 break; 271 break;
179 case BENCH_FORMAT_SIMPLE: 272 case BENCH_FORMAT_SIMPLE:
180 if (use_clock) { 273 if (!only_prefault && !no_prefault) {
181 printf("%14lf\n", 274 if (use_clock) {
182 (double)clock_diff / (double)length); 275 printf("%lf %lf\n",
183 } else 276 (double)result_clock[0] / (double)len,
184 printf("%lf\n", bps); 277 (double)result_clock[1] / (double)len);
278 } else {
279 printf("%lf %lf\n",
280 result_bps[0], result_bps[1]);
281 }
282 } else {
283 if (use_clock) {
284 printf("%lf\n", (double)result_clock[pf]
285 / (double)len);
286 } else
287 printf("%lf\n", result_bps[pf]);
288 }
185 break; 289 break;
186 default: 290 default:
187 /* reaching this means there's some disaster: */ 291 /* reaching this means there's some disaster: */
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index 81cee78181fa..d1d1b30f99c1 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -31,9 +31,9 @@
31 31
32#define DATASIZE 100 32#define DATASIZE 100
33 33
34static int use_pipes = 0; 34static bool use_pipes = false;
35static unsigned int loops = 100; 35static unsigned int loops = 100;
36static unsigned int thread_mode = 0; 36static bool thread_mode = false;
37static unsigned int num_groups = 10; 37static unsigned int num_groups = 10;
38 38
39struct sender_context { 39struct sender_context {
@@ -256,10 +256,8 @@ static const struct option options[] = {
256 "Use pipe() instead of socketpair()"), 256 "Use pipe() instead of socketpair()"),
257 OPT_BOOLEAN('t', "thread", &thread_mode, 257 OPT_BOOLEAN('t', "thread", &thread_mode,
258 "Be multi thread instead of multi process"), 258 "Be multi thread instead of multi process"),
259 OPT_INTEGER('g', "group", &num_groups, 259 OPT_UINTEGER('g', "group", &num_groups, "Specify number of groups"),
260 "Specify number of groups"), 260 OPT_UINTEGER('l', "loop", &loops, "Specify number of loops"),
261 OPT_INTEGER('l', "loop", &loops,
262 "Specify number of loops"),
263 OPT_END() 261 OPT_END()
264}; 262};
265 263
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 4f77c7c27640..d9ab3ce446ac 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -93,7 +93,7 @@ int bench_sched_pipe(int argc, const char **argv,
93 93
94 switch (bench_format) { 94 switch (bench_format) {
95 case BENCH_FORMAT_DEFAULT: 95 case BENCH_FORMAT_DEFAULT:
96 printf("# Extecuted %d pipe operations between two tasks\n\n", 96 printf("# Executed %d pipe operations between two tasks\n\n",
97 loops); 97 loops);
98 98
99 result_usec = diff.tv_sec * 1000000; 99 result_usec = diff.tv_sec * 1000000;
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 593ff25006de..c056cdc06912 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -14,7 +14,6 @@
14#include "util/cache.h" 14#include "util/cache.h"
15#include <linux/rbtree.h> 15#include <linux/rbtree.h>
16#include "util/symbol.h" 16#include "util/symbol.h"
17#include "util/string.h"
18 17
19#include "perf.h" 18#include "perf.h"
20#include "util/debug.h" 19#include "util/debug.h"
@@ -29,175 +28,65 @@
29 28
30static char const *input_name = "perf.data"; 29static char const *input_name = "perf.data";
31 30
32static int force; 31static bool force, use_tui, use_stdio;
33 32
34static int full_paths; 33static bool full_paths;
35 34
36static int print_line; 35static bool print_line;
37
38struct sym_hist {
39 u64 sum;
40 u64 ip[0];
41};
42
43struct sym_ext {
44 struct rb_node node;
45 double percent;
46 char *path;
47};
48
49struct sym_priv {
50 struct sym_hist *hist;
51 struct sym_ext *ext;
52};
53 36
54static const char *sym_hist_filter; 37static const char *sym_hist_filter;
55 38
56static int symbol_filter(struct map *map __used, struct symbol *sym) 39static int hists__add_entry(struct hists *self, struct addr_location *al)
57{ 40{
58 if (sym_hist_filter == NULL || 41 struct hist_entry *he;
59 strcmp(sym->name, sym_hist_filter) == 0) { 42
60 struct sym_priv *priv = symbol__priv(sym); 43 if (sym_hist_filter != NULL &&
61 const int size = (sizeof(*priv->hist) + 44 (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
62 (sym->end - sym->start) * sizeof(u64)); 45 /* We're only interested in a symbol named sym_hist_filter */
63 46 if (al->sym != NULL) {
64 priv->hist = malloc(size); 47 rb_erase(&al->sym->rb_node,
65 if (priv->hist) 48 &al->map->dso->symbols[al->map->type]);
66 memset(priv->hist, 0, size); 49 symbol__delete(al->sym);
50 }
67 return 0; 51 return 0;
68 } 52 }
69 /*
70 * FIXME: We should really filter it out, as we don't want to go thru symbols
71 * we're not interested, and if a DSO ends up with no symbols, delete it too,
72 * but right now the kernel loading routines in symbol.c bail out if no symbols
73 * are found, fix it later.
74 */
75 return 0;
76}
77
78/*
79 * collect histogram counts
80 */
81static void hist_hit(struct hist_entry *he, u64 ip)
82{
83 unsigned int sym_size, offset;
84 struct symbol *sym = he->sym;
85 struct sym_priv *priv;
86 struct sym_hist *h;
87 53
88 he->count++; 54 he = __hists__add_entry(self, al, NULL, 1);
89
90 if (!sym || !he->map)
91 return;
92
93 priv = symbol__priv(sym);
94 if (!priv->hist)
95 return;
96
97 sym_size = sym->end - sym->start;
98 offset = ip - sym->start;
99
100 if (verbose)
101 fprintf(stderr, "%s: ip=%Lx\n", __func__,
102 he->map->unmap_ip(he->map, ip));
103
104 if (offset >= sym_size)
105 return;
106
107 h = priv->hist;
108 h->sum++;
109 h->ip[offset]++;
110
111 if (verbose >= 3)
112 printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n",
113 (void *)(unsigned long)he->sym->start,
114 he->sym->name,
115 (void *)(unsigned long)ip, ip - he->sym->start,
116 h->ip[offset]);
117}
118
119static int perf_session__add_hist_entry(struct perf_session *self,
120 struct addr_location *al, u64 count)
121{
122 bool hit;
123 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL,
124 count, &hit);
125 if (he == NULL) 55 if (he == NULL)
126 return -ENOMEM; 56 return -ENOMEM;
127 hist_hit(he, al->addr); 57
128 return 0; 58 return hist_entry__inc_addr_samples(he, al->addr);
129} 59}
130 60
131static int process_sample_event(event_t *event, struct perf_session *session) 61static int process_sample_event(event_t *event, struct sample_data *sample,
62 struct perf_session *session)
132{ 63{
133 struct addr_location al; 64 struct addr_location al;
134 65
135 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 66 if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
136 event->ip.pid, (void *)(long)event->ip.ip); 67 pr_warning("problem processing %d event, skipping it.\n",
137 68 event->header.type);
138 if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) {
139 fprintf(stderr, "problem processing %d event, skipping it.\n",
140 event->header.type);
141 return -1; 69 return -1;
142 } 70 }
143 71
144 if (!al.filtered && perf_session__add_hist_entry(session, &al, 1)) { 72 if (!al.filtered && hists__add_entry(&session->hists, &al)) {
145 fprintf(stderr, "problem incrementing symbol count, " 73 pr_warning("problem incrementing symbol count, "
146 "skipping event\n"); 74 "skipping event\n");
147 return -1; 75 return -1;
148 } 76 }
149 77
150 return 0; 78 return 0;
151} 79}
152 80
153static int parse_line(FILE *file, struct hist_entry *he, u64 len) 81static int objdump_line__print(struct objdump_line *self,
82 struct list_head *head,
83 struct hist_entry *he, u64 len)
154{ 84{
155 struct symbol *sym = he->sym; 85 struct symbol *sym = he->ms.sym;
156 char *line = NULL, *tmp, *tmp2;
157 static const char *prev_line; 86 static const char *prev_line;
158 static const char *prev_color; 87 static const char *prev_color;
159 unsigned int offset;
160 size_t line_len;
161 u64 start;
162 s64 line_ip;
163 int ret;
164 char *c;
165
166 if (getline(&line, &line_len, file) < 0)
167 return -1;
168 if (!line)
169 return -1;
170 88
171 c = strchr(line, '\n'); 89 if (self->offset != -1) {
172 if (c)
173 *c = 0;
174
175 line_ip = -1;
176 offset = 0;
177 ret = -2;
178
179 /*
180 * Strip leading spaces:
181 */
182 tmp = line;
183 while (*tmp) {
184 if (*tmp != ' ')
185 break;
186 tmp++;
187 }
188
189 if (*tmp) {
190 /*
191 * Parse hexa addresses followed by ':'
192 */
193 line_ip = strtoull(tmp, &tmp2, 16);
194 if (*tmp2 != ':')
195 line_ip = -1;
196 }
197
198 start = he->map->unmap_ip(he->map, sym->start);
199
200 if (line_ip != -1) {
201 const char *path = NULL; 90 const char *path = NULL;
202 unsigned int hits = 0; 91 unsigned int hits = 0;
203 double percent = 0.0; 92 double percent = 0.0;
@@ -205,15 +94,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
205 struct sym_priv *priv = symbol__priv(sym); 94 struct sym_priv *priv = symbol__priv(sym);
206 struct sym_ext *sym_ext = priv->ext; 95 struct sym_ext *sym_ext = priv->ext;
207 struct sym_hist *h = priv->hist; 96 struct sym_hist *h = priv->hist;
97 s64 offset = self->offset;
98 struct objdump_line *next = objdump__get_next_ip_line(head, self);
99
100 while (offset < (s64)len &&
101 (next == NULL || offset < next->offset)) {
102 if (sym_ext) {
103 if (path == NULL)
104 path = sym_ext[offset].path;
105 percent += sym_ext[offset].percent;
106 } else
107 hits += h->ip[offset];
108
109 ++offset;
110 }
208 111
209 offset = line_ip - start; 112 if (sym_ext == NULL && h->sum)
210 if (offset < len)
211 hits = h->ip[offset];
212
213 if (offset < len && sym_ext) {
214 path = sym_ext[offset].path;
215 percent = sym_ext[offset].percent;
216 } else if (h->sum)
217 percent = 100.0 * hits / h->sum; 113 percent = 100.0 * hits / h->sum;
218 114
219 color = get_percent_color(percent); 115 color = get_percent_color(percent);
@@ -234,12 +130,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len)
234 130
235 color_fprintf(stdout, color, " %7.2f", percent); 131 color_fprintf(stdout, color, " %7.2f", percent);
236 printf(" : "); 132 printf(" : ");
237 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); 133 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
238 } else { 134 } else {
239 if (!*line) 135 if (!*self->line)
240 printf(" :\n"); 136 printf(" :\n");
241 else 137 else
242 printf(" : %s\n", line); 138 printf(" : %s\n", self->line);
243 } 139 }
244 140
245 return 0; 141 return 0;
@@ -269,7 +165,7 @@ static void insert_source_line(struct sym_ext *sym_ext)
269 165
270static void free_source_line(struct hist_entry *he, int len) 166static void free_source_line(struct hist_entry *he, int len)
271{ 167{
272 struct sym_priv *priv = symbol__priv(he->sym); 168 struct sym_priv *priv = symbol__priv(he->ms.sym);
273 struct sym_ext *sym_ext = priv->ext; 169 struct sym_ext *sym_ext = priv->ext;
274 int i; 170 int i;
275 171
@@ -288,7 +184,7 @@ static void free_source_line(struct hist_entry *he, int len)
288static void 184static void
289get_source_line(struct hist_entry *he, int len, const char *filename) 185get_source_line(struct hist_entry *he, int len, const char *filename)
290{ 186{
291 struct symbol *sym = he->sym; 187 struct symbol *sym = he->ms.sym;
292 u64 start; 188 u64 start;
293 int i; 189 int i;
294 char cmd[PATH_MAX * 2]; 190 char cmd[PATH_MAX * 2];
@@ -303,7 +199,7 @@ get_source_line(struct hist_entry *he, int len, const char *filename)
303 if (!priv->ext) 199 if (!priv->ext)
304 return; 200 return;
305 201
306 start = he->map->unmap_ip(he->map, sym->start); 202 start = he->ms.map->unmap_ip(he->ms.map, sym->start);
307 203
308 for (i = 0; i < len; i++) { 204 for (i = 0; i < len; i++) {
309 char *path = NULL; 205 char *path = NULL;
@@ -365,24 +261,32 @@ static void print_summary(const char *filename)
365 } 261 }
366} 262}
367 263
368static void annotate_sym(struct hist_entry *he) 264static void hist_entry__print_hits(struct hist_entry *self)
369{ 265{
370 struct map *map = he->map; 266 struct symbol *sym = self->ms.sym;
267 struct sym_priv *priv = symbol__priv(sym);
268 struct sym_hist *h = priv->hist;
269 u64 len = sym->end - sym->start, offset;
270
271 for (offset = 0; offset < len; ++offset)
272 if (h->ip[offset] != 0)
273 printf("%*Lx: %Lu\n", BITS_PER_LONG / 2,
274 sym->start + offset, h->ip[offset]);
275 printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum);
276}
277
278static int hist_entry__tty_annotate(struct hist_entry *he)
279{
280 struct map *map = he->ms.map;
371 struct dso *dso = map->dso; 281 struct dso *dso = map->dso;
372 struct symbol *sym = he->sym; 282 struct symbol *sym = he->ms.sym;
373 const char *filename = dso->long_name, *d_filename; 283 const char *filename = dso->long_name, *d_filename;
374 u64 len; 284 u64 len;
375 char command[PATH_MAX*2]; 285 LIST_HEAD(head);
376 FILE *file; 286 struct objdump_line *pos, *n;
377 287
378 if (!filename) 288 if (hist_entry__annotate(he, &head, 0) < 0)
379 return; 289 return -1;
380
381 if (verbose)
382 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n",
383 __func__, filename, sym->name,
384 map->unmap_ip(map, sym->start),
385 map->unmap_ip(map, sym->end));
386 290
387 if (full_paths) 291 if (full_paths)
388 d_filename = filename; 292 d_filename = filename;
@@ -400,61 +304,79 @@ static void annotate_sym(struct hist_entry *he)
400 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 304 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
401 printf("------------------------------------------------\n"); 305 printf("------------------------------------------------\n");
402 306
403 if (verbose >= 2) 307 if (verbose)
404 printf("annotating [%p] %30s : [%p] %30s\n", 308 hist_entry__print_hits(he);
405 dso, dso->long_name, sym, sym->name);
406
407 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s",
408 map->unmap_ip(map, sym->start), map->unmap_ip(map, sym->end),
409 filename, filename);
410
411 if (verbose >= 3)
412 printf("doing: %s\n", command);
413
414 file = popen(command, "r");
415 if (!file)
416 return;
417 309
418 while (!feof(file)) { 310 list_for_each_entry_safe(pos, n, &head, node) {
419 if (parse_line(file, he, len) < 0) 311 objdump_line__print(pos, &head, he, len);
420 break; 312 list_del(&pos->node);
313 objdump_line__free(pos);
421 } 314 }
422 315
423 pclose(file);
424 if (print_line) 316 if (print_line)
425 free_source_line(he, len); 317 free_source_line(he, len);
318
319 return 0;
426} 320}
427 321
428static void perf_session__find_annotations(struct perf_session *self) 322static void hists__find_annotations(struct hists *self)
429{ 323{
430 struct rb_node *nd; 324 struct rb_node *nd = rb_first(&self->entries), *next;
325 int key = KEY_RIGHT;
431 326
432 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { 327 while (nd) {
433 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 328 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
434 struct sym_priv *priv; 329 struct sym_priv *priv;
435 330
436 if (he->sym == NULL) 331 if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
437 continue; 332 goto find_next;
438 333
439 priv = symbol__priv(he->sym); 334 priv = symbol__priv(he->ms.sym);
440 if (priv->hist == NULL) 335 if (priv->hist == NULL) {
336find_next:
337 if (key == KEY_LEFT)
338 nd = rb_prev(nd);
339 else
340 nd = rb_next(nd);
441 continue; 341 continue;
342 }
442 343
443 annotate_sym(he); 344 if (use_browser > 0) {
444 /* 345 key = hist_entry__tui_annotate(he);
445 * Since we have a hist_entry per IP for the same symbol, free 346 switch (key) {
446 * he->sym->hist to signal we already processed this symbol. 347 case KEY_RIGHT:
447 */ 348 next = rb_next(nd);
448 free(priv->hist); 349 break;
449 priv->hist = NULL; 350 case KEY_LEFT:
351 next = rb_prev(nd);
352 break;
353 default:
354 return;
355 }
356
357 if (next != NULL)
358 nd = next;
359 } else {
360 hist_entry__tty_annotate(he);
361 nd = rb_next(nd);
362 /*
363 * Since we have a hist_entry per IP for the same
364 * symbol, free he->ms.sym->hist to signal we already
365 * processed this symbol.
366 */
367 free(priv->hist);
368 priv->hist = NULL;
369 }
450 } 370 }
451} 371}
452 372
453static struct perf_event_ops event_ops = { 373static struct perf_event_ops event_ops = {
454 .process_sample_event = process_sample_event, 374 .sample = process_sample_event,
455 .process_mmap_event = event__process_mmap, 375 .mmap = event__process_mmap,
456 .process_comm_event = event__process_comm, 376 .comm = event__process_comm,
457 .process_fork_event = event__process_task, 377 .fork = event__process_task,
378 .ordered_samples = true,
379 .ordering_requires_timestamps = true,
458}; 380};
459 381
460static int __cmd_annotate(void) 382static int __cmd_annotate(void)
@@ -462,7 +384,7 @@ static int __cmd_annotate(void)
462 int ret; 384 int ret;
463 struct perf_session *session; 385 struct perf_session *session;
464 386
465 session = perf_session__new(input_name, O_RDONLY, force); 387 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
466 if (session == NULL) 388 if (session == NULL)
467 return -ENOMEM; 389 return -ENOMEM;
468 390
@@ -471,7 +393,7 @@ static int __cmd_annotate(void)
471 goto out_delete; 393 goto out_delete;
472 394
473 if (dump_trace) { 395 if (dump_trace) {
474 event__print_totals(); 396 perf_session__fprintf_nr_events(session, stdout);
475 goto out_delete; 397 goto out_delete;
476 } 398 }
477 399
@@ -479,11 +401,11 @@ static int __cmd_annotate(void)
479 perf_session__fprintf(session, stdout); 401 perf_session__fprintf(session, stdout);
480 402
481 if (verbose > 2) 403 if (verbose > 2)
482 dsos__fprintf(stdout); 404 perf_session__fprintf_dsos(session, stdout);
483 405
484 perf_session__collapse_resort(session); 406 hists__collapse_resort(&session->hists);
485 perf_session__output_resort(session, session->event_total[0]); 407 hists__output_resort(&session->hists);
486 perf_session__find_annotations(session); 408 hists__find_annotations(&session->hists);
487out_delete: 409out_delete:
488 perf_session__delete(session); 410 perf_session__delete(session);
489 411
@@ -498,13 +420,17 @@ static const char * const annotate_usage[] = {
498static const struct option options[] = { 420static const struct option options[] = {
499 OPT_STRING('i', "input", &input_name, "file", 421 OPT_STRING('i', "input", &input_name, "file",
500 "input file name"), 422 "input file name"),
423 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
424 "only consider symbols in these dsos"),
501 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", 425 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
502 "symbol to annotate"), 426 "symbol to annotate"),
503 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 427 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
504 OPT_BOOLEAN('v', "verbose", &verbose, 428 OPT_INCR('v', "verbose", &verbose,
505 "be more verbose (show symbol address, etc)"), 429 "be more verbose (show symbol address, etc)"),
506 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 430 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
507 "dump raw trace in ASCII"), 431 "dump raw trace in ASCII"),
432 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
433 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
508 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 434 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
509 "file", "vmlinux pathname"), 435 "file", "vmlinux pathname"),
510 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 436 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
@@ -520,6 +446,13 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
520{ 446{
521 argc = parse_options(argc, argv, options, annotate_usage, 0); 447 argc = parse_options(argc, argv, options, annotate_usage, 0);
522 448
449 if (use_stdio)
450 use_browser = 0;
451 else if (use_tui)
452 use_browser = 1;
453
454 setup_browser();
455
523 symbol_conf.priv_size = sizeof(struct sym_priv); 456 symbol_conf.priv_size = sizeof(struct sym_priv);
524 symbol_conf.try_vmlinux_path = true; 457 symbol_conf.try_vmlinux_path = true;
525 458
@@ -539,12 +472,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
539 sym_hist_filter = argv[0]; 472 sym_hist_filter = argv[0];
540 } 473 }
541 474
542 setup_pager();
543
544 if (field_sep && *field_sep == '.') { 475 if (field_sep && *field_sep == '.') {
545 fputs("'.' is the only non valid --field-separator argument\n", 476 pr_err("'.' is the only non valid --field-separator argument\n");
546 stderr); 477 return -1;
547 exit(129);
548 } 478 }
549 479
550 return __cmd_annotate(); 480 return __cmd_annotate();
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index 46996774e559..fcb96269852a 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -95,7 +95,7 @@ static void dump_suites(int subsys_index)
95 return; 95 return;
96} 96}
97 97
98static char *bench_format_str; 98static const char *bench_format_str;
99int bench_format = BENCH_FORMAT_DEFAULT; 99int bench_format = BENCH_FORMAT_DEFAULT;
100 100
101static const struct option bench_options[] = { 101static const struct option bench_options[] = {
@@ -126,7 +126,7 @@ static void print_usage(void)
126 printf("\n"); 126 printf("\n");
127} 127}
128 128
129static int bench_str2int(char *str) 129static int bench_str2int(const char *str)
130{ 130{
131 if (!str) 131 if (!str)
132 return BENCH_FORMAT_DEFAULT; 132 return BENCH_FORMAT_DEFAULT;
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
new file mode 100644
index 000000000000..29ad20e67919
--- /dev/null
+++ b/tools/perf/builtin-buildid-cache.c
@@ -0,0 +1,132 @@
1/*
2 * builtin-buildid-cache.c
3 *
4 * Builtin buildid-cache command: Manages build-id cache
5 *
6 * Copyright (C) 2010, Red Hat Inc.
7 * Copyright (C) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "builtin.h"
10#include "perf.h"
11#include "util/cache.h"
12#include "util/debug.h"
13#include "util/header.h"
14#include "util/parse-options.h"
15#include "util/strlist.h"
16#include "util/symbol.h"
17
18static char const *add_name_list_str, *remove_name_list_str;
19
20static const char * const buildid_cache_usage[] = {
21 "perf buildid-cache [<options>]",
22 NULL
23};
24
25static const struct option buildid_cache_options[] = {
26 OPT_STRING('a', "add", &add_name_list_str,
27 "file list", "file(s) to add"),
28 OPT_STRING('r', "remove", &remove_name_list_str, "file list",
29 "file(s) to remove"),
30 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
31 OPT_END()
32};
33
34static int build_id_cache__add_file(const char *filename, const char *debugdir)
35{
36 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
37 u8 build_id[BUILD_ID_SIZE];
38 int err;
39
40 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
41 pr_debug("Couldn't read a build-id in %s\n", filename);
42 return -1;
43 }
44
45 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
46 err = build_id_cache__add_s(sbuild_id, debugdir, filename, false);
47 if (verbose)
48 pr_info("Adding %s %s: %s\n", sbuild_id, filename,
49 err ? "FAIL" : "Ok");
50 return err;
51}
52
53static int build_id_cache__remove_file(const char *filename __used,
54 const char *debugdir __used)
55{
56 u8 build_id[BUILD_ID_SIZE];
57 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
58
59 int err;
60
61 if (filename__read_build_id(filename, &build_id, sizeof(build_id)) < 0) {
62 pr_debug("Couldn't read a build-id in %s\n", filename);
63 return -1;
64 }
65
66 build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
67 err = build_id_cache__remove_s(sbuild_id, debugdir);
68 if (verbose)
69 pr_info("Removing %s %s: %s\n", sbuild_id, filename,
70 err ? "FAIL" : "Ok");
71
72 return err;
73}
74
75static int __cmd_buildid_cache(void)
76{
77 struct strlist *list;
78 struct str_node *pos;
79 char debugdir[PATH_MAX];
80
81 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
82
83 if (add_name_list_str) {
84 list = strlist__new(true, add_name_list_str);
85 if (list) {
86 strlist__for_each(pos, list)
87 if (build_id_cache__add_file(pos->s, debugdir)) {
88 if (errno == EEXIST) {
89 pr_debug("%s already in the cache\n",
90 pos->s);
91 continue;
92 }
93 pr_warning("Couldn't add %s: %s\n",
94 pos->s, strerror(errno));
95 }
96
97 strlist__delete(list);
98 }
99 }
100
101 if (remove_name_list_str) {
102 list = strlist__new(true, remove_name_list_str);
103 if (list) {
104 strlist__for_each(pos, list)
105 if (build_id_cache__remove_file(pos->s, debugdir)) {
106 if (errno == ENOENT) {
107 pr_debug("%s wasn't in the cache\n",
108 pos->s);
109 continue;
110 }
111 pr_warning("Couldn't remove %s: %s\n",
112 pos->s, strerror(errno));
113 }
114
115 strlist__delete(list);
116 }
117 }
118
119 return 0;
120}
121
122int cmd_buildid_cache(int argc, const char **argv, const char *prefix __used)
123{
124 argc = parse_options(argc, argv, buildid_cache_options,
125 buildid_cache_usage, 0);
126
127 if (symbol__init() < 0)
128 return -1;
129
130 setup_pager();
131 return __cmd_buildid_cache();
132}
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 1e99ac806913..5af32ae9031e 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -8,6 +8,7 @@
8 */ 8 */
9#include "builtin.h" 9#include "builtin.h"
10#include "perf.h" 10#include "perf.h"
11#include "util/build-id.h"
11#include "util/cache.h" 12#include "util/cache.h"
12#include "util/debug.h" 13#include "util/debug.h"
13#include "util/parse-options.h" 14#include "util/parse-options.h"
@@ -15,7 +16,8 @@
15#include "util/symbol.h" 16#include "util/symbol.h"
16 17
17static char const *input_name = "perf.data"; 18static char const *input_name = "perf.data";
18static int force; 19static bool force;
20static bool with_hits;
19 21
20static const char * const buildid_list_usage[] = { 22static const char * const buildid_list_usage[] = {
21 "perf buildid-list [<options>]", 23 "perf buildid-list [<options>]",
@@ -23,50 +25,31 @@ static const char * const buildid_list_usage[] = {
23}; 25};
24 26
25static const struct option options[] = { 27static const struct option options[] = {
28 OPT_BOOLEAN('H', "with-hits", &with_hits, "Show only DSOs with hits"),
26 OPT_STRING('i', "input", &input_name, "file", 29 OPT_STRING('i', "input", &input_name, "file",
27 "input file name"), 30 "input file name"),
28 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 31 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
29 OPT_BOOLEAN('v', "verbose", &verbose, 32 OPT_INCR('v', "verbose", &verbose,
30 "be more verbose"), 33 "be more verbose"),
31 OPT_END() 34 OPT_END()
32}; 35};
33 36
34static int perf_file_section__process_buildids(struct perf_file_section *self,
35 int feat, int fd)
36{
37 if (feat != HEADER_BUILD_ID)
38 return 0;
39
40 if (lseek(fd, self->offset, SEEK_SET) < 0) {
41 pr_warning("Failed to lseek to %Ld offset for buildids!\n",
42 self->offset);
43 return -1;
44 }
45
46 if (perf_header__read_build_ids(fd, self->offset, self->size)) {
47 pr_warning("Failed to read buildids!\n");
48 return -1;
49 }
50
51 return 0;
52}
53
54static int __cmd_buildid_list(void) 37static int __cmd_buildid_list(void)
55{ 38{
56 int err = -1;
57 struct perf_session *session; 39 struct perf_session *session;
58 40
59 session = perf_session__new(input_name, O_RDONLY, force); 41 session = perf_session__new(input_name, O_RDONLY, force, false,
42 &build_id__mark_dso_hit_ops);
60 if (session == NULL) 43 if (session == NULL)
61 return -1; 44 return -1;
62 45
63 err = perf_header__process_sections(&session->header, session->fd, 46 if (with_hits)
64 perf_file_section__process_buildids); 47 perf_session__process_events(session, &build_id__mark_dso_hit_ops);
65 if (err >= 0) 48
66 dsos__fprintf_buildid(stdout); 49 perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
67 50
68 perf_session__delete(session); 51 perf_session__delete(session);
69 return err; 52 return 0;
70} 53}
71 54
72int cmd_buildid_list(int argc, const char **argv, const char *prefix __used) 55int cmd_buildid_list(int argc, const char **argv, const char *prefix __used)
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index bd71b8ceafb7..3153e492dbcc 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -19,59 +19,50 @@
19static char const *input_old = "perf.data.old", 19static char const *input_old = "perf.data.old",
20 *input_new = "perf.data"; 20 *input_new = "perf.data";
21static char diff__default_sort_order[] = "dso,symbol"; 21static char diff__default_sort_order[] = "dso,symbol";
22static int force; 22static bool force;
23static bool show_displacement; 23static bool show_displacement;
24 24
25static int perf_session__add_hist_entry(struct perf_session *self, 25static int hists__add_entry(struct hists *self,
26 struct addr_location *al, u64 count) 26 struct addr_location *al, u64 period)
27{ 27{
28 bool hit; 28 if (__hists__add_entry(self, al, NULL, period) != NULL)
29 struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, 29 return 0;
30 count, &hit); 30 return -ENOMEM;
31 if (he == NULL)
32 return -ENOMEM;
33
34 if (hit)
35 he->count += count;
36
37 return 0;
38} 31}
39 32
40static int diff__process_sample_event(event_t *event, struct perf_session *session) 33static int diff__process_sample_event(event_t *event,
34 struct sample_data *sample,
35 struct perf_session *session)
41{ 36{
42 struct addr_location al; 37 struct addr_location al;
43 struct sample_data data = { .period = 1, };
44
45 dump_printf("(IP, %d): %d: %p\n", event->header.misc,
46 event->ip.pid, (void *)(long)event->ip.ip);
47 38
48 if (event__preprocess_sample(event, session, &al, NULL) < 0) { 39 if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
49 pr_warning("problem processing %d event, skipping it.\n", 40 pr_warning("problem processing %d event, skipping it.\n",
50 event->header.type); 41 event->header.type);
51 return -1; 42 return -1;
52 } 43 }
53 44
54 if (al.filtered) 45 if (al.filtered || al.sym == NULL)
55 return 0; 46 return 0;
56 47
57 event__parse_sample(event, session->sample_type, &data); 48 if (hists__add_entry(&session->hists, &al, sample->period)) {
58 49 pr_warning("problem incrementing symbol period, skipping event\n");
59 if (al.sym && perf_session__add_hist_entry(session, &al, data.period)) {
60 pr_warning("problem incrementing symbol count, skipping event\n");
61 return -1; 50 return -1;
62 } 51 }
63 52
64 session->events_stats.total += data.period; 53 session->hists.stats.total_period += sample->period;
65 return 0; 54 return 0;
66} 55}
67 56
68static struct perf_event_ops event_ops = { 57static struct perf_event_ops event_ops = {
69 .process_sample_event = diff__process_sample_event, 58 .sample = diff__process_sample_event,
70 .process_mmap_event = event__process_mmap, 59 .mmap = event__process_mmap,
71 .process_comm_event = event__process_comm, 60 .comm = event__process_comm,
72 .process_exit_event = event__process_task, 61 .exit = event__process_task,
73 .process_fork_event = event__process_task, 62 .fork = event__process_task,
74 .process_lost_event = event__process_lost, 63 .lost = event__process_lost,
64 .ordered_samples = true,
65 .ordering_requires_timestamps = true,
75}; 66};
76 67
77static void perf_session__insert_hist_entry_by_name(struct rb_root *root, 68static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -82,84 +73,69 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
82 struct hist_entry *iter; 73 struct hist_entry *iter;
83 74
84 while (*p != NULL) { 75 while (*p != NULL) {
85 int cmp;
86 parent = *p; 76 parent = *p;
87 iter = rb_entry(parent, struct hist_entry, rb_node); 77 iter = rb_entry(parent, struct hist_entry, rb_node);
88 78 if (hist_entry__cmp(he, iter) < 0)
89 cmp = strcmp(he->map->dso->name, iter->map->dso->name);
90 if (cmp > 0)
91 p = &(*p)->rb_left; 79 p = &(*p)->rb_left;
92 else if (cmp < 0) 80 else
93 p = &(*p)->rb_right; 81 p = &(*p)->rb_right;
94 else {
95 cmp = strcmp(he->sym->name, iter->sym->name);
96 if (cmp > 0)
97 p = &(*p)->rb_left;
98 else
99 p = &(*p)->rb_right;
100 }
101 } 82 }
102 83
103 rb_link_node(&he->rb_node, parent, p); 84 rb_link_node(&he->rb_node, parent, p);
104 rb_insert_color(&he->rb_node, root); 85 rb_insert_color(&he->rb_node, root);
105} 86}
106 87
107static void perf_session__resort_by_name(struct perf_session *self) 88static void hists__resort_entries(struct hists *self)
108{ 89{
109 unsigned long position = 1; 90 unsigned long position = 1;
110 struct rb_root tmp = RB_ROOT; 91 struct rb_root tmp = RB_ROOT;
111 struct rb_node *next = rb_first(&self->hists); 92 struct rb_node *next = rb_first(&self->entries);
112 93
113 while (next != NULL) { 94 while (next != NULL) {
114 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); 95 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
115 96
116 next = rb_next(&n->rb_node); 97 next = rb_next(&n->rb_node);
117 rb_erase(&n->rb_node, &self->hists); 98 rb_erase(&n->rb_node, &self->entries);
118 n->position = position++; 99 n->position = position++;
119 perf_session__insert_hist_entry_by_name(&tmp, n); 100 perf_session__insert_hist_entry_by_name(&tmp, n);
120 } 101 }
121 102
122 self->hists = tmp; 103 self->entries = tmp;
104}
105
106static void hists__set_positions(struct hists *self)
107{
108 hists__output_resort(self);
109 hists__resort_entries(self);
123} 110}
124 111
125static struct hist_entry * 112static struct hist_entry *hists__find_entry(struct hists *self,
126perf_session__find_hist_entry_by_name(struct perf_session *self, 113 struct hist_entry *he)
127 struct hist_entry *he)
128{ 114{
129 struct rb_node *n = self->hists.rb_node; 115 struct rb_node *n = self->entries.rb_node;
130 116
131 while (n) { 117 while (n) {
132 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 118 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
133 int cmp = strcmp(he->map->dso->name, iter->map->dso->name); 119 int64_t cmp = hist_entry__cmp(he, iter);
134 120
135 if (cmp > 0) 121 if (cmp < 0)
136 n = n->rb_left; 122 n = n->rb_left;
137 else if (cmp < 0) 123 else if (cmp > 0)
138 n = n->rb_right; 124 n = n->rb_right;
139 else { 125 else
140 cmp = strcmp(he->sym->name, iter->sym->name); 126 return iter;
141 if (cmp > 0)
142 n = n->rb_left;
143 else if (cmp < 0)
144 n = n->rb_right;
145 else
146 return iter;
147 }
148 } 127 }
149 128
150 return NULL; 129 return NULL;
151} 130}
152 131
153static void perf_session__match_hists(struct perf_session *old_session, 132static void hists__match(struct hists *older, struct hists *newer)
154 struct perf_session *new_session)
155{ 133{
156 struct rb_node *nd; 134 struct rb_node *nd;
157 135
158 perf_session__resort_by_name(old_session); 136 for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) {
159
160 for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
161 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node); 137 struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
162 pos->pair = perf_session__find_hist_entry_by_name(old_session, pos); 138 pos->pair = hists__find_entry(older, pos);
163 } 139 }
164} 140}
165 141
@@ -168,8 +144,8 @@ static int __cmd_diff(void)
168 int ret, i; 144 int ret, i;
169 struct perf_session *session[2]; 145 struct perf_session *session[2];
170 146
171 session[0] = perf_session__new(input_old, O_RDONLY, force); 147 session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops);
172 session[1] = perf_session__new(input_new, O_RDONLY, force); 148 session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops);
173 if (session[0] == NULL || session[1] == NULL) 149 if (session[0] == NULL || session[1] == NULL)
174 return -ENOMEM; 150 return -ENOMEM;
175 151
@@ -177,12 +153,15 @@ static int __cmd_diff(void)
177 ret = perf_session__process_events(session[i], &event_ops); 153 ret = perf_session__process_events(session[i], &event_ops);
178 if (ret) 154 if (ret)
179 goto out_delete; 155 goto out_delete;
180 perf_session__output_resort(session[i], session[i]->events_stats.total);
181 } 156 }
182 157
183 perf_session__match_hists(session[0], session[1]); 158 hists__output_resort(&session[1]->hists);
184 perf_session__fprintf_hists(session[1], session[0], 159 if (show_displacement)
185 show_displacement, stdout); 160 hists__set_positions(&session[0]->hists);
161
162 hists__match(&session[0]->hists, &session[1]->hists);
163 hists__fprintf(&session[1]->hists, &session[0]->hists,
164 show_displacement, stdout);
186out_delete: 165out_delete:
187 for (i = 0; i < 2; ++i) 166 for (i = 0; i < 2; ++i)
188 perf_session__delete(session[i]); 167 perf_session__delete(session[i]);
@@ -195,17 +174,15 @@ static const char * const diff_usage[] = {
195}; 174};
196 175
197static const struct option options[] = { 176static const struct option options[] = {
198 OPT_BOOLEAN('v', "verbose", &verbose, 177 OPT_INCR('v', "verbose", &verbose,
199 "be more verbose (show symbol address, etc)"), 178 "be more verbose (show symbol address, etc)"),
200 OPT_BOOLEAN('m', "displacement", &show_displacement, 179 OPT_BOOLEAN('M', "displacement", &show_displacement,
201 "Show position displacement relative to baseline"), 180 "Show position displacement relative to baseline"),
202 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 181 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
203 "dump raw trace in ASCII"), 182 "dump raw trace in ASCII"),
204 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 183 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
205 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 184 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
206 "load module symbols - WARNING: use only with -k and LIVE kernel"), 185 "load module symbols - WARNING: use only with -k and LIVE kernel"),
207 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths,
208 "Don't shorten the pathnames taking into account the cwd"),
209 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 186 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
210 "only consider symbols in these dsos"), 187 "only consider symbols in these dsos"),
211 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 188 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -217,6 +194,8 @@ static const struct option options[] = {
217 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 194 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
218 "separator for columns, no spaces will be added between " 195 "separator for columns, no spaces will be added between "
219 "columns '.' is reserved."), 196 "columns '.' is reserved."),
197 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
198 "Look for files with symbols relative to this directory"),
220 OPT_END() 199 OPT_END()
221}; 200};
222 201
@@ -232,6 +211,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix __used)
232 input_new = argv[1]; 211 input_new = argv[1];
233 } else 212 } else
234 input_new = argv[0]; 213 input_new = argv[0];
214 } else if (symbol_conf.default_guest_vmlinux_name ||
215 symbol_conf.default_guest_kallsyms) {
216 input_old = "perf.data.host";
217 input_new = "perf.data.guest";
235 } 218 }
236 219
237 symbol_conf.exclude_other = false; 220 symbol_conf.exclude_other = false;
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 9f810b17c25c..6d5a8a7faf48 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -29,14 +29,14 @@ enum help_format {
29 HELP_FORMAT_WEB, 29 HELP_FORMAT_WEB,
30}; 30};
31 31
32static int show_all = 0; 32static bool show_all = false;
33static enum help_format help_format = HELP_FORMAT_MAN; 33static enum help_format help_format = HELP_FORMAT_MAN;
34static struct option builtin_help_options[] = { 34static struct option builtin_help_options[] = {
35 OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), 35 OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
36 OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), 36 OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
37 OPT_SET_INT('w', "web", &help_format, "show manual in web browser", 37 OPT_SET_UINT('w', "web", &help_format, "show manual in web browser",
38 HELP_FORMAT_WEB), 38 HELP_FORMAT_WEB),
39 OPT_SET_INT('i', "info", &help_format, "show info page", 39 OPT_SET_UINT('i', "info", &help_format, "show info page",
40 HELP_FORMAT_INFO), 40 HELP_FORMAT_INFO),
41 OPT_END(), 41 OPT_END(),
42}; 42};
@@ -286,8 +286,7 @@ void list_common_cmds_help(void)
286 286
287 puts(" The most commonly used perf commands are:"); 287 puts(" The most commonly used perf commands are:");
288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { 288 for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
289 printf(" %s ", common_cmds[i].name); 289 printf(" %-*s ", longest, common_cmds[i].name);
290 mput_char(' ', longest - strlen(common_cmds[i].name));
291 puts(common_cmds[i].help); 290 puts(common_cmds[i].help);
292 } 291 }
293} 292}
@@ -314,8 +313,6 @@ static const char *cmd_to_page(const char *perf_cmd)
314 return "perf"; 313 return "perf";
315 else if (!prefixcmp(perf_cmd, "perf")) 314 else if (!prefixcmp(perf_cmd, "perf"))
316 return perf_cmd; 315 return perf_cmd;
317 else if (is_perf_command(perf_cmd))
318 return prepend("perf-", perf_cmd);
319 else 316 else
320 return prepend("perf-", perf_cmd); 317 return prepend("perf-", perf_cmd);
321} 318}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
new file mode 100644
index 000000000000..0c78ffa7bf67
--- /dev/null
+++ b/tools/perf/builtin-inject.c
@@ -0,0 +1,237 @@
1/*
2 * builtin-inject.c
3 *
4 * Builtin inject command: Examine the live mode (stdin) event stream
5 * and repipe it to stdout while optionally injecting additional
6 * events into it.
7 */
8#include "builtin.h"
9
10#include "perf.h"
11#include "util/session.h"
12#include "util/debug.h"
13
14#include "util/parse-options.h"
15
16static char const *input_name = "-";
17static bool inject_build_ids;
18
19static int event__repipe_synth(event_t *event,
20 struct perf_session *session __used)
21{
22 uint32_t size;
23 void *buf = event;
24
25 size = event->header.size;
26
27 while (size) {
28 int ret = write(STDOUT_FILENO, buf, size);
29 if (ret < 0)
30 return -errno;
31
32 size -= ret;
33 buf += ret;
34 }
35
36 return 0;
37}
38
39static int event__repipe(event_t *event, struct sample_data *sample __used,
40 struct perf_session *session)
41{
42 return event__repipe_synth(event, session);
43}
44
45static int event__repipe_mmap(event_t *self, struct sample_data *sample,
46 struct perf_session *session)
47{
48 int err;
49
50 err = event__process_mmap(self, sample, session);
51 event__repipe(self, sample, session);
52
53 return err;
54}
55
56static int event__repipe_task(event_t *self, struct sample_data *sample,
57 struct perf_session *session)
58{
59 int err;
60
61 err = event__process_task(self, sample, session);
62 event__repipe(self, sample, session);
63
64 return err;
65}
66
67static int event__repipe_tracing_data(event_t *self,
68 struct perf_session *session)
69{
70 int err;
71
72 event__repipe_synth(self, session);
73 err = event__process_tracing_data(self, session);
74
75 return err;
76}
77
78static int dso__read_build_id(struct dso *self)
79{
80 if (self->has_build_id)
81 return 0;
82
83 if (filename__read_build_id(self->long_name, self->build_id,
84 sizeof(self->build_id)) > 0) {
85 self->has_build_id = true;
86 return 0;
87 }
88
89 return -1;
90}
91
92static int dso__inject_build_id(struct dso *self, struct perf_session *session)
93{
94 u16 misc = PERF_RECORD_MISC_USER;
95 struct machine *machine;
96 int err;
97
98 if (dso__read_build_id(self) < 0) {
99 pr_debug("no build_id found for %s\n", self->long_name);
100 return -1;
101 }
102
103 machine = perf_session__find_host_machine(session);
104 if (machine == NULL) {
105 pr_err("Can't find machine for session\n");
106 return -1;
107 }
108
109 if (self->kernel)
110 misc = PERF_RECORD_MISC_KERNEL;
111
112 err = event__synthesize_build_id(self, misc, event__repipe,
113 machine, session);
114 if (err) {
115 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
116 return -1;
117 }
118
119 return 0;
120}
121
122static int event__inject_buildid(event_t *event, struct sample_data *sample,
123 struct perf_session *session)
124{
125 struct addr_location al;
126 struct thread *thread;
127 u8 cpumode;
128
129 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
130
131 thread = perf_session__findnew(session, event->ip.pid);
132 if (thread == NULL) {
133 pr_err("problem processing %d event, skipping it.\n",
134 event->header.type);
135 goto repipe;
136 }
137
138 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
139 event->ip.pid, event->ip.ip, &al);
140
141 if (al.map != NULL) {
142 if (!al.map->dso->hit) {
143 al.map->dso->hit = 1;
144 if (map__load(al.map, NULL) >= 0) {
145 dso__inject_build_id(al.map->dso, session);
146 /*
147 * If this fails, too bad, let the other side
148 * account this as unresolved.
149 */
150 } else
151 pr_warning("no symbols found in %s, maybe "
152 "install a debug package?\n",
153 al.map->dso->long_name);
154 }
155 }
156
157repipe:
158 event__repipe(event, sample, session);
159 return 0;
160}
161
162struct perf_event_ops inject_ops = {
163 .sample = event__repipe,
164 .mmap = event__repipe,
165 .comm = event__repipe,
166 .fork = event__repipe,
167 .exit = event__repipe,
168 .lost = event__repipe,
169 .read = event__repipe,
170 .throttle = event__repipe,
171 .unthrottle = event__repipe,
172 .attr = event__repipe_synth,
173 .event_type = event__repipe_synth,
174 .tracing_data = event__repipe_synth,
175 .build_id = event__repipe_synth,
176};
177
178extern volatile int session_done;
179
180static void sig_handler(int sig __attribute__((__unused__)))
181{
182 session_done = 1;
183}
184
185static int __cmd_inject(void)
186{
187 struct perf_session *session;
188 int ret = -EINVAL;
189
190 signal(SIGINT, sig_handler);
191
192 if (inject_build_ids) {
193 inject_ops.sample = event__inject_buildid;
194 inject_ops.mmap = event__repipe_mmap;
195 inject_ops.fork = event__repipe_task;
196 inject_ops.tracing_data = event__repipe_tracing_data;
197 }
198
199 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
200 if (session == NULL)
201 return -ENOMEM;
202
203 ret = perf_session__process_events(session, &inject_ops);
204
205 perf_session__delete(session);
206
207 return ret;
208}
209
210static const char * const report_usage[] = {
211 "perf inject [<options>]",
212 NULL
213};
214
215static const struct option options[] = {
216 OPT_BOOLEAN('b', "build-ids", &inject_build_ids,
217 "Inject build-ids into the output stream"),
218 OPT_INCR('v', "verbose", &verbose,
219 "be more verbose (show build ids, etc)"),
220 OPT_END()
221};
222
223int cmd_inject(int argc, const char **argv, const char *prefix __used)
224{
225 argc = parse_options(argc, argv, options, report_usage, 0);
226
227 /*
228 * Any (unrecognized) arguments left?
229 */
230 if (argc)
231 usage_with_options(report_usage, options);
232
233 if (symbol__init() < 0)
234 return -1;
235
236 return __cmd_inject();
237}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 93c67bf53d2c..def7ddc2fd4f 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -92,23 +92,18 @@ static void setup_cpunode_map(void)
92 if (!dir1) 92 if (!dir1)
93 return; 93 return;
94 94
95 while (true) { 95 while ((dent1 = readdir(dir1)) != NULL) {
96 dent1 = readdir(dir1); 96 if (dent1->d_type != DT_DIR ||
97 if (!dent1) 97 sscanf(dent1->d_name, "node%u", &mem) < 1)
98 break;
99
100 if (sscanf(dent1->d_name, "node%u", &mem) < 1)
101 continue; 98 continue;
102 99
103 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name); 100 snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
104 dir2 = opendir(buf); 101 dir2 = opendir(buf);
105 if (!dir2) 102 if (!dir2)
106 continue; 103 continue;
107 while (true) { 104 while ((dent2 = readdir(dir2)) != NULL) {
108 dent2 = readdir(dir2); 105 if (dent2->d_type != DT_LNK ||
109 if (!dent2) 106 sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
110 break;
111 if (sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
112 continue; 107 continue;
113 cpunode_map[cpu] = mem; 108 cpunode_map[cpu] = mem;
114 } 109 }
@@ -309,25 +304,11 @@ process_raw_event(event_t *raw_event __used, void *data,
309 } 304 }
310} 305}
311 306
312static int process_sample_event(event_t *event, struct perf_session *session) 307static int process_sample_event(event_t *event, struct sample_data *sample,
308 struct perf_session *session)
313{ 309{
314 struct sample_data data; 310 struct thread *thread = perf_session__findnew(session, event->ip.pid);
315 struct thread *thread;
316
317 memset(&data, 0, sizeof(data));
318 data.time = -1;
319 data.cpu = -1;
320 data.period = 1;
321
322 event__parse_sample(event, session->sample_type, &data);
323 311
324 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
325 event->header.misc,
326 data.pid, data.tid,
327 (void *)(long)data.ip,
328 (long long)data.period);
329
330 thread = perf_session__findnew(session, event->ip.pid);
331 if (thread == NULL) { 312 if (thread == NULL) {
332 pr_debug("problem processing %d event, skipping it.\n", 313 pr_debug("problem processing %d event, skipping it.\n",
333 event->header.type); 314 event->header.type);
@@ -336,28 +317,16 @@ static int process_sample_event(event_t *event, struct perf_session *session)
336 317
337 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 318 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
338 319
339 process_raw_event(event, data.raw_data, data.cpu, 320 process_raw_event(event, sample->raw_data, sample->cpu,
340 data.time, thread); 321 sample->time, thread);
341
342 return 0;
343}
344
345static int sample_type_check(struct perf_session *session)
346{
347 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
348 fprintf(stderr,
349 "No trace sample to read. Did you call perf record "
350 "without -R?");
351 return -1;
352 }
353 322
354 return 0; 323 return 0;
355} 324}
356 325
357static struct perf_event_ops event_ops = { 326static struct perf_event_ops event_ops = {
358 .process_sample_event = process_sample_event, 327 .sample = process_sample_event,
359 .process_comm_event = event__process_comm, 328 .comm = event__process_comm,
360 .sample_type_check = sample_type_check, 329 .ordered_samples = true,
361}; 330};
362 331
363static double fragmentation(unsigned long n_req, unsigned long n_alloc) 332static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -372,6 +341,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
372 int n_lines, int is_caller) 341 int n_lines, int is_caller)
373{ 342{
374 struct rb_node *next; 343 struct rb_node *next;
344 struct machine *machine;
375 345
376 printf("%.102s\n", graph_dotted_line); 346 printf("%.102s\n", graph_dotted_line);
377 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 347 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
@@ -380,23 +350,29 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
380 350
381 next = rb_first(root); 351 next = rb_first(root);
382 352
353 machine = perf_session__find_host_machine(session);
354 if (!machine) {
355 pr_err("__print_result: couldn't find kernel information\n");
356 return;
357 }
383 while (next && n_lines--) { 358 while (next && n_lines--) {
384 struct alloc_stat *data = rb_entry(next, struct alloc_stat, 359 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
385 node); 360 node);
386 struct symbol *sym = NULL; 361 struct symbol *sym = NULL;
362 struct map *map;
387 char buf[BUFSIZ]; 363 char buf[BUFSIZ];
388 u64 addr; 364 u64 addr;
389 365
390 if (is_caller) { 366 if (is_caller) {
391 addr = data->call_site; 367 addr = data->call_site;
392 if (!raw_ip) 368 if (!raw_ip)
393 sym = map_groups__find_function(&session->kmaps, session, addr, NULL); 369 sym = machine__find_kernel_function(machine, addr, &map, NULL);
394 } else 370 } else
395 addr = data->ptr; 371 addr = data->ptr;
396 372
397 if (sym != NULL) 373 if (sym != NULL)
398 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name, 374 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
399 addr - sym->start); 375 addr - map->unmap_ip(map, sym->start));
400 else 376 else
401 snprintf(buf, sizeof(buf), "%#Lx", addr); 377 snprintf(buf, sizeof(buf), "%#Lx", addr);
402 printf(" %-34s |", buf); 378 printf(" %-34s |", buf);
@@ -504,11 +480,18 @@ static void sort_result(void)
504 480
505static int __cmd_kmem(void) 481static int __cmd_kmem(void)
506{ 482{
507 int err; 483 int err = -EINVAL;
508 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 484 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
485 0, false, &event_ops);
509 if (session == NULL) 486 if (session == NULL)
510 return -ENOMEM; 487 return -ENOMEM;
511 488
489 if (perf_session__create_kernel_maps(session) < 0)
490 goto out_delete;
491
492 if (!perf_session__has_traces(session, "kmem record"))
493 goto out_delete;
494
512 setup_pager(); 495 setup_pager();
513 err = perf_session__process_events(session, &event_ops); 496 err = perf_session__process_events(session, &event_ops);
514 if (err != 0) 497 if (err != 0)
@@ -736,7 +719,6 @@ static const char *record_args[] = {
736 "record", 719 "record",
737 "-a", 720 "-a",
738 "-R", 721 "-R",
739 "-M",
740 "-f", 722 "-f",
741 "-c", "1", 723 "-c", "1",
742 "-e", "kmem:kmalloc", 724 "-e", "kmem:kmalloc",
@@ -755,6 +737,9 @@ static int __cmd_record(int argc, const char **argv)
755 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 737 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
756 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 738 rec_argv = calloc(rec_argc + 1, sizeof(char *));
757 739
740 if (rec_argv == NULL)
741 return -ENOMEM;
742
758 for (i = 0; i < ARRAY_SIZE(record_args); i++) 743 for (i = 0; i < ARRAY_SIZE(record_args); i++)
759 rec_argv[i] = strdup(record_args[i]); 744 rec_argv[i] = strdup(record_args[i]);
760 745
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
new file mode 100644
index 000000000000..34d1e853829d
--- /dev/null
+++ b/tools/perf/builtin-kvm.c
@@ -0,0 +1,144 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9#include "util/session.h"
10
11#include "util/parse-options.h"
12#include "util/trace-event.h"
13
14#include "util/debug.h"
15
16#include <sys/prctl.h>
17
18#include <semaphore.h>
19#include <pthread.h>
20#include <math.h>
21
22static const char *file_name;
23static char name_buffer[256];
24
25bool perf_host = 1;
26bool perf_guest;
27
28static const char * const kvm_usage[] = {
29 "perf kvm [<options>] {top|record|report|diff|buildid-list}",
30 NULL
31};
32
33static const struct option kvm_options[] = {
34 OPT_STRING('i', "input", &file_name, "file",
35 "Input file name"),
36 OPT_STRING('o', "output", &file_name, "file",
37 "Output file name"),
38 OPT_BOOLEAN(0, "guest", &perf_guest,
39 "Collect guest os data"),
40 OPT_BOOLEAN(0, "host", &perf_host,
41 "Collect guest os data"),
42 OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
43 "guest mount directory under which every guest os"
44 " instance has a subdir"),
45 OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name,
46 "file", "file saving guest os vmlinux"),
47 OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,
48 "file", "file saving guest os /proc/kallsyms"),
49 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
50 "file", "file saving guest os /proc/modules"),
51 OPT_END()
52};
53
54static int __cmd_record(int argc, const char **argv)
55{
56 int rec_argc, i = 0, j;
57 const char **rec_argv;
58
59 rec_argc = argc + 2;
60 rec_argv = calloc(rec_argc + 1, sizeof(char *));
61 rec_argv[i++] = strdup("record");
62 rec_argv[i++] = strdup("-o");
63 rec_argv[i++] = strdup(file_name);
64 for (j = 1; j < argc; j++, i++)
65 rec_argv[i] = argv[j];
66
67 BUG_ON(i != rec_argc);
68
69 return cmd_record(i, rec_argv, NULL);
70}
71
72static int __cmd_report(int argc, const char **argv)
73{
74 int rec_argc, i = 0, j;
75 const char **rec_argv;
76
77 rec_argc = argc + 2;
78 rec_argv = calloc(rec_argc + 1, sizeof(char *));
79 rec_argv[i++] = strdup("report");
80 rec_argv[i++] = strdup("-i");
81 rec_argv[i++] = strdup(file_name);
82 for (j = 1; j < argc; j++, i++)
83 rec_argv[i] = argv[j];
84
85 BUG_ON(i != rec_argc);
86
87 return cmd_report(i, rec_argv, NULL);
88}
89
90static int __cmd_buildid_list(int argc, const char **argv)
91{
92 int rec_argc, i = 0, j;
93 const char **rec_argv;
94
95 rec_argc = argc + 2;
96 rec_argv = calloc(rec_argc + 1, sizeof(char *));
97 rec_argv[i++] = strdup("buildid-list");
98 rec_argv[i++] = strdup("-i");
99 rec_argv[i++] = strdup(file_name);
100 for (j = 1; j < argc; j++, i++)
101 rec_argv[i] = argv[j];
102
103 BUG_ON(i != rec_argc);
104
105 return cmd_buildid_list(i, rec_argv, NULL);
106}
107
108int cmd_kvm(int argc, const char **argv, const char *prefix __used)
109{
110 perf_host = perf_guest = 0;
111
112 argc = parse_options(argc, argv, kvm_options, kvm_usage,
113 PARSE_OPT_STOP_AT_NON_OPTION);
114 if (!argc)
115 usage_with_options(kvm_usage, kvm_options);
116
117 if (!perf_host)
118 perf_guest = 1;
119
120 if (!file_name) {
121 if (perf_host && !perf_guest)
122 sprintf(name_buffer, "perf.data.host");
123 else if (!perf_host && perf_guest)
124 sprintf(name_buffer, "perf.data.guest");
125 else
126 sprintf(name_buffer, "perf.data.kvm");
127 file_name = name_buffer;
128 }
129
130 if (!strncmp(argv[0], "rec", 3))
131 return __cmd_record(argc, argv);
132 else if (!strncmp(argv[0], "rep", 3))
133 return __cmd_report(argc, argv);
134 else if (!strncmp(argv[0], "diff", 4))
135 return cmd_diff(argc, argv, NULL);
136 else if (!strncmp(argv[0], "top", 3))
137 return cmd_top(argc, argv, NULL);
138 else if (!strncmp(argv[0], "buildid-list", 12))
139 return __cmd_buildid_list(argc, argv);
140 else
141 usage_with_options(kvm_usage, kvm_options);
142
143 return 0;
144}
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
new file mode 100644
index 000000000000..b9c6e5432971
--- /dev/null
+++ b/tools/perf/builtin-lock.c
@@ -0,0 +1,1004 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9
10#include "util/parse-options.h"
11#include "util/trace-event.h"
12
13#include "util/debug.h"
14#include "util/session.h"
15
16#include <sys/types.h>
17#include <sys/prctl.h>
18#include <semaphore.h>
19#include <pthread.h>
20#include <math.h>
21#include <limits.h>
22
23#include <linux/list.h>
24#include <linux/hash.h>
25
26static struct perf_session *session;
27
28/* based on kernel/lockdep.c */
29#define LOCKHASH_BITS 12
30#define LOCKHASH_SIZE (1UL << LOCKHASH_BITS)
31
32static struct list_head lockhash_table[LOCKHASH_SIZE];
33
34#define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS)
35#define lockhashentry(key) (lockhash_table + __lockhashfn((key)))
36
37struct lock_stat {
38 struct list_head hash_entry;
39 struct rb_node rb; /* used for sorting */
40
41 /*
42 * FIXME: raw_field_value() returns unsigned long long,
43 * so address of lockdep_map should be dealed as 64bit.
44 * Is there more better solution?
45 */
46 void *addr; /* address of lockdep_map, used as ID */
47 char *name; /* for strcpy(), we cannot use const */
48
49 unsigned int nr_acquire;
50 unsigned int nr_acquired;
51 unsigned int nr_contended;
52 unsigned int nr_release;
53
54 unsigned int nr_readlock;
55 unsigned int nr_trylock;
56 /* these times are in nano sec. */
57 u64 wait_time_total;
58 u64 wait_time_min;
59 u64 wait_time_max;
60
61 int discard; /* flag of blacklist */
62};
63
64/*
65 * States of lock_seq_stat
66 *
67 * UNINITIALIZED is required for detecting first event of acquire.
68 * As the nature of lock events, there is no guarantee
69 * that the first event for the locks are acquire,
70 * it can be acquired, contended or release.
71 */
72#define SEQ_STATE_UNINITIALIZED 0 /* initial state */
73#define SEQ_STATE_RELEASED 1
74#define SEQ_STATE_ACQUIRING 2
75#define SEQ_STATE_ACQUIRED 3
76#define SEQ_STATE_READ_ACQUIRED 4
77#define SEQ_STATE_CONTENDED 5
78
79/*
80 * MAX_LOCK_DEPTH
81 * Imported from include/linux/sched.h.
82 * Should this be synchronized?
83 */
84#define MAX_LOCK_DEPTH 48
85
86/*
87 * struct lock_seq_stat:
88 * Place to put on state of one lock sequence
89 * 1) acquire -> acquired -> release
90 * 2) acquire -> contended -> acquired -> release
91 * 3) acquire (with read or try) -> release
92 * 4) Are there other patterns?
93 */
94struct lock_seq_stat {
95 struct list_head list;
96 int state;
97 u64 prev_event_time;
98 void *addr;
99
100 int read_count;
101};
102
103struct thread_stat {
104 struct rb_node rb;
105
106 u32 tid;
107 struct list_head seq_list;
108};
109
110static struct rb_root thread_stats;
111
112static struct thread_stat *thread_stat_find(u32 tid)
113{
114 struct rb_node *node;
115 struct thread_stat *st;
116
117 node = thread_stats.rb_node;
118 while (node) {
119 st = container_of(node, struct thread_stat, rb);
120 if (st->tid == tid)
121 return st;
122 else if (tid < st->tid)
123 node = node->rb_left;
124 else
125 node = node->rb_right;
126 }
127
128 return NULL;
129}
130
131static void thread_stat_insert(struct thread_stat *new)
132{
133 struct rb_node **rb = &thread_stats.rb_node;
134 struct rb_node *parent = NULL;
135 struct thread_stat *p;
136
137 while (*rb) {
138 p = container_of(*rb, struct thread_stat, rb);
139 parent = *rb;
140
141 if (new->tid < p->tid)
142 rb = &(*rb)->rb_left;
143 else if (new->tid > p->tid)
144 rb = &(*rb)->rb_right;
145 else
146 BUG_ON("inserting invalid thread_stat\n");
147 }
148
149 rb_link_node(&new->rb, parent, rb);
150 rb_insert_color(&new->rb, &thread_stats);
151}
152
153static struct thread_stat *thread_stat_findnew_after_first(u32 tid)
154{
155 struct thread_stat *st;
156
157 st = thread_stat_find(tid);
158 if (st)
159 return st;
160
161 st = zalloc(sizeof(struct thread_stat));
162 if (!st)
163 die("memory allocation failed\n");
164
165 st->tid = tid;
166 INIT_LIST_HEAD(&st->seq_list);
167
168 thread_stat_insert(st);
169
170 return st;
171}
172
173static struct thread_stat *thread_stat_findnew_first(u32 tid);
174static struct thread_stat *(*thread_stat_findnew)(u32 tid) =
175 thread_stat_findnew_first;
176
177static struct thread_stat *thread_stat_findnew_first(u32 tid)
178{
179 struct thread_stat *st;
180
181 st = zalloc(sizeof(struct thread_stat));
182 if (!st)
183 die("memory allocation failed\n");
184 st->tid = tid;
185 INIT_LIST_HEAD(&st->seq_list);
186
187 rb_link_node(&st->rb, NULL, &thread_stats.rb_node);
188 rb_insert_color(&st->rb, &thread_stats);
189
190 thread_stat_findnew = thread_stat_findnew_after_first;
191 return st;
192}
193
194/* build simple key function one is bigger than two */
195#define SINGLE_KEY(member) \
196 static int lock_stat_key_ ## member(struct lock_stat *one, \
197 struct lock_stat *two) \
198 { \
199 return one->member > two->member; \
200 }
201
202SINGLE_KEY(nr_acquired)
203SINGLE_KEY(nr_contended)
204SINGLE_KEY(wait_time_total)
205SINGLE_KEY(wait_time_min)
206SINGLE_KEY(wait_time_max)
207
208struct lock_key {
209 /*
210 * name: the value for specify by user
211 * this should be simpler than raw name of member
212 * e.g. nr_acquired -> acquired, wait_time_total -> wait_total
213 */
214 const char *name;
215 int (*key)(struct lock_stat*, struct lock_stat*);
216};
217
218static const char *sort_key = "acquired";
219
220static int (*compare)(struct lock_stat *, struct lock_stat *);
221
222static struct rb_root result; /* place to store sorted data */
223
224#define DEF_KEY_LOCK(name, fn_suffix) \
225 { #name, lock_stat_key_ ## fn_suffix }
226struct lock_key keys[] = {
227 DEF_KEY_LOCK(acquired, nr_acquired),
228 DEF_KEY_LOCK(contended, nr_contended),
229 DEF_KEY_LOCK(wait_total, wait_time_total),
230 DEF_KEY_LOCK(wait_min, wait_time_min),
231 DEF_KEY_LOCK(wait_max, wait_time_max),
232
233 /* extra comparisons much complicated should be here */
234
235 { NULL, NULL }
236};
237
238static void select_key(void)
239{
240 int i;
241
242 for (i = 0; keys[i].name; i++) {
243 if (!strcmp(keys[i].name, sort_key)) {
244 compare = keys[i].key;
245 return;
246 }
247 }
248
249 die("Unknown compare key:%s\n", sort_key);
250}
251
252static void insert_to_result(struct lock_stat *st,
253 int (*bigger)(struct lock_stat *, struct lock_stat *))
254{
255 struct rb_node **rb = &result.rb_node;
256 struct rb_node *parent = NULL;
257 struct lock_stat *p;
258
259 while (*rb) {
260 p = container_of(*rb, struct lock_stat, rb);
261 parent = *rb;
262
263 if (bigger(st, p))
264 rb = &(*rb)->rb_left;
265 else
266 rb = &(*rb)->rb_right;
267 }
268
269 rb_link_node(&st->rb, parent, rb);
270 rb_insert_color(&st->rb, &result);
271}
272
273/* returns left most element of result, and erase it */
274static struct lock_stat *pop_from_result(void)
275{
276 struct rb_node *node = result.rb_node;
277
278 if (!node)
279 return NULL;
280
281 while (node->rb_left)
282 node = node->rb_left;
283
284 rb_erase(node, &result);
285 return container_of(node, struct lock_stat, rb);
286}
287
288static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
289{
290 struct list_head *entry = lockhashentry(addr);
291 struct lock_stat *ret, *new;
292
293 list_for_each_entry(ret, entry, hash_entry) {
294 if (ret->addr == addr)
295 return ret;
296 }
297
298 new = zalloc(sizeof(struct lock_stat));
299 if (!new)
300 goto alloc_failed;
301
302 new->addr = addr;
303 new->name = zalloc(sizeof(char) * strlen(name) + 1);
304 if (!new->name)
305 goto alloc_failed;
306 strcpy(new->name, name);
307
308 new->wait_time_min = ULLONG_MAX;
309
310 list_add(&new->hash_entry, entry);
311 return new;
312
313alloc_failed:
314 die("memory allocation failed\n");
315}
316
317static char const *input_name = "perf.data";
318
319struct raw_event_sample {
320 u32 size;
321 char data[0];
322};
323
324struct trace_acquire_event {
325 void *addr;
326 const char *name;
327 int flag;
328};
329
330struct trace_acquired_event {
331 void *addr;
332 const char *name;
333};
334
335struct trace_contended_event {
336 void *addr;
337 const char *name;
338};
339
340struct trace_release_event {
341 void *addr;
342 const char *name;
343};
344
345struct trace_lock_handler {
346 void (*acquire_event)(struct trace_acquire_event *,
347 struct event *,
348 int cpu,
349 u64 timestamp,
350 struct thread *thread);
351
352 void (*acquired_event)(struct trace_acquired_event *,
353 struct event *,
354 int cpu,
355 u64 timestamp,
356 struct thread *thread);
357
358 void (*contended_event)(struct trace_contended_event *,
359 struct event *,
360 int cpu,
361 u64 timestamp,
362 struct thread *thread);
363
364 void (*release_event)(struct trace_release_event *,
365 struct event *,
366 int cpu,
367 u64 timestamp,
368 struct thread *thread);
369};
370
371static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
372{
373 struct lock_seq_stat *seq;
374
375 list_for_each_entry(seq, &ts->seq_list, list) {
376 if (seq->addr == addr)
377 return seq;
378 }
379
380 seq = zalloc(sizeof(struct lock_seq_stat));
381 if (!seq)
382 die("Not enough memory\n");
383 seq->state = SEQ_STATE_UNINITIALIZED;
384 seq->addr = addr;
385
386 list_add(&seq->list, &ts->seq_list);
387 return seq;
388}
389
390enum broken_state {
391 BROKEN_ACQUIRE,
392 BROKEN_ACQUIRED,
393 BROKEN_CONTENDED,
394 BROKEN_RELEASE,
395 BROKEN_MAX,
396};
397
398static int bad_hist[BROKEN_MAX];
399
400enum acquire_flags {
401 TRY_LOCK = 1,
402 READ_LOCK = 2,
403};
404
405static void
406report_lock_acquire_event(struct trace_acquire_event *acquire_event,
407 struct event *__event __used,
408 int cpu __used,
409 u64 timestamp __used,
410 struct thread *thread __used)
411{
412 struct lock_stat *ls;
413 struct thread_stat *ts;
414 struct lock_seq_stat *seq;
415
416 ls = lock_stat_findnew(acquire_event->addr, acquire_event->name);
417 if (ls->discard)
418 return;
419
420 ts = thread_stat_findnew(thread->pid);
421 seq = get_seq(ts, acquire_event->addr);
422
423 switch (seq->state) {
424 case SEQ_STATE_UNINITIALIZED:
425 case SEQ_STATE_RELEASED:
426 if (!acquire_event->flag) {
427 seq->state = SEQ_STATE_ACQUIRING;
428 } else {
429 if (acquire_event->flag & TRY_LOCK)
430 ls->nr_trylock++;
431 if (acquire_event->flag & READ_LOCK)
432 ls->nr_readlock++;
433 seq->state = SEQ_STATE_READ_ACQUIRED;
434 seq->read_count = 1;
435 ls->nr_acquired++;
436 }
437 break;
438 case SEQ_STATE_READ_ACQUIRED:
439 if (acquire_event->flag & READ_LOCK) {
440 seq->read_count++;
441 ls->nr_acquired++;
442 goto end;
443 } else {
444 goto broken;
445 }
446 break;
447 case SEQ_STATE_ACQUIRED:
448 case SEQ_STATE_ACQUIRING:
449 case SEQ_STATE_CONTENDED:
450broken:
451 /* broken lock sequence, discard it */
452 ls->discard = 1;
453 bad_hist[BROKEN_ACQUIRE]++;
454 list_del(&seq->list);
455 free(seq);
456 goto end;
457 break;
458 default:
459 BUG_ON("Unknown state of lock sequence found!\n");
460 break;
461 }
462
463 ls->nr_acquire++;
464 seq->prev_event_time = timestamp;
465end:
466 return;
467}
468
469static void
470report_lock_acquired_event(struct trace_acquired_event *acquired_event,
471 struct event *__event __used,
472 int cpu __used,
473 u64 timestamp __used,
474 struct thread *thread __used)
475{
476 struct lock_stat *ls;
477 struct thread_stat *ts;
478 struct lock_seq_stat *seq;
479 u64 contended_term;
480
481 ls = lock_stat_findnew(acquired_event->addr, acquired_event->name);
482 if (ls->discard)
483 return;
484
485 ts = thread_stat_findnew(thread->pid);
486 seq = get_seq(ts, acquired_event->addr);
487
488 switch (seq->state) {
489 case SEQ_STATE_UNINITIALIZED:
490 /* orphan event, do nothing */
491 return;
492 case SEQ_STATE_ACQUIRING:
493 break;
494 case SEQ_STATE_CONTENDED:
495 contended_term = timestamp - seq->prev_event_time;
496 ls->wait_time_total += contended_term;
497 if (contended_term < ls->wait_time_min)
498 ls->wait_time_min = contended_term;
499 if (ls->wait_time_max < contended_term)
500 ls->wait_time_max = contended_term;
501 break;
502 case SEQ_STATE_RELEASED:
503 case SEQ_STATE_ACQUIRED:
504 case SEQ_STATE_READ_ACQUIRED:
505 /* broken lock sequence, discard it */
506 ls->discard = 1;
507 bad_hist[BROKEN_ACQUIRED]++;
508 list_del(&seq->list);
509 free(seq);
510 goto end;
511 break;
512
513 default:
514 BUG_ON("Unknown state of lock sequence found!\n");
515 break;
516 }
517
518 seq->state = SEQ_STATE_ACQUIRED;
519 ls->nr_acquired++;
520 seq->prev_event_time = timestamp;
521end:
522 return;
523}
524
525static void
526report_lock_contended_event(struct trace_contended_event *contended_event,
527 struct event *__event __used,
528 int cpu __used,
529 u64 timestamp __used,
530 struct thread *thread __used)
531{
532 struct lock_stat *ls;
533 struct thread_stat *ts;
534 struct lock_seq_stat *seq;
535
536 ls = lock_stat_findnew(contended_event->addr, contended_event->name);
537 if (ls->discard)
538 return;
539
540 ts = thread_stat_findnew(thread->pid);
541 seq = get_seq(ts, contended_event->addr);
542
543 switch (seq->state) {
544 case SEQ_STATE_UNINITIALIZED:
545 /* orphan event, do nothing */
546 return;
547 case SEQ_STATE_ACQUIRING:
548 break;
549 case SEQ_STATE_RELEASED:
550 case SEQ_STATE_ACQUIRED:
551 case SEQ_STATE_READ_ACQUIRED:
552 case SEQ_STATE_CONTENDED:
553 /* broken lock sequence, discard it */
554 ls->discard = 1;
555 bad_hist[BROKEN_CONTENDED]++;
556 list_del(&seq->list);
557 free(seq);
558 goto end;
559 break;
560 default:
561 BUG_ON("Unknown state of lock sequence found!\n");
562 break;
563 }
564
565 seq->state = SEQ_STATE_CONTENDED;
566 ls->nr_contended++;
567 seq->prev_event_time = timestamp;
568end:
569 return;
570}
571
572static void
573report_lock_release_event(struct trace_release_event *release_event,
574 struct event *__event __used,
575 int cpu __used,
576 u64 timestamp __used,
577 struct thread *thread __used)
578{
579 struct lock_stat *ls;
580 struct thread_stat *ts;
581 struct lock_seq_stat *seq;
582
583 ls = lock_stat_findnew(release_event->addr, release_event->name);
584 if (ls->discard)
585 return;
586
587 ts = thread_stat_findnew(thread->pid);
588 seq = get_seq(ts, release_event->addr);
589
590 switch (seq->state) {
591 case SEQ_STATE_UNINITIALIZED:
592 goto end;
593 break;
594 case SEQ_STATE_ACQUIRED:
595 break;
596 case SEQ_STATE_READ_ACQUIRED:
597 seq->read_count--;
598 BUG_ON(seq->read_count < 0);
599 if (!seq->read_count) {
600 ls->nr_release++;
601 goto end;
602 }
603 break;
604 case SEQ_STATE_ACQUIRING:
605 case SEQ_STATE_CONTENDED:
606 case SEQ_STATE_RELEASED:
607 /* broken lock sequence, discard it */
608 ls->discard = 1;
609 bad_hist[BROKEN_RELEASE]++;
610 goto free_seq;
611 break;
612 default:
613 BUG_ON("Unknown state of lock sequence found!\n");
614 break;
615 }
616
617 ls->nr_release++;
618free_seq:
619 list_del(&seq->list);
620 free(seq);
621end:
622 return;
623}
624
625/* lock oriented handlers */
626/* TODO: handlers for CPU oriented, thread oriented */
627static struct trace_lock_handler report_lock_ops = {
628 .acquire_event = report_lock_acquire_event,
629 .acquired_event = report_lock_acquired_event,
630 .contended_event = report_lock_contended_event,
631 .release_event = report_lock_release_event,
632};
633
634static struct trace_lock_handler *trace_handler;
635
636static void
637process_lock_acquire_event(void *data,
638 struct event *event __used,
639 int cpu __used,
640 u64 timestamp __used,
641 struct thread *thread __used)
642{
643 struct trace_acquire_event acquire_event;
644 u64 tmp; /* this is required for casting... */
645
646 tmp = raw_field_value(event, "lockdep_addr", data);
647 memcpy(&acquire_event.addr, &tmp, sizeof(void *));
648 acquire_event.name = (char *)raw_field_ptr(event, "name", data);
649 acquire_event.flag = (int)raw_field_value(event, "flag", data);
650
651 if (trace_handler->acquire_event)
652 trace_handler->acquire_event(&acquire_event, event, cpu, timestamp, thread);
653}
654
655static void
656process_lock_acquired_event(void *data,
657 struct event *event __used,
658 int cpu __used,
659 u64 timestamp __used,
660 struct thread *thread __used)
661{
662 struct trace_acquired_event acquired_event;
663 u64 tmp; /* this is required for casting... */
664
665 tmp = raw_field_value(event, "lockdep_addr", data);
666 memcpy(&acquired_event.addr, &tmp, sizeof(void *));
667 acquired_event.name = (char *)raw_field_ptr(event, "name", data);
668
669 if (trace_handler->acquire_event)
670 trace_handler->acquired_event(&acquired_event, event, cpu, timestamp, thread);
671}
672
673static void
674process_lock_contended_event(void *data,
675 struct event *event __used,
676 int cpu __used,
677 u64 timestamp __used,
678 struct thread *thread __used)
679{
680 struct trace_contended_event contended_event;
681 u64 tmp; /* this is required for casting... */
682
683 tmp = raw_field_value(event, "lockdep_addr", data);
684 memcpy(&contended_event.addr, &tmp, sizeof(void *));
685 contended_event.name = (char *)raw_field_ptr(event, "name", data);
686
687 if (trace_handler->acquire_event)
688 trace_handler->contended_event(&contended_event, event, cpu, timestamp, thread);
689}
690
691static void
692process_lock_release_event(void *data,
693 struct event *event __used,
694 int cpu __used,
695 u64 timestamp __used,
696 struct thread *thread __used)
697{
698 struct trace_release_event release_event;
699 u64 tmp; /* this is required for casting... */
700
701 tmp = raw_field_value(event, "lockdep_addr", data);
702 memcpy(&release_event.addr, &tmp, sizeof(void *));
703 release_event.name = (char *)raw_field_ptr(event, "name", data);
704
705 if (trace_handler->acquire_event)
706 trace_handler->release_event(&release_event, event, cpu, timestamp, thread);
707}
708
709static void
710process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
711{
712 struct event *event;
713 int type;
714
715 type = trace_parse_common_type(data);
716 event = trace_find_event(type);
717
718 if (!strcmp(event->name, "lock_acquire"))
719 process_lock_acquire_event(data, event, cpu, timestamp, thread);
720 if (!strcmp(event->name, "lock_acquired"))
721 process_lock_acquired_event(data, event, cpu, timestamp, thread);
722 if (!strcmp(event->name, "lock_contended"))
723 process_lock_contended_event(data, event, cpu, timestamp, thread);
724 if (!strcmp(event->name, "lock_release"))
725 process_lock_release_event(data, event, cpu, timestamp, thread);
726}
727
728static void print_bad_events(int bad, int total)
729{
730 /* Output for debug, this have to be removed */
731 int i;
732 const char *name[4] =
733 { "acquire", "acquired", "contended", "release" };
734
735 pr_info("\n=== output for debug===\n\n");
736 pr_info("bad: %d, total: %d\n", bad, total);
737 pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100);
738 pr_info("histogram of events caused bad sequence\n");
739 for (i = 0; i < BROKEN_MAX; i++)
740 pr_info(" %10s: %d\n", name[i], bad_hist[i]);
741}
742
743/* TODO: various way to print, coloring, nano or milli sec */
744static void print_result(void)
745{
746 struct lock_stat *st;
747 char cut_name[20];
748 int bad, total;
749
750 pr_info("%20s ", "Name");
751 pr_info("%10s ", "acquired");
752 pr_info("%10s ", "contended");
753
754 pr_info("%15s ", "total wait (ns)");
755 pr_info("%15s ", "max wait (ns)");
756 pr_info("%15s ", "min wait (ns)");
757
758 pr_info("\n\n");
759
760 bad = total = 0;
761 while ((st = pop_from_result())) {
762 total++;
763 if (st->discard) {
764 bad++;
765 continue;
766 }
767 bzero(cut_name, 20);
768
769 if (strlen(st->name) < 16) {
770 /* output raw name */
771 pr_info("%20s ", st->name);
772 } else {
773 strncpy(cut_name, st->name, 16);
774 cut_name[16] = '.';
775 cut_name[17] = '.';
776 cut_name[18] = '.';
777 cut_name[19] = '\0';
778 /* cut off name for saving output style */
779 pr_info("%20s ", cut_name);
780 }
781
782 pr_info("%10u ", st->nr_acquired);
783 pr_info("%10u ", st->nr_contended);
784
785 pr_info("%15llu ", st->wait_time_total);
786 pr_info("%15llu ", st->wait_time_max);
787 pr_info("%15llu ", st->wait_time_min == ULLONG_MAX ?
788 0 : st->wait_time_min);
789 pr_info("\n");
790 }
791
792 print_bad_events(bad, total);
793}
794
795static bool info_threads, info_map;
796
797static void dump_threads(void)
798{
799 struct thread_stat *st;
800 struct rb_node *node;
801 struct thread *t;
802
803 pr_info("%10s: comm\n", "Thread ID");
804
805 node = rb_first(&thread_stats);
806 while (node) {
807 st = container_of(node, struct thread_stat, rb);
808 t = perf_session__findnew(session, st->tid);
809 pr_info("%10d: %s\n", st->tid, t->comm);
810 node = rb_next(node);
811 };
812}
813
814static void dump_map(void)
815{
816 unsigned int i;
817 struct lock_stat *st;
818
819 pr_info("Address of instance: name of class\n");
820 for (i = 0; i < LOCKHASH_SIZE; i++) {
821 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
822 pr_info(" %p: %s\n", st->addr, st->name);
823 }
824 }
825}
826
827static void dump_info(void)
828{
829 if (info_threads)
830 dump_threads();
831 else if (info_map)
832 dump_map();
833 else
834 die("Unknown type of information\n");
835}
836
837static int process_sample_event(event_t *self, struct sample_data *sample,
838 struct perf_session *s)
839{
840 struct thread *thread = perf_session__findnew(s, sample->tid);
841
842 if (thread == NULL) {
843 pr_debug("problem processing %d event, skipping it.\n",
844 self->header.type);
845 return -1;
846 }
847
848 process_raw_event(sample->raw_data, sample->cpu, sample->time, thread);
849
850 return 0;
851}
852
853static struct perf_event_ops eops = {
854 .sample = process_sample_event,
855 .comm = event__process_comm,
856 .ordered_samples = true,
857};
858
859static int read_events(void)
860{
861 session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
862 if (!session)
863 die("Initializing perf session failed\n");
864
865 return perf_session__process_events(session, &eops);
866}
867
868static void sort_result(void)
869{
870 unsigned int i;
871 struct lock_stat *st;
872
873 for (i = 0; i < LOCKHASH_SIZE; i++) {
874 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
875 insert_to_result(st, compare);
876 }
877 }
878}
879
880static void __cmd_report(void)
881{
882 setup_pager();
883 select_key();
884 read_events();
885 sort_result();
886 print_result();
887}
888
889static const char * const report_usage[] = {
890 "perf lock report [<options>]",
891 NULL
892};
893
894static const struct option report_options[] = {
895 OPT_STRING('k', "key", &sort_key, "acquired",
896 "key for sorting"),
897 /* TODO: type */
898 OPT_END()
899};
900
901static const char * const info_usage[] = {
902 "perf lock info [<options>]",
903 NULL
904};
905
906static const struct option info_options[] = {
907 OPT_BOOLEAN('t', "threads", &info_threads,
908 "dump thread list in perf.data"),
909 OPT_BOOLEAN('m', "map", &info_map,
910 "map of lock instances (name:address table)"),
911 OPT_END()
912};
913
914static const char * const lock_usage[] = {
915 "perf lock [<options>] {record|trace|report}",
916 NULL
917};
918
919static const struct option lock_options[] = {
920 OPT_STRING('i', "input", &input_name, "file", "input file name"),
921 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
922 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
923 OPT_END()
924};
925
926static const char *record_args[] = {
927 "record",
928 "-R",
929 "-f",
930 "-m", "1024",
931 "-c", "1",
932 "-e", "lock:lock_acquire:r",
933 "-e", "lock:lock_acquired:r",
934 "-e", "lock:lock_contended:r",
935 "-e", "lock:lock_release:r",
936};
937
938static int __cmd_record(int argc, const char **argv)
939{
940 unsigned int rec_argc, i, j;
941 const char **rec_argv;
942
943 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
944 rec_argv = calloc(rec_argc + 1, sizeof(char *));
945
946 if (rec_argv == NULL)
947 return -ENOMEM;
948
949 for (i = 0; i < ARRAY_SIZE(record_args); i++)
950 rec_argv[i] = strdup(record_args[i]);
951
952 for (j = 1; j < (unsigned int)argc; j++, i++)
953 rec_argv[i] = argv[j];
954
955 BUG_ON(i != rec_argc);
956
957 return cmd_record(i, rec_argv, NULL);
958}
959
960int cmd_lock(int argc, const char **argv, const char *prefix __used)
961{
962 unsigned int i;
963
964 symbol__init();
965 for (i = 0; i < LOCKHASH_SIZE; i++)
966 INIT_LIST_HEAD(lockhash_table + i);
967
968 argc = parse_options(argc, argv, lock_options, lock_usage,
969 PARSE_OPT_STOP_AT_NON_OPTION);
970 if (!argc)
971 usage_with_options(lock_usage, lock_options);
972
973 if (!strncmp(argv[0], "rec", 3)) {
974 return __cmd_record(argc, argv);
975 } else if (!strncmp(argv[0], "report", 6)) {
976 trace_handler = &report_lock_ops;
977 if (argc) {
978 argc = parse_options(argc, argv,
979 report_options, report_usage, 0);
980 if (argc)
981 usage_with_options(report_usage, report_options);
982 }
983 __cmd_report();
984 } else if (!strcmp(argv[0], "script")) {
985 /* Aliased to 'perf script' */
986 return cmd_script(argc, argv, prefix);
987 } else if (!strcmp(argv[0], "info")) {
988 if (argc) {
989 argc = parse_options(argc, argv,
990 info_options, info_usage, 0);
991 if (argc)
992 usage_with_options(info_usage, info_options);
993 }
994 /* recycling report_lock_ops */
995 trace_handler = &report_lock_ops;
996 setup_pager();
997 read_events();
998 dump_info();
999 } else {
1000 usage_with_options(lock_usage, lock_options);
1001 }
1002
1003 return 0;
1004}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c1e6774fd3ed..add163c9f0e7 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -36,51 +36,53 @@
36#include "builtin.h" 36#include "builtin.h"
37#include "util/util.h" 37#include "util/util.h"
38#include "util/strlist.h" 38#include "util/strlist.h"
39#include "util/event.h" 39#include "util/symbol.h"
40#include "util/debug.h" 40#include "util/debug.h"
41#include "util/debugfs.h" 41#include "util/debugfs.h"
42#include "util/symbol.h"
43#include "util/thread.h"
44#include "util/session.h"
45#include "util/parse-options.h" 42#include "util/parse-options.h"
46#include "util/parse-events.h" /* For debugfs_path */
47#include "util/probe-finder.h" 43#include "util/probe-finder.h"
48#include "util/probe-event.h" 44#include "util/probe-event.h"
49 45
50#define MAX_PATH_LEN 256 46#define MAX_PATH_LEN 256
51#define MAX_PROBES 128
52 47
53/* Session management structure */ 48/* Session management structure */
54static struct { 49static struct {
55 bool need_dwarf;
56 bool list_events; 50 bool list_events;
57 bool force_add; 51 bool force_add;
58 int nr_probe; 52 bool show_lines;
59 struct probe_point probes[MAX_PROBES]; 53 bool show_vars;
54 bool show_ext_vars;
55 bool mod_events;
56 int nevents;
57 struct perf_probe_event events[MAX_PROBES];
60 struct strlist *dellist; 58 struct strlist *dellist;
61 struct perf_session *psession; 59 struct line_range line_range;
62 struct map *kmap; 60 const char *target_module;
63} session; 61 int max_probe_points;
64 62} params;
65 63
66/* Parse an event definition. Note that any error must die. */ 64/* Parse an event definition. Note that any error must die. */
67static void parse_probe_event(const char *str) 65static int parse_probe_event(const char *str)
68{ 66{
69 struct probe_point *pp = &session.probes[session.nr_probe]; 67 struct perf_probe_event *pev = &params.events[params.nevents];
68 int ret;
70 69
71 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str); 70 pr_debug("probe-definition(%d): %s\n", params.nevents, str);
72 if (++session.nr_probe == MAX_PROBES) 71 if (++params.nevents == MAX_PROBES) {
73 die("Too many probes (> %d) are specified.", MAX_PROBES); 72 pr_err("Too many probes (> %d) were specified.", MAX_PROBES);
73 return -1;
74 }
74 75
75 /* Parse perf-probe event into probe_point */ 76 /* Parse a perf-probe command into event */
76 parse_perf_probe_event(str, pp, &session.need_dwarf); 77 ret = parse_perf_probe_command(str, pev);
78 pr_debug("%d arguments\n", pev->nargs);
77 79
78 pr_debug("%d arguments\n", pp->nr_args); 80 return ret;
79} 81}
80 82
81static void parse_probe_event_argv(int argc, const char **argv) 83static int parse_probe_event_argv(int argc, const char **argv)
82{ 84{
83 int i, len; 85 int i, len, ret;
84 char *buf; 86 char *buf;
85 87
86 /* Bind up rest arguments */ 88 /* Bind up rest arguments */
@@ -88,54 +90,70 @@ static void parse_probe_event_argv(int argc, const char **argv)
88 for (i = 0; i < argc; i++) 90 for (i = 0; i < argc; i++)
89 len += strlen(argv[i]) + 1; 91 len += strlen(argv[i]) + 1;
90 buf = zalloc(len + 1); 92 buf = zalloc(len + 1);
91 if (!buf) 93 if (buf == NULL)
92 die("Failed to allocate memory for binding arguments."); 94 return -ENOMEM;
93 len = 0; 95 len = 0;
94 for (i = 0; i < argc; i++) 96 for (i = 0; i < argc; i++)
95 len += sprintf(&buf[len], "%s ", argv[i]); 97 len += sprintf(&buf[len], "%s ", argv[i]);
96 parse_probe_event(buf); 98 params.mod_events = true;
99 ret = parse_probe_event(buf);
97 free(buf); 100 free(buf);
101 return ret;
98} 102}
99 103
100static int opt_add_probe_event(const struct option *opt __used, 104static int opt_add_probe_event(const struct option *opt __used,
101 const char *str, int unset __used) 105 const char *str, int unset __used)
102{ 106{
103 if (str) 107 if (str) {
104 parse_probe_event(str); 108 params.mod_events = true;
105 return 0; 109 return parse_probe_event(str);
110 } else
111 return 0;
106} 112}
107 113
108static int opt_del_probe_event(const struct option *opt __used, 114static int opt_del_probe_event(const struct option *opt __used,
109 const char *str, int unset __used) 115 const char *str, int unset __used)
110{ 116{
111 if (str) { 117 if (str) {
112 if (!session.dellist) 118 params.mod_events = true;
113 session.dellist = strlist__new(true, NULL); 119 if (!params.dellist)
114 strlist__add(session.dellist, str); 120 params.dellist = strlist__new(true, NULL);
121 strlist__add(params.dellist, str);
115 } 122 }
116 return 0; 123 return 0;
117} 124}
118 125
119/* Currently just checking function name from symbol map */ 126#ifdef DWARF_SUPPORT
120static void evaluate_probe_point(struct probe_point *pp) 127static int opt_show_lines(const struct option *opt __used,
128 const char *str, int unset __used)
121{ 129{
122 struct symbol *sym; 130 int ret = 0;
123 sym = map__find_symbol_by_name(session.kmap, pp->function, 131
124 session.psession, NULL); 132 if (str)
125 if (!sym) 133 ret = parse_line_range_desc(str, &params.line_range);
126 die("Kernel symbol \'%s\' not found - probe not added.", 134 INIT_LIST_HEAD(&params.line_range.line_list);
127 pp->function); 135 params.show_lines = true;
136
137 return ret;
128} 138}
129 139
130#ifndef NO_LIBDWARF 140static int opt_show_vars(const struct option *opt __used,
131static int open_vmlinux(void) 141 const char *str, int unset __used)
132{ 142{
133 if (map__load(session.kmap, session.psession, NULL) < 0) { 143 struct perf_probe_event *pev = &params.events[params.nevents];
134 pr_debug("Failed to load kernel map.\n"); 144 int ret;
145
146 if (!str)
147 return 0;
148
149 ret = parse_probe_event(str);
150 if (!ret && pev->nargs != 0) {
151 pr_err(" Error: '--vars' doesn't accept arguments.\n");
135 return -EINVAL; 152 return -EINVAL;
136 } 153 }
137 pr_debug("Try to open %s\n", session.kmap->dso->long_name); 154 params.show_vars = true;
138 return open(session.kmap->dso->long_name, O_RDONLY); 155
156 return ret;
139} 157}
140#endif 158#endif
141 159
@@ -144,54 +162,71 @@ static const char * const probe_usage[] = {
144 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 162 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
145 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 163 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
146 "perf probe --list", 164 "perf probe --list",
165#ifdef DWARF_SUPPORT
166 "perf probe [<options>] --line 'LINEDESC'",
167 "perf probe [<options>] --vars 'PROBEPOINT'",
168#endif
147 NULL 169 NULL
148}; 170};
149 171
150static const struct option options[] = { 172static const struct option options[] = {
151 OPT_BOOLEAN('v', "verbose", &verbose, 173 OPT_INCR('v', "verbose", &verbose,
152 "be more verbose (show parsed arguments, etc)"), 174 "be more verbose (show parsed arguments, etc)"),
153#ifndef NO_LIBDWARF 175 OPT_BOOLEAN('l', "list", &params.list_events,
154 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
155 "file", "vmlinux pathname"),
156#endif
157 OPT_BOOLEAN('l', "list", &session.list_events,
158 "list up current probe events"), 176 "list up current probe events"),
159 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 177 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
160 opt_del_probe_event), 178 opt_del_probe_event),
161 OPT_CALLBACK('a', "add", NULL, 179 OPT_CALLBACK('a', "add", NULL,
162#ifdef NO_LIBDWARF 180#ifdef DWARF_SUPPORT
163 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]", 181 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
182 " [[NAME=]ARG ...]",
164#else 183#else
165 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 184 "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]",
166#endif 185#endif
167 "probe point definition, where\n" 186 "probe point definition, where\n"
168 "\t\tGROUP:\tGroup name (optional)\n" 187 "\t\tGROUP:\tGroup name (optional)\n"
169 "\t\tEVENT:\tEvent name\n" 188 "\t\tEVENT:\tEvent name\n"
170 "\t\tFUNC:\tFunction name\n" 189 "\t\tFUNC:\tFunction name\n"
171 "\t\tOFFS:\tOffset from function entry (in byte)\n" 190 "\t\tOFF:\tOffset from function entry (in byte)\n"
172 "\t\t%return:\tPut the probe at function return\n" 191 "\t\t%return:\tPut the probe at function return\n"
173#ifdef NO_LIBDWARF 192#ifdef DWARF_SUPPORT
174 "\t\tARG:\tProbe argument (only \n"
175#else
176 "\t\tSRC:\tSource code path\n" 193 "\t\tSRC:\tSource code path\n"
177 "\t\tRLN:\tRelative line number from function entry.\n" 194 "\t\tRL:\tRelative line number from function entry.\n"
178 "\t\tALN:\tAbsolute line number in file.\n" 195 "\t\tAL:\tAbsolute line number in file.\n"
196 "\t\tPT:\tLazy expression of line code.\n"
179 "\t\tARG:\tProbe argument (local variable name or\n" 197 "\t\tARG:\tProbe argument (local variable name or\n"
180#endif
181 "\t\t\tkprobe-tracer argument format.)\n", 198 "\t\t\tkprobe-tracer argument format.)\n",
199#else
200 "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
201#endif
182 opt_add_probe_event), 202 opt_add_probe_event),
183 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" 203 OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
184 " with existing name"), 204 " with existing name"),
205#ifdef DWARF_SUPPORT
206 OPT_CALLBACK('L', "line", NULL,
207 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
208 "Show source code lines.", opt_show_lines),
209 OPT_CALLBACK('V', "vars", NULL,
210 "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
211 "Show accessible variables on PROBEDEF", opt_show_vars),
212 OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
213 "Show external variables too (with --vars only)"),
214 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
215 "file", "vmlinux pathname"),
216 OPT_STRING('s', "source", &symbol_conf.source_prefix,
217 "directory", "path to kernel source"),
218 OPT_STRING('m', "module", &params.target_module,
219 "modname", "target module name"),
220#endif
221 OPT__DRY_RUN(&probe_event_dry_run),
222 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
223 "Set how many probe points can be found for a probe."),
185 OPT_END() 224 OPT_END()
186}; 225};
187 226
188int cmd_probe(int argc, const char **argv, const char *prefix __used) 227int cmd_probe(int argc, const char **argv, const char *prefix __used)
189{ 228{
190 int i, ret; 229 int ret;
191#ifndef NO_LIBDWARF
192 int fd;
193#endif
194 struct probe_point *pp;
195 230
196 argc = parse_options(argc, argv, options, probe_usage, 231 argc = parse_options(argc, argv, options, probe_usage,
197 PARSE_OPT_STOP_AT_NON_OPTION); 232 PARSE_OPT_STOP_AT_NON_OPTION);
@@ -200,110 +235,96 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
200 pr_warning(" Error: '-' is not supported.\n"); 235 pr_warning(" Error: '-' is not supported.\n");
201 usage_with_options(probe_usage, options); 236 usage_with_options(probe_usage, options);
202 } 237 }
203 parse_probe_event_argv(argc, argv); 238 ret = parse_probe_event_argv(argc, argv);
239 if (ret < 0) {
240 pr_err(" Error: Parse Error. (%d)\n", ret);
241 return ret;
242 }
204 } 243 }
205 244
206 if ((!session.nr_probe && !session.dellist && !session.list_events)) 245 if (params.max_probe_points == 0)
246 params.max_probe_points = MAX_PROBES;
247
248 if ((!params.nevents && !params.dellist && !params.list_events &&
249 !params.show_lines))
207 usage_with_options(probe_usage, options); 250 usage_with_options(probe_usage, options);
208 251
209 if (debugfs_valid_mountpoint(debugfs_path) < 0) 252 /*
210 die("Failed to find debugfs path."); 253 * Only consider the user's kernel image path if given.
254 */
255 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
211 256
212 if (session.list_events) { 257 if (params.list_events) {
213 if (session.nr_probe != 0 || session.dellist) { 258 if (params.mod_events) {
214 pr_warning(" Error: Don't use --list with" 259 pr_err(" Error: Don't use --list with --add/--del.\n");
215 " --add/--del.\n");
216 usage_with_options(probe_usage, options); 260 usage_with_options(probe_usage, options);
217 } 261 }
218 show_perf_probe_events(); 262 if (params.show_lines) {
219 return 0; 263 pr_err(" Error: Don't use --list with --line.\n");
220 } 264 usage_with_options(probe_usage, options);
221 265 }
222 if (session.dellist) { 266 if (params.show_vars) {
223 del_trace_kprobe_events(session.dellist); 267 pr_err(" Error: Don't use --list with --vars.\n");
224 strlist__delete(session.dellist); 268 usage_with_options(probe_usage, options);
225 if (session.nr_probe == 0) 269 }
226 return 0; 270 ret = show_perf_probe_events();
271 if (ret < 0)
272 pr_err(" Error: Failed to show event list. (%d)\n",
273 ret);
274 return ret;
227 } 275 }
228 276
229 /* Initialize symbol maps for vmlinux */ 277#ifdef DWARF_SUPPORT
230 symbol_conf.sort_by_name = true; 278 if (params.show_lines) {
231 if (symbol_conf.vmlinux_name == NULL) 279 if (params.mod_events) {
232 symbol_conf.try_vmlinux_path = true; 280 pr_err(" Error: Don't use --line with"
233 if (symbol__init() < 0) 281 " --add/--del.\n");
234 die("Failed to init symbol map."); 282 usage_with_options(probe_usage, options);
235 session.psession = perf_session__new(NULL, O_WRONLY, false); 283 }
236 if (session.psession == NULL) 284 if (params.show_vars) {
237 die("Failed to init perf_session."); 285 pr_err(" Error: Don't use --line with --vars.\n");
238 session.kmap = map_groups__find_by_name(&session.psession->kmaps, 286 usage_with_options(probe_usage, options);
239 MAP__FUNCTION, 287 }
240 "[kernel.kallsyms]");
241 if (!session.kmap)
242 die("Could not find kernel map.\n");
243
244 if (session.need_dwarf)
245#ifdef NO_LIBDWARF
246 die("Debuginfo-analysis is not supported");
247#else /* !NO_LIBDWARF */
248 pr_debug("Some probes require debuginfo.\n");
249
250 fd = open_vmlinux();
251 if (fd < 0) {
252 if (session.need_dwarf)
253 die("Could not open debuginfo file.");
254 288
255 pr_debug("Could not open vmlinux/module file." 289 ret = show_line_range(&params.line_range, params.target_module);
256 " Try to use symbols.\n"); 290 if (ret < 0)
257 goto end_dwarf; 291 pr_err(" Error: Failed to show lines. (%d)\n", ret);
292 return ret;
258 } 293 }
259 294 if (params.show_vars) {
260 /* Searching probe points */ 295 if (params.mod_events) {
261 for (i = 0; i < session.nr_probe; i++) { 296 pr_err(" Error: Don't use --vars with"
262 pp = &session.probes[i]; 297 " --add/--del.\n");
263 if (pp->found) 298 usage_with_options(probe_usage, options);
264 continue;
265
266 lseek(fd, SEEK_SET, 0);
267 ret = find_probepoint(fd, pp);
268 if (ret > 0)
269 continue;
270 if (ret == 0) { /* No error but failed to find probe point. */
271 synthesize_perf_probe_point(pp);
272 die("Probe point '%s' not found. - probe not added.",
273 pp->probes[0]);
274 }
275 /* Error path */
276 if (session.need_dwarf) {
277 if (ret == -ENOENT)
278 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n");
279 die("Could not analyze debuginfo.");
280 } 299 }
281 pr_debug("An error occurred in debuginfo analysis." 300 ret = show_available_vars(params.events, params.nevents,
282 " Try to use symbols.\n"); 301 params.max_probe_points,
283 break; 302 params.target_module,
303 params.show_ext_vars);
304 if (ret < 0)
305 pr_err(" Error: Failed to show vars. (%d)\n", ret);
306 return ret;
284 } 307 }
285 close(fd); 308#endif
286
287end_dwarf:
288#endif /* !NO_LIBDWARF */
289
290 /* Synthesize probes without dwarf */
291 for (i = 0; i < session.nr_probe; i++) {
292 pp = &session.probes[i];
293 if (pp->found) /* This probe is already found. */
294 continue;
295 309
296 evaluate_probe_point(pp); 310 if (params.dellist) {
297 ret = synthesize_trace_kprobe_event(pp); 311 ret = del_perf_probe_events(params.dellist);
298 if (ret == -E2BIG) 312 strlist__delete(params.dellist);
299 die("probe point definition becomes too long."); 313 if (ret < 0) {
300 else if (ret < 0) 314 pr_err(" Error: Failed to delete events. (%d)\n", ret);
301 die("Failed to synthesize a probe point."); 315 return ret;
316 }
302 } 317 }
303 318
304 /* Settng up probe points */ 319 if (params.nevents) {
305 add_trace_kprobe_events(session.probes, session.nr_probe, 320 ret = add_perf_probe_events(params.events, params.nevents,
306 session.force_add); 321 params.max_probe_points,
322 params.target_module,
323 params.force_add);
324 if (ret < 0) {
325 pr_err(" Error: Failed to add events. (%d)\n", ret);
326 return ret;
327 }
328 }
307 return 0; 329 return 0;
308} 330}
309
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 265425322734..fcd29e8af29f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -5,74 +5,89 @@
5 * (or a CPU, or a PID) into the perf.data output file - for 5 * (or a CPU, or a PID) into the perf.data output file - for
6 * later analysis via perf report. 6 * later analysis via perf report.
7 */ 7 */
8#define _FILE_OFFSET_BITS 64
9
8#include "builtin.h" 10#include "builtin.h"
9 11
10#include "perf.h" 12#include "perf.h"
11 13
14#include "util/build-id.h"
12#include "util/util.h" 15#include "util/util.h"
13#include "util/parse-options.h" 16#include "util/parse-options.h"
14#include "util/parse-events.h" 17#include "util/parse-events.h"
15#include "util/string.h"
16 18
17#include "util/header.h" 19#include "util/header.h"
18#include "util/event.h" 20#include "util/event.h"
21#include "util/evsel.h"
19#include "util/debug.h" 22#include "util/debug.h"
20#include "util/session.h" 23#include "util/session.h"
21#include "util/symbol.h" 24#include "util/symbol.h"
25#include "util/cpumap.h"
22 26
23#include <unistd.h> 27#include <unistd.h>
24#include <sched.h> 28#include <sched.h>
29#include <sys/mman.h>
30
31#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
25 32
26static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 33enum write_mode_t {
34 WRITE_FORCE,
35 WRITE_APPEND
36};
27 37
28static long default_interval = 0; 38static u64 user_interval = ULLONG_MAX;
39static u64 default_interval = 0;
40static u64 sample_type;
29 41
30static int nr_cpus = 0; 42static struct cpu_map *cpus;
31static unsigned int page_size; 43static unsigned int page_size;
32static unsigned int mmap_pages = 128; 44static unsigned int mmap_pages = 128;
45static unsigned int user_freq = UINT_MAX;
33static int freq = 1000; 46static int freq = 1000;
34static int output; 47static int output;
48static int pipe_output = 0;
35static const char *output_name = "perf.data"; 49static const char *output_name = "perf.data";
36static int group = 0; 50static int group = 0;
37static unsigned int realtime_prio = 0; 51static int realtime_prio = 0;
38static int raw_samples = 0; 52static bool nodelay = false;
39static int system_wide = 0; 53static bool raw_samples = false;
40static int profile_cpu = -1; 54static bool sample_id_all_avail = true;
55static bool system_wide = false;
41static pid_t target_pid = -1; 56static pid_t target_pid = -1;
57static pid_t target_tid = -1;
58static struct thread_map *threads;
42static pid_t child_pid = -1; 59static pid_t child_pid = -1;
43static int inherit = 1; 60static bool no_inherit = false;
44static int force = 0; 61static enum write_mode_t write_mode = WRITE_FORCE;
45static int append_file = 0; 62static bool call_graph = false;
46static int call_graph = 0; 63static bool inherit_stat = false;
47static int inherit_stat = 0; 64static bool no_samples = false;
48static int no_samples = 0; 65static bool sample_address = false;
49static int sample_address = 0; 66static bool sample_time = false;
50static int multiplex = 0; 67static bool no_buildid = false;
51static int multiplex_fd = -1; 68static bool no_buildid_cache = false;
52 69
53static long samples = 0; 70static long samples = 0;
54static struct timeval last_read;
55static struct timeval this_read;
56
57static u64 bytes_written = 0; 71static u64 bytes_written = 0;
58 72
59static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 73static struct pollfd *event_array;
60 74
61static int nr_poll = 0; 75static int nr_poll = 0;
62static int nr_cpu = 0; 76static int nr_cpu = 0;
63 77
64static int file_new = 1; 78static int file_new = 1;
79static off_t post_processing_offset;
65 80
66static struct perf_session *session; 81static struct perf_session *session;
82static const char *cpu_list;
67 83
68struct mmap_data { 84struct mmap_data {
69 int counter;
70 void *base; 85 void *base;
71 unsigned int mask; 86 unsigned int mask;
72 unsigned int prev; 87 unsigned int prev;
73}; 88};
74 89
75static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 90static struct mmap_data mmap_array[MAX_NR_CPUS];
76 91
77static unsigned long mmap_read_head(struct mmap_data *md) 92static unsigned long mmap_read_head(struct mmap_data *md)
78{ 93{
@@ -96,6 +111,11 @@ static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
96 pc->data_tail = tail; 111 pc->data_tail = tail;
97} 112}
98 113
114static void advance_output(size_t size)
115{
116 bytes_written += size;
117}
118
99static void write_output(void *buf, size_t size) 119static void write_output(void *buf, size_t size)
100{ 120{
101 while (size) { 121 while (size) {
@@ -111,22 +131,11 @@ static void write_output(void *buf, size_t size)
111 } 131 }
112} 132}
113 133
114static void write_event(event_t *buf, size_t size)
115{
116 /*
117 * Add it to the list of DSOs, so that when we finish this
118 * record session we can pick the available build-ids.
119 */
120 if (buf->header.type == PERF_RECORD_MMAP)
121 dsos__findnew(buf->mmap.filename);
122
123 write_output(buf, size);
124}
125
126static int process_synthesized_event(event_t *event, 134static int process_synthesized_event(event_t *event,
135 struct sample_data *sample __used,
127 struct perf_session *self __used) 136 struct perf_session *self __used)
128{ 137{
129 write_event(event, event->header.size); 138 write_output(event, event->header.size);
130 return 0; 139 return 0;
131} 140}
132 141
@@ -139,8 +148,6 @@ static void mmap_read(struct mmap_data *md)
139 void *buf; 148 void *buf;
140 int diff; 149 int diff;
141 150
142 gettimeofday(&this_read, NULL);
143
144 /* 151 /*
145 * If we're further behind than half the buffer, there's a chance 152 * If we're further behind than half the buffer, there's a chance
146 * the writer will bite our tail and mess up the samples under us. 153 * the writer will bite our tail and mess up the samples under us.
@@ -151,23 +158,13 @@ static void mmap_read(struct mmap_data *md)
151 */ 158 */
152 diff = head - old; 159 diff = head - old;
153 if (diff < 0) { 160 if (diff < 0) {
154 struct timeval iv; 161 fprintf(stderr, "WARNING: failed to keep up with mmap data\n");
155 unsigned long msecs;
156
157 timersub(&this_read, &last_read, &iv);
158 msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
159
160 fprintf(stderr, "WARNING: failed to keep up with mmap data."
161 " Last read %lu msecs ago.\n", msecs);
162
163 /* 162 /*
164 * head points to a known good entry, start there. 163 * head points to a known good entry, start there.
165 */ 164 */
166 old = head; 165 old = head;
167 } 166 }
168 167
169 last_read = this_read;
170
171 if (old != head) 168 if (old != head)
172 samples++; 169 samples++;
173 170
@@ -178,14 +175,14 @@ static void mmap_read(struct mmap_data *md)
178 size = md->mask + 1 - (old & md->mask); 175 size = md->mask + 1 - (old & md->mask);
179 old += size; 176 old += size;
180 177
181 write_event(buf, size); 178 write_output(buf, size);
182 } 179 }
183 180
184 buf = &data[old & md->mask]; 181 buf = &data[old & md->mask];
185 size = head - old; 182 size = head - old;
186 old += size; 183 old += size;
187 184
188 write_event(buf, size); 185 write_output(buf, size);
189 186
190 md->prev = old; 187 md->prev = old;
191 mmap_write_tail(md, old); 188 mmap_write_tail(md, old);
@@ -202,10 +199,10 @@ static void sig_handler(int sig)
202 199
203static void sig_atexit(void) 200static void sig_atexit(void)
204{ 201{
205 if (child_pid != -1) 202 if (child_pid > 0)
206 kill(child_pid, SIGTERM); 203 kill(child_pid, SIGTERM);
207 204
208 if (signr == -1) 205 if (signr == -1 || signr == SIGUSR1)
209 return; 206 return;
210 207
211 signal(signr, SIG_DFL); 208 signal(signr, SIG_DFL);
@@ -232,12 +229,13 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
232 return h_attr; 229 return h_attr;
233} 230}
234 231
235static void create_counter(int counter, int cpu, pid_t pid) 232static void create_counter(struct perf_evsel *evsel, int cpu)
236{ 233{
237 char *filter = filters[counter]; 234 char *filter = evsel->filter;
238 struct perf_event_attr *attr = attrs + counter; 235 struct perf_event_attr *attr = &evsel->attr;
239 struct perf_header_attr *h_attr; 236 struct perf_header_attr *h_attr;
240 int track = !counter; /* only the first counter needs these */ 237 int track = !evsel->idx; /* only the first counter needs these */
238 int thread_index;
241 int ret; 239 int ret;
242 struct { 240 struct {
243 u64 count; 241 u64 count;
@@ -245,6 +243,19 @@ static void create_counter(int counter, int cpu, pid_t pid)
245 u64 time_running; 243 u64 time_running;
246 u64 id; 244 u64 id;
247 } read_data; 245 } read_data;
246 /*
247 * Check if parse_single_tracepoint_event has already asked for
248 * PERF_SAMPLE_TIME.
249 *
250 * XXX this is kludgy but short term fix for problems introduced by
251 * eac23d1c that broke 'perf script' by having different sample_types
252 * when using multiple tracepoint events when we use a perf binary
253 * that tries to use sample_id_all on an older kernel.
254 *
255 * We need to move counter creation to perf_session, support
256 * different sample_types, etc.
257 */
258 bool time_needed = attr->sample_type & PERF_SAMPLE_TIME;
248 259
249 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 260 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
250 PERF_FORMAT_TOTAL_TIME_RUNNING | 261 PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -252,10 +263,22 @@ static void create_counter(int counter, int cpu, pid_t pid)
252 263
253 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 264 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
254 265
255 if (freq) { 266 if (nr_counters > 1)
256 attr->sample_type |= PERF_SAMPLE_PERIOD; 267 attr->sample_type |= PERF_SAMPLE_ID;
257 attr->freq = 1; 268
258 attr->sample_freq = freq; 269 /*
270 * We default some events to a 1 default interval. But keep
271 * it a weak assumption overridable by the user.
272 */
273 if (!attr->sample_period || (user_freq != UINT_MAX &&
274 user_interval != ULLONG_MAX)) {
275 if (freq) {
276 attr->sample_type |= PERF_SAMPLE_PERIOD;
277 attr->freq = 1;
278 attr->sample_freq = freq;
279 } else {
280 attr->sample_period = default_interval;
281 }
259 } 282 }
260 283
261 if (no_samples) 284 if (no_samples)
@@ -264,234 +287,348 @@ static void create_counter(int counter, int cpu, pid_t pid)
264 if (inherit_stat) 287 if (inherit_stat)
265 attr->inherit_stat = 1; 288 attr->inherit_stat = 1;
266 289
267 if (sample_address) 290 if (sample_address) {
268 attr->sample_type |= PERF_SAMPLE_ADDR; 291 attr->sample_type |= PERF_SAMPLE_ADDR;
292 attr->mmap_data = track;
293 }
269 294
270 if (call_graph) 295 if (call_graph)
271 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 296 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
272 297
298 if (system_wide)
299 attr->sample_type |= PERF_SAMPLE_CPU;
300
301 if (sample_id_all_avail &&
302 (sample_time || system_wide || !no_inherit || cpu_list))
303 attr->sample_type |= PERF_SAMPLE_TIME;
304
273 if (raw_samples) { 305 if (raw_samples) {
274 attr->sample_type |= PERF_SAMPLE_TIME; 306 attr->sample_type |= PERF_SAMPLE_TIME;
275 attr->sample_type |= PERF_SAMPLE_RAW; 307 attr->sample_type |= PERF_SAMPLE_RAW;
276 attr->sample_type |= PERF_SAMPLE_CPU; 308 attr->sample_type |= PERF_SAMPLE_CPU;
277 } 309 }
278 310
311 if (nodelay) {
312 attr->watermark = 0;
313 attr->wakeup_events = 1;
314 }
315
279 attr->mmap = track; 316 attr->mmap = track;
280 attr->comm = track; 317 attr->comm = track;
281 attr->inherit = inherit; 318 attr->inherit = !no_inherit;
282 attr->disabled = 1; 319 if (target_pid == -1 && target_tid == -1 && !system_wide) {
320 attr->disabled = 1;
321 attr->enable_on_exec = 1;
322 }
323retry_sample_id:
324 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
283 325
326 for (thread_index = 0; thread_index < threads->nr; thread_index++) {
284try_again: 327try_again:
285 fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0); 328 FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0);
286 329
287 if (fd[nr_cpu][counter] < 0) { 330 if (FD(evsel, nr_cpu, thread_index) < 0) {
288 int err = errno; 331 int err = errno;
289 332
290 if (err == EPERM || err == EACCES) 333 if (err == EPERM || err == EACCES)
291 die("Permission error - are you root?\n"); 334 die("Permission error - are you root?\n"
292 else if (err == ENODEV && profile_cpu != -1) 335 "\t Consider tweaking"
293 die("No such device - did you specify an out-of-range profile CPU?\n"); 336 " /proc/sys/kernel/perf_event_paranoid.\n");
337 else if (err == ENODEV && cpu_list) {
338 die("No such device - did you specify"
339 " an out-of-range profile CPU?\n");
340 } else if (err == EINVAL && sample_id_all_avail) {
341 /*
342 * Old kernel, no attr->sample_id_type_all field
343 */
344 sample_id_all_avail = false;
345 if (!sample_time && !raw_samples && !time_needed)
346 attr->sample_type &= ~PERF_SAMPLE_TIME;
347
348 goto retry_sample_id;
349 }
294 350
295 /* 351 /*
296 * If it's cycles then fall back to hrtimer 352 * If it's cycles then fall back to hrtimer
297 * based cpu-clock-tick sw counter, which 353 * based cpu-clock-tick sw counter, which
298 * is always available even if no PMU support: 354 * is always available even if no PMU support:
299 */ 355 */
300 if (attr->type == PERF_TYPE_HARDWARE 356 if (attr->type == PERF_TYPE_HARDWARE
301 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 357 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
302 358
303 if (verbose) 359 if (verbose)
304 warning(" ... trying to fall back to cpu-clock-ticks\n"); 360 warning(" ... trying to fall back to cpu-clock-ticks\n");
305 attr->type = PERF_TYPE_SOFTWARE; 361 attr->type = PERF_TYPE_SOFTWARE;
306 attr->config = PERF_COUNT_SW_CPU_CLOCK; 362 attr->config = PERF_COUNT_SW_CPU_CLOCK;
307 goto try_again; 363 goto try_again;
308 } 364 }
309 printf("\n"); 365 printf("\n");
310 error("perfcounter syscall returned with %d (%s)\n", 366 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
311 fd[nr_cpu][counter], strerror(err)); 367 FD(evsel, nr_cpu, thread_index), strerror(err));
312 368
313#if defined(__i386__) || defined(__x86_64__) 369#if defined(__i386__) || defined(__x86_64__)
314 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 370 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
315 die("No hardware sampling interrupt available. No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.\n"); 371 die("No hardware sampling interrupt available."
372 " No APIC? If so then you can boot the kernel"
373 " with the \"lapic\" boot parameter to"
374 " force-enable it.\n");
316#endif 375#endif
317 376
318 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 377 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
319 exit(-1);
320 }
321
322 h_attr = get_header_attr(attr, counter);
323 if (h_attr == NULL)
324 die("nomem\n");
325
326 if (!file_new) {
327 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
328 fprintf(stderr, "incompatible append\n");
329 exit(-1); 378 exit(-1);
330 } 379 }
331 }
332 380
333 if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) { 381 h_attr = get_header_attr(attr, evsel->idx);
334 perror("Unable to read perf file descriptor\n"); 382 if (h_attr == NULL)
335 exit(-1); 383 die("nomem\n");
336 }
337 384
338 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { 385 if (!file_new) {
339 pr_warning("Not enough memory to add id\n"); 386 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
340 exit(-1); 387 fprintf(stderr, "incompatible append\n");
341 } 388 exit(-1);
389 }
390 }
342 391
343 assert(fd[nr_cpu][counter] >= 0); 392 if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) {
344 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 393 perror("Unable to read perf file descriptor");
394 exit(-1);
395 }
345 396
346 /* 397 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
347 * First counter acts as the group leader: 398 pr_warning("Not enough memory to add id\n");
348 */ 399 exit(-1);
349 if (group && group_fd == -1) 400 }
350 group_fd = fd[nr_cpu][counter];
351 if (multiplex && multiplex_fd == -1)
352 multiplex_fd = fd[nr_cpu][counter];
353 401
354 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { 402 assert(FD(evsel, nr_cpu, thread_index) >= 0);
403 fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK);
355 404
356 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); 405 /*
357 assert(ret != -1); 406 * First counter acts as the group leader:
358 } else { 407 */
359 event_array[nr_poll].fd = fd[nr_cpu][counter]; 408 if (group && group_fd == -1)
360 event_array[nr_poll].events = POLLIN; 409 group_fd = FD(evsel, nr_cpu, thread_index);
361 nr_poll++; 410
362 411 if (evsel->idx || thread_index) {
363 mmap_array[nr_cpu][counter].counter = counter; 412 struct perf_evsel *first;
364 mmap_array[nr_cpu][counter].prev = 0; 413 first = list_entry(evsel_list.next, struct perf_evsel, node);
365 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; 414 ret = ioctl(FD(evsel, nr_cpu, thread_index),
366 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, 415 PERF_EVENT_IOC_SET_OUTPUT,
367 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); 416 FD(first, nr_cpu, 0));
368 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { 417 if (ret) {
369 error("failed to mmap with %d (%s)\n", errno, strerror(errno)); 418 error("failed to set output: %d (%s)\n", errno,
370 exit(-1); 419 strerror(errno));
420 exit(-1);
421 }
422 } else {
423 mmap_array[nr_cpu].prev = 0;
424 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
425 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
426 PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0);
427 if (mmap_array[nr_cpu].base == MAP_FAILED) {
428 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
429 exit(-1);
430 }
431
432 event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index);
433 event_array[nr_poll].events = POLLIN;
434 nr_poll++;
371 } 435 }
372 }
373 436
374 if (filter != NULL) { 437 if (filter != NULL) {
375 ret = ioctl(fd[nr_cpu][counter], 438 ret = ioctl(FD(evsel, nr_cpu, thread_index),
376 PERF_EVENT_IOC_SET_FILTER, filter); 439 PERF_EVENT_IOC_SET_FILTER, filter);
377 if (ret) { 440 if (ret) {
378 error("failed to set filter with %d (%s)\n", errno, 441 error("failed to set filter with %d (%s)\n", errno,
379 strerror(errno)); 442 strerror(errno));
380 exit(-1); 443 exit(-1);
444 }
381 } 445 }
382 } 446 }
383 447
384 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); 448 if (!sample_type)
449 sample_type = attr->sample_type;
385} 450}
386 451
387static void open_counters(int cpu, pid_t pid) 452static void open_counters(int cpu)
388{ 453{
389 int counter; 454 struct perf_evsel *pos;
390 455
391 group_fd = -1; 456 group_fd = -1;
392 for (counter = 0; counter < nr_counters; counter++) 457
393 create_counter(counter, cpu, pid); 458 list_for_each_entry(pos, &evsel_list, node)
459 create_counter(pos, cpu);
394 460
395 nr_cpu++; 461 nr_cpu++;
396} 462}
397 463
464static int process_buildids(void)
465{
466 u64 size = lseek(output, 0, SEEK_CUR);
467
468 if (size == 0)
469 return 0;
470
471 session->fd = output;
472 return __perf_session__process_events(session, post_processing_offset,
473 size - post_processing_offset,
474 size, &build_id__mark_dso_hit_ops);
475}
476
398static void atexit_header(void) 477static void atexit_header(void)
399{ 478{
400 session->header.data_size += bytes_written; 479 if (!pipe_output) {
480 session->header.data_size += bytes_written;
481
482 if (!no_buildid)
483 process_buildids();
484 perf_header__write(&session->header, output, true);
485 perf_session__delete(session);
486 perf_evsel_list__delete();
487 symbol__exit();
488 }
489}
490
491static void event__synthesize_guest_os(struct machine *machine, void *data)
492{
493 int err;
494 struct perf_session *psession = data;
495
496 if (machine__is_host(machine))
497 return;
498
499 /*
500 *As for guest kernel when processing subcommand record&report,
501 *we arrange module mmap prior to guest kernel mmap and trigger
502 *a preload dso because default guest module symbols are loaded
503 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
504 *method is used to avoid symbol missing when the first addr is
505 *in module instead of in guest kernel.
506 */
507 err = event__synthesize_modules(process_synthesized_event,
508 psession, machine);
509 if (err < 0)
510 pr_err("Couldn't record guest kernel [%d]'s reference"
511 " relocation symbol.\n", machine->pid);
512
513 /*
514 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
515 * have no _text sometimes.
516 */
517 err = event__synthesize_kernel_mmap(process_synthesized_event,
518 psession, machine, "_text");
519 if (err < 0)
520 err = event__synthesize_kernel_mmap(process_synthesized_event,
521 psession, machine, "_stext");
522 if (err < 0)
523 pr_err("Couldn't record guest kernel [%d]'s reference"
524 " relocation symbol.\n", machine->pid);
525}
526
527static struct perf_event_header finished_round_event = {
528 .size = sizeof(struct perf_event_header),
529 .type = PERF_RECORD_FINISHED_ROUND,
530};
531
532static void mmap_read_all(void)
533{
534 int i;
535
536 for (i = 0; i < nr_cpu; i++) {
537 if (mmap_array[i].base)
538 mmap_read(&mmap_array[i]);
539 }
401 540
402 perf_header__write(&session->header, output, true); 541 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
542 write_output(&finished_round_event, sizeof(finished_round_event));
403} 543}
404 544
405static int __cmd_record(int argc, const char **argv) 545static int __cmd_record(int argc, const char **argv)
406{ 546{
407 int i, counter; 547 int i;
408 struct stat st; 548 struct stat st;
409 pid_t pid = 0;
410 int flags; 549 int flags;
411 int err; 550 int err;
412 unsigned long waking = 0; 551 unsigned long waking = 0;
413 int child_ready_pipe[2], go_pipe[2]; 552 int child_ready_pipe[2], go_pipe[2];
414 const bool forks = target_pid == -1 && argc > 0; 553 const bool forks = argc > 0;
415 char buf; 554 char buf;
555 struct machine *machine;
416 556
417 page_size = sysconf(_SC_PAGE_SIZE); 557 page_size = sysconf(_SC_PAGE_SIZE);
418 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
419 assert(nr_cpus <= MAX_NR_CPUS);
420 assert(nr_cpus >= 0);
421 558
422 atexit(sig_atexit); 559 atexit(sig_atexit);
423 signal(SIGCHLD, sig_handler); 560 signal(SIGCHLD, sig_handler);
424 signal(SIGINT, sig_handler); 561 signal(SIGINT, sig_handler);
562 signal(SIGUSR1, sig_handler);
425 563
426 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { 564 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
427 perror("failed to create pipes"); 565 perror("failed to create pipes");
428 exit(-1); 566 exit(-1);
429 } 567 }
430 568
431 if (!stat(output_name, &st) && st.st_size) { 569 if (!strcmp(output_name, "-"))
432 if (!force) { 570 pipe_output = 1;
433 if (!append_file) { 571 else if (!stat(output_name, &st) && st.st_size) {
434 pr_err("Error, output file %s exists, use -A " 572 if (write_mode == WRITE_FORCE) {
435 "to append or -f to overwrite.\n",
436 output_name);
437 exit(-1);
438 }
439 } else {
440 char oldname[PATH_MAX]; 573 char oldname[PATH_MAX];
441 snprintf(oldname, sizeof(oldname), "%s.old", 574 snprintf(oldname, sizeof(oldname), "%s.old",
442 output_name); 575 output_name);
443 unlink(oldname); 576 unlink(oldname);
444 rename(output_name, oldname); 577 rename(output_name, oldname);
445 } 578 }
446 } else { 579 } else if (write_mode == WRITE_APPEND) {
447 append_file = 0; 580 write_mode = WRITE_FORCE;
448 } 581 }
449 582
450 flags = O_CREAT|O_RDWR; 583 flags = O_CREAT|O_RDWR;
451 if (append_file) 584 if (write_mode == WRITE_APPEND)
452 file_new = 0; 585 file_new = 0;
453 else 586 else
454 flags |= O_TRUNC; 587 flags |= O_TRUNC;
455 588
456 output = open(output_name, flags, S_IRUSR|S_IWUSR); 589 if (pipe_output)
590 output = STDOUT_FILENO;
591 else
592 output = open(output_name, flags, S_IRUSR | S_IWUSR);
457 if (output < 0) { 593 if (output < 0) {
458 perror("failed to create output file"); 594 perror("failed to create output file");
459 exit(-1); 595 exit(-1);
460 } 596 }
461 597
462 session = perf_session__new(output_name, O_WRONLY, force); 598 session = perf_session__new(output_name, O_WRONLY,
599 write_mode == WRITE_FORCE, false, NULL);
463 if (session == NULL) { 600 if (session == NULL) {
464 pr_err("Not enough memory for reading perf file header\n"); 601 pr_err("Not enough memory for reading perf file header\n");
465 return -1; 602 return -1;
466 } 603 }
467 604
605 if (!no_buildid)
606 perf_header__set_feat(&session->header, HEADER_BUILD_ID);
607
468 if (!file_new) { 608 if (!file_new) {
469 err = perf_header__read(&session->header, output); 609 err = perf_header__read(session, output);
470 if (err < 0) 610 if (err < 0)
471 return err; 611 goto out_delete_session;
472 } 612 }
473 613
474 if (raw_samples) { 614 if (have_tracepoints(&evsel_list))
475 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 615 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
476 } else {
477 for (i = 0; i < nr_counters; i++) {
478 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
479 perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
480 break;
481 }
482 }
483 }
484 616
617 /*
618 * perf_session__delete(session) will be called at atexit_header()
619 */
485 atexit(atexit_header); 620 atexit(atexit_header);
486 621
487 if (forks) { 622 if (forks) {
488 pid = fork(); 623 child_pid = fork();
489 if (pid < 0) { 624 if (child_pid < 0) {
490 perror("failed to fork"); 625 perror("failed to fork");
491 exit(-1); 626 exit(-1);
492 } 627 }
493 628
494 if (!pid) { 629 if (!child_pid) {
630 if (pipe_output)
631 dup2(2, 1);
495 close(child_ready_pipe[0]); 632 close(child_ready_pipe[0]);
496 close(go_pipe[1]); 633 close(go_pipe[1]);
497 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 634 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
@@ -517,13 +654,12 @@ static int __cmd_record(int argc, const char **argv)
517 execvp(argv[0], (char **)argv); 654 execvp(argv[0], (char **)argv);
518 655
519 perror(argv[0]); 656 perror(argv[0]);
657 kill(getppid(), SIGUSR1);
520 exit(-1); 658 exit(-1);
521 } 659 }
522 660
523 child_pid = pid; 661 if (!system_wide && target_tid == -1 && target_pid == -1)
524 662 threads->map[0] = child_pid;
525 if (!system_wide)
526 target_pid = pid;
527 663
528 close(child_ready_pipe[1]); 664 close(child_ready_pipe[1]);
529 close(go_pipe[0]); 665 close(go_pipe[0]);
@@ -537,22 +673,93 @@ static int __cmd_record(int argc, const char **argv)
537 close(child_ready_pipe[0]); 673 close(child_ready_pipe[0]);
538 } 674 }
539 675
540 676 if (!system_wide && no_inherit && !cpu_list) {
541 if ((!system_wide && !inherit) || profile_cpu != -1) { 677 open_counters(-1);
542 open_counters(profile_cpu, target_pid);
543 } else { 678 } else {
544 for (i = 0; i < nr_cpus; i++) 679 for (i = 0; i < cpus->nr; i++)
545 open_counters(i, target_pid); 680 open_counters(cpus->map[i]);
546 } 681 }
547 682
548 if (file_new) { 683 perf_session__set_sample_type(session, sample_type);
684
685 if (pipe_output) {
686 err = perf_header__write_pipe(output);
687 if (err < 0)
688 return err;
689 } else if (file_new) {
549 err = perf_header__write(&session->header, output, false); 690 err = perf_header__write(&session->header, output, false);
550 if (err < 0) 691 if (err < 0)
551 return err; 692 return err;
552 } 693 }
553 694
554 if (!system_wide && profile_cpu == -1) 695 post_processing_offset = lseek(output, 0, SEEK_CUR);
555 event__synthesize_thread(pid, process_synthesized_event, 696
697 perf_session__set_sample_id_all(session, sample_id_all_avail);
698
699 if (pipe_output) {
700 err = event__synthesize_attrs(&session->header,
701 process_synthesized_event,
702 session);
703 if (err < 0) {
704 pr_err("Couldn't synthesize attrs.\n");
705 return err;
706 }
707
708 err = event__synthesize_event_types(process_synthesized_event,
709 session);
710 if (err < 0) {
711 pr_err("Couldn't synthesize event_types.\n");
712 return err;
713 }
714
715 if (have_tracepoints(&evsel_list)) {
716 /*
717 * FIXME err <= 0 here actually means that
718 * there were no tracepoints so its not really
719 * an error, just that we don't need to
720 * synthesize anything. We really have to
721 * return this more properly and also
722 * propagate errors that now are calling die()
723 */
724 err = event__synthesize_tracing_data(output, &evsel_list,
725 process_synthesized_event,
726 session);
727 if (err <= 0) {
728 pr_err("Couldn't record tracing data.\n");
729 return err;
730 }
731 advance_output(err);
732 }
733 }
734
735 machine = perf_session__find_host_machine(session);
736 if (!machine) {
737 pr_err("Couldn't find native kernel information.\n");
738 return -1;
739 }
740
741 err = event__synthesize_kernel_mmap(process_synthesized_event,
742 session, machine, "_text");
743 if (err < 0)
744 err = event__synthesize_kernel_mmap(process_synthesized_event,
745 session, machine, "_stext");
746 if (err < 0)
747 pr_err("Couldn't record kernel reference relocation symbol\n"
748 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
749 "Check /proc/kallsyms permission or run as root.\n");
750
751 err = event__synthesize_modules(process_synthesized_event,
752 session, machine);
753 if (err < 0)
754 pr_err("Couldn't record kernel module information.\n"
755 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
756 "Check /proc/modules permission or run as root.\n");
757
758 if (perf_guest)
759 perf_session__process_machines(session, event__synthesize_guest_os);
760
761 if (!system_wide)
762 event__synthesize_thread(target_tid, process_synthesized_event,
556 session); 763 session);
557 else 764 else
558 event__synthesize_threads(process_synthesized_event, session); 765 event__synthesize_threads(process_synthesized_event, session);
@@ -575,13 +782,9 @@ static int __cmd_record(int argc, const char **argv)
575 782
576 for (;;) { 783 for (;;) {
577 int hits = samples; 784 int hits = samples;
785 int thread;
578 786
579 for (i = 0; i < nr_cpu; i++) { 787 mmap_read_all();
580 for (counter = 0; counter < nr_counters; counter++) {
581 if (mmap_array[i][counter].base)
582 mmap_read(&mmap_array[i][counter]);
583 }
584 }
585 788
586 if (hits == samples) { 789 if (hits == samples) {
587 if (done) 790 if (done)
@@ -592,12 +795,22 @@ static int __cmd_record(int argc, const char **argv)
592 795
593 if (done) { 796 if (done) {
594 for (i = 0; i < nr_cpu; i++) { 797 for (i = 0; i < nr_cpu; i++) {
595 for (counter = 0; counter < nr_counters; counter++) 798 struct perf_evsel *pos;
596 ioctl(fd[i][counter], PERF_EVENT_IOC_DISABLE); 799
800 list_for_each_entry(pos, &evsel_list, node) {
801 for (thread = 0;
802 thread < threads->nr;
803 thread++)
804 ioctl(FD(pos, i, thread),
805 PERF_EVENT_IOC_DISABLE);
806 }
597 } 807 }
598 } 808 }
599 } 809 }
600 810
811 if (quiet || signr == SIGUSR1)
812 return 0;
813
601 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking); 814 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
602 815
603 /* 816 /*
@@ -610,6 +823,10 @@ static int __cmd_record(int argc, const char **argv)
610 bytes_written / 24); 823 bytes_written / 24);
611 824
612 return 0; 825 return 0;
826
827out_delete_session:
828 perf_session__delete(session);
829 return err;
613} 830}
614 831
615static const char * const record_usage[] = { 832static const char * const record_usage[] = {
@@ -618,68 +835,120 @@ static const char * const record_usage[] = {
618 NULL 835 NULL
619}; 836};
620 837
621static const struct option options[] = { 838static bool force, append_file;
839
840const struct option record_options[] = {
622 OPT_CALLBACK('e', "event", NULL, "event", 841 OPT_CALLBACK('e', "event", NULL, "event",
623 "event selector. use 'perf list' to list available events", 842 "event selector. use 'perf list' to list available events",
624 parse_events), 843 parse_events),
625 OPT_CALLBACK(0, "filter", NULL, "filter", 844 OPT_CALLBACK(0, "filter", NULL, "filter",
626 "event filter", parse_filter), 845 "event filter", parse_filter),
627 OPT_INTEGER('p', "pid", &target_pid, 846 OPT_INTEGER('p', "pid", &target_pid,
628 "record events on existing pid"), 847 "record events on existing process id"),
848 OPT_INTEGER('t', "tid", &target_tid,
849 "record events on existing thread id"),
629 OPT_INTEGER('r', "realtime", &realtime_prio, 850 OPT_INTEGER('r', "realtime", &realtime_prio,
630 "collect data with this RT SCHED_FIFO priority"), 851 "collect data with this RT SCHED_FIFO priority"),
852 OPT_BOOLEAN('D', "no-delay", &nodelay,
853 "collect data without buffering"),
631 OPT_BOOLEAN('R', "raw-samples", &raw_samples, 854 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
632 "collect raw sample records from all opened counters"), 855 "collect raw sample records from all opened counters"),
633 OPT_BOOLEAN('a', "all-cpus", &system_wide, 856 OPT_BOOLEAN('a', "all-cpus", &system_wide,
634 "system-wide collection from all CPUs"), 857 "system-wide collection from all CPUs"),
635 OPT_BOOLEAN('A', "append", &append_file, 858 OPT_BOOLEAN('A', "append", &append_file,
636 "append to the output file to do incremental profiling"), 859 "append to the output file to do incremental profiling"),
637 OPT_INTEGER('C', "profile_cpu", &profile_cpu, 860 OPT_STRING('C', "cpu", &cpu_list, "cpu",
638 "CPU to profile on"), 861 "list of cpus to monitor"),
639 OPT_BOOLEAN('f', "force", &force, 862 OPT_BOOLEAN('f', "force", &force,
640 "overwrite existing data file"), 863 "overwrite existing data file (deprecated)"),
641 OPT_LONG('c', "count", &default_interval, 864 OPT_U64('c', "count", &user_interval, "event period to sample"),
642 "event period to sample"),
643 OPT_STRING('o', "output", &output_name, "file", 865 OPT_STRING('o', "output", &output_name, "file",
644 "output file name"), 866 "output file name"),
645 OPT_BOOLEAN('i', "inherit", &inherit, 867 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
646 "child tasks inherit counters"), 868 "child tasks do not inherit counters"),
647 OPT_INTEGER('F', "freq", &freq, 869 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
648 "profile at this frequency"), 870 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
649 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
650 "number of mmap data pages"),
651 OPT_BOOLEAN('g', "call-graph", &call_graph, 871 OPT_BOOLEAN('g', "call-graph", &call_graph,
652 "do call-graph (stack chain/backtrace) recording"), 872 "do call-graph (stack chain/backtrace) recording"),
653 OPT_BOOLEAN('v', "verbose", &verbose, 873 OPT_INCR('v', "verbose", &verbose,
654 "be more verbose (show counter open errors, etc)"), 874 "be more verbose (show counter open errors, etc)"),
875 OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
655 OPT_BOOLEAN('s', "stat", &inherit_stat, 876 OPT_BOOLEAN('s', "stat", &inherit_stat,
656 "per thread counts"), 877 "per thread counts"),
657 OPT_BOOLEAN('d', "data", &sample_address, 878 OPT_BOOLEAN('d', "data", &sample_address,
658 "Sample addresses"), 879 "Sample addresses"),
880 OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
659 OPT_BOOLEAN('n', "no-samples", &no_samples, 881 OPT_BOOLEAN('n', "no-samples", &no_samples,
660 "don't sample"), 882 "don't sample"),
661 OPT_BOOLEAN('M', "multiplex", &multiplex, 883 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
662 "multiplex counter output in a single channel"), 884 "do not update the buildid cache"),
885 OPT_BOOLEAN('B', "no-buildid", &no_buildid,
886 "do not collect buildids in perf.data"),
663 OPT_END() 887 OPT_END()
664}; 888};
665 889
666int cmd_record(int argc, const char **argv, const char *prefix __used) 890int cmd_record(int argc, const char **argv, const char *prefix __used)
667{ 891{
668 int counter; 892 int err = -ENOMEM;
893 struct perf_evsel *pos;
669 894
670 argc = parse_options(argc, argv, options, record_usage, 895 argc = parse_options(argc, argv, record_options, record_usage,
671 PARSE_OPT_STOP_AT_NON_OPTION); 896 PARSE_OPT_STOP_AT_NON_OPTION);
672 if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1) 897 if (!argc && target_pid == -1 && target_tid == -1 &&
673 usage_with_options(record_usage, options); 898 !system_wide && !cpu_list)
899 usage_with_options(record_usage, record_options);
900
901 if (force && append_file) {
902 fprintf(stderr, "Can't overwrite and append at the same time."
903 " You need to choose between -f and -A");
904 usage_with_options(record_usage, record_options);
905 } else if (append_file) {
906 write_mode = WRITE_APPEND;
907 } else {
908 write_mode = WRITE_FORCE;
909 }
674 910
675 symbol__init(); 911 symbol__init();
676 912
677 if (!nr_counters) { 913 if (no_buildid_cache || no_buildid)
678 nr_counters = 1; 914 disable_buildid_cache();
679 attrs[0].type = PERF_TYPE_HARDWARE; 915
680 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 916 if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) {
917 pr_err("Not enough memory for event selector list\n");
918 goto out_symbol_exit;
681 } 919 }
682 920
921 if (target_pid != -1)
922 target_tid = target_pid;
923
924 threads = thread_map__new(target_pid, target_tid);
925 if (threads == NULL) {
926 pr_err("Problems finding threads of monitor\n");
927 usage_with_options(record_usage, record_options);
928 }
929
930 cpus = cpu_map__new(cpu_list);
931 if (cpus == NULL) {
932 perror("failed to parse CPUs map");
933 return -1;
934 }
935
936 list_for_each_entry(pos, &evsel_list, node) {
937 if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
938 goto out_free_fd;
939 if (perf_header__push_event(pos->attr.config, event_name(pos)))
940 goto out_free_fd;
941 }
942 event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS *
943 MAX_COUNTERS * threads->nr));
944 if (!event_array)
945 goto out_free_fd;
946
947 if (user_interval != ULLONG_MAX)
948 default_interval = user_interval;
949 if (user_freq != UINT_MAX)
950 freq = user_freq;
951
683 /* 952 /*
684 * User specified count overrides default frequency. 953 * User specified count overrides default frequency.
685 */ 954 */
@@ -689,15 +958,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
689 default_interval = freq; 958 default_interval = freq;
690 } else { 959 } else {
691 fprintf(stderr, "frequency and count are zero, aborting\n"); 960 fprintf(stderr, "frequency and count are zero, aborting\n");
692 exit(EXIT_FAILURE); 961 err = -EINVAL;
962 goto out_free_event_array;
693 } 963 }
694 964
695 for (counter = 0; counter < nr_counters; counter++) { 965 err = __cmd_record(argc, argv);
696 if (attrs[counter].sample_period)
697 continue;
698
699 attrs[counter].sample_period = default_interval;
700 }
701 966
702 return __cmd_record(argc, argv); 967out_free_event_array:
968 free(event_array);
969out_free_fd:
970 thread_map__delete(threads);
971 threads = NULL;
972out_symbol_exit:
973 symbol__exit();
974 return err;
703} 975}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index db10c0e8ecae..75183a4518e6 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -14,7 +14,6 @@
14#include "util/cache.h" 14#include "util/cache.h"
15#include <linux/rbtree.h> 15#include <linux/rbtree.h>
16#include "util/symbol.h" 16#include "util/symbol.h"
17#include "util/string.h"
18#include "util/callchain.h" 17#include "util/callchain.h"
19#include "util/strlist.h" 18#include "util/strlist.h"
20#include "util/values.h" 19#include "util/values.h"
@@ -33,107 +32,156 @@
33 32
34static char const *input_name = "perf.data"; 33static char const *input_name = "perf.data";
35 34
36static int force; 35static bool force, use_tui, use_stdio;
36static bool hide_unresolved;
37static bool dont_use_callchains;
37 38
38static int show_threads; 39static bool show_threads;
39static struct perf_read_values show_threads_values; 40static struct perf_read_values show_threads_values;
40 41
41static char default_pretty_printing_style[] = "normal"; 42static const char default_pretty_printing_style[] = "normal";
42static char *pretty_printing_style = default_pretty_printing_style; 43static const char *pretty_printing_style = default_pretty_printing_style;
43 44
44static char callchain_default_opt[] = "fractal,0.5"; 45static char callchain_default_opt[] = "fractal,0.5";
45 46
47static struct hists *perf_session__hists_findnew(struct perf_session *self,
48 u64 event_stream, u32 type,
49 u64 config)
50{
51 struct rb_node **p = &self->hists_tree.rb_node;
52 struct rb_node *parent = NULL;
53 struct hists *iter, *new;
54
55 while (*p != NULL) {
56 parent = *p;
57 iter = rb_entry(parent, struct hists, rb_node);
58 if (iter->config == config)
59 return iter;
60
61
62 if (config > iter->config)
63 p = &(*p)->rb_right;
64 else
65 p = &(*p)->rb_left;
66 }
67
68 new = malloc(sizeof(struct hists));
69 if (new == NULL)
70 return NULL;
71 memset(new, 0, sizeof(struct hists));
72 new->event_stream = event_stream;
73 new->config = config;
74 new->type = type;
75 rb_link_node(&new->rb_node, parent, p);
76 rb_insert_color(&new->rb_node, &self->hists_tree);
77 return new;
78}
79
46static int perf_session__add_hist_entry(struct perf_session *self, 80static int perf_session__add_hist_entry(struct perf_session *self,
47 struct addr_location *al, 81 struct addr_location *al,
48 struct ip_callchain *chain, u64 count) 82 struct sample_data *data)
49{ 83{
50 struct symbol **syms = NULL, *parent = NULL; 84 struct map_symbol *syms = NULL;
51 bool hit; 85 struct symbol *parent = NULL;
86 int err = -ENOMEM;
52 struct hist_entry *he; 87 struct hist_entry *he;
88 struct hists *hists;
89 struct perf_event_attr *attr;
53 90
54 if ((sort__has_parent || symbol_conf.use_callchain) && chain) 91 if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
55 syms = perf_session__resolve_callchain(self, al->thread, 92 syms = perf_session__resolve_callchain(self, al->thread,
56 chain, &parent); 93 data->callchain, &parent);
57 he = __perf_session__add_hist_entry(self, al, parent, count, &hit); 94 if (syms == NULL)
58 if (he == NULL) 95 return -ENOMEM;
59 return -ENOMEM; 96 }
60
61 if (hit)
62 he->count += count;
63 97
98 attr = perf_header__find_attr(data->id, &self->header);
99 if (attr)
100 hists = perf_session__hists_findnew(self, data->id, attr->type, attr->config);
101 else
102 hists = perf_session__hists_findnew(self, data->id, 0, 0);
103 if (hists == NULL)
104 goto out_free_syms;
105 he = __hists__add_entry(hists, al, parent, data->period);
106 if (he == NULL)
107 goto out_free_syms;
108 err = 0;
64 if (symbol_conf.use_callchain) { 109 if (symbol_conf.use_callchain) {
65 if (!hit) 110 err = callchain_append(he->callchain, data->callchain, syms,
66 callchain_init(&he->callchain); 111 data->period);
67 append_chain(&he->callchain, chain, syms); 112 if (err)
68 free(syms); 113 goto out_free_syms;
69 } 114 }
70 115 /*
71 return 0; 116 * Only in the newt browser we are doing integrated annotation,
117 * so we don't allocated the extra space needed because the stdio
118 * code will not use it.
119 */
120 if (use_browser > 0)
121 err = hist_entry__inc_addr_samples(he, al->addr);
122out_free_syms:
123 free(syms);
124 return err;
72} 125}
73 126
74static int validate_chain(struct ip_callchain *chain, event_t *event) 127static int add_event_total(struct perf_session *session,
128 struct sample_data *data,
129 struct perf_event_attr *attr)
75{ 130{
76 unsigned int chain_size; 131 struct hists *hists;
77 132
78 chain_size = event->header.size; 133 if (attr)
79 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; 134 hists = perf_session__hists_findnew(session, data->id,
135 attr->type, attr->config);
136 else
137 hists = perf_session__hists_findnew(session, data->id, 0, 0);
80 138
81 if (chain->nr*sizeof(u64) > chain_size) 139 if (!hists)
82 return -1; 140 return -ENOMEM;
83 141
142 hists->stats.total_period += data->period;
143 /*
144 * FIXME: add_event_total should be moved from here to
145 * perf_session__process_event so that the proper hist is passed to
146 * the event_op methods.
147 */
148 hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
149 session->hists.stats.total_period += data->period;
84 return 0; 150 return 0;
85} 151}
86 152
87static int process_sample_event(event_t *event, struct perf_session *session) 153static int process_sample_event(event_t *event, struct sample_data *sample,
154 struct perf_session *session)
88{ 155{
89 struct sample_data data = { .period = 1, };
90 struct addr_location al; 156 struct addr_location al;
157 struct perf_event_attr *attr;
91 158
92 event__parse_sample(event, session->sample_type, &data); 159 if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
93
94 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
95 event->header.misc,
96 data.pid, data.tid,
97 (void *)(long)data.ip,
98 (long long)data.period);
99
100 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
101 unsigned int i;
102
103 dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
104
105 if (validate_chain(data.callchain, event) < 0) {
106 pr_debug("call-chain problem with event, "
107 "skipping it.\n");
108 return 0;
109 }
110
111 if (dump_trace) {
112 for (i = 0; i < data.callchain->nr; i++)
113 dump_printf("..... %2d: %016Lx\n",
114 i, data.callchain->ips[i]);
115 }
116 }
117
118 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
119 fprintf(stderr, "problem processing %d event, skipping it.\n", 160 fprintf(stderr, "problem processing %d event, skipping it.\n",
120 event->header.type); 161 event->header.type);
121 return -1; 162 return -1;
122 } 163 }
123 164
124 if (al.filtered) 165 if (al.filtered || (hide_unresolved && al.sym == NULL))
125 return 0; 166 return 0;
126 167
127 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { 168 if (perf_session__add_hist_entry(session, &al, sample)) {
128 pr_debug("problem incrementing symbol count, skipping event\n"); 169 pr_debug("problem incrementing symbol period, skipping event\n");
170 return -1;
171 }
172
173 attr = perf_header__find_attr(sample->id, &session->header);
174
175 if (add_event_total(session, sample, attr)) {
176 pr_debug("problem adding event period\n");
129 return -1; 177 return -1;
130 } 178 }
131 179
132 session->events_stats.total += data.period;
133 return 0; 180 return 0;
134} 181}
135 182
136static int process_read_event(event_t *event, struct perf_session *session __used) 183static int process_read_event(event_t *event, struct sample_data *sample __used,
184 struct perf_session *session __used)
137{ 185{
138 struct perf_event_attr *attr; 186 struct perf_event_attr *attr;
139 187
@@ -156,14 +204,14 @@ static int process_read_event(event_t *event, struct perf_session *session __use
156 return 0; 204 return 0;
157} 205}
158 206
159static int sample_type_check(struct perf_session *session) 207static int perf_session__setup_sample_type(struct perf_session *self)
160{ 208{
161 if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) { 209 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
162 if (sort__has_parent) { 210 if (sort__has_parent) {
163 fprintf(stderr, "selected --sort parent, but no" 211 fprintf(stderr, "selected --sort parent, but no"
164 " callchain data. Did you call" 212 " callchain data. Did you call"
165 " perf record without -g?\n"); 213 " perf record without -g?\n");
166 return -1; 214 return -EINVAL;
167 } 215 }
168 if (symbol_conf.use_callchain) { 216 if (symbol_conf.use_callchain) {
169 fprintf(stderr, "selected -g but no callchain data." 217 fprintf(stderr, "selected -g but no callchain data."
@@ -171,12 +219,13 @@ static int sample_type_check(struct perf_session *session)
171 " -g?\n"); 219 " -g?\n");
172 return -1; 220 return -1;
173 } 221 }
174 } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { 222 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
223 !symbol_conf.use_callchain) {
175 symbol_conf.use_callchain = true; 224 symbol_conf.use_callchain = true;
176 if (register_callchain_param(&callchain_param) < 0) { 225 if (register_callchain_param(&callchain_param) < 0) {
177 fprintf(stderr, "Can't register callchain" 226 fprintf(stderr, "Can't register callchain"
178 " params\n"); 227 " params\n");
179 return -1; 228 return -EINVAL;
180 } 229 }
181 } 230 }
182 231
@@ -184,35 +233,100 @@ static int sample_type_check(struct perf_session *session)
184} 233}
185 234
186static struct perf_event_ops event_ops = { 235static struct perf_event_ops event_ops = {
187 .process_sample_event = process_sample_event, 236 .sample = process_sample_event,
188 .process_mmap_event = event__process_mmap, 237 .mmap = event__process_mmap,
189 .process_comm_event = event__process_comm, 238 .comm = event__process_comm,
190 .process_exit_event = event__process_task, 239 .exit = event__process_task,
191 .process_fork_event = event__process_task, 240 .fork = event__process_task,
192 .process_lost_event = event__process_lost, 241 .lost = event__process_lost,
193 .process_read_event = process_read_event, 242 .read = process_read_event,
194 .sample_type_check = sample_type_check, 243 .attr = event__process_attr,
244 .event_type = event__process_event_type,
245 .tracing_data = event__process_tracing_data,
246 .build_id = event__process_build_id,
247 .ordered_samples = true,
248 .ordering_requires_timestamps = true,
195}; 249};
196 250
251extern volatile int session_done;
252
253static void sig_handler(int sig __used)
254{
255 session_done = 1;
256}
257
258static size_t hists__fprintf_nr_sample_events(struct hists *self,
259 const char *evname, FILE *fp)
260{
261 size_t ret;
262 char unit;
263 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
264
265 nr_events = convert_unit(nr_events, &unit);
266 ret = fprintf(fp, "# Events: %lu%c", nr_events, unit);
267 if (evname != NULL)
268 ret += fprintf(fp, " %s", evname);
269 return ret + fprintf(fp, "\n#\n");
270}
271
272static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
273{
274 struct rb_node *next = rb_first(tree);
275
276 while (next) {
277 struct hists *hists = rb_entry(next, struct hists, rb_node);
278 const char *evname = NULL;
279
280 if (rb_first(&hists->entries) != rb_last(&hists->entries))
281 evname = __event_name(hists->type, hists->config);
282
283 hists__fprintf_nr_sample_events(hists, evname, stdout);
284 hists__fprintf(hists, NULL, false, stdout);
285 fprintf(stdout, "\n\n");
286 next = rb_next(&hists->rb_node);
287 }
288
289 if (sort_order == default_sort_order &&
290 parent_pattern == default_parent_pattern) {
291 fprintf(stdout, "#\n# (%s)\n#\n", help);
292
293 if (show_threads) {
294 bool style = !strcmp(pretty_printing_style, "raw");
295 perf_read_values_display(stdout, &show_threads_values,
296 style);
297 perf_read_values_destroy(&show_threads_values);
298 }
299 }
300
301 return 0;
302}
197 303
198static int __cmd_report(void) 304static int __cmd_report(void)
199{ 305{
200 int ret; 306 int ret = -EINVAL;
201 struct perf_session *session; 307 struct perf_session *session;
308 struct rb_node *next;
309 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
202 310
203 session = perf_session__new(input_name, O_RDONLY, force); 311 signal(SIGINT, sig_handler);
312
313 session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
204 if (session == NULL) 314 if (session == NULL)
205 return -ENOMEM; 315 return -ENOMEM;
206 316
207 if (show_threads) 317 if (show_threads)
208 perf_read_values_init(&show_threads_values); 318 perf_read_values_init(&show_threads_values);
209 319
320 ret = perf_session__setup_sample_type(session);
321 if (ret)
322 goto out_delete;
323
210 ret = perf_session__process_events(session, &event_ops); 324 ret = perf_session__process_events(session, &event_ops);
211 if (ret) 325 if (ret)
212 goto out_delete; 326 goto out_delete;
213 327
214 if (dump_trace) { 328 if (dump_trace) {
215 event__print_totals(); 329 perf_session__fprintf_nr_events(session, stdout);
216 goto out_delete; 330 goto out_delete;
217 } 331 }
218 332
@@ -220,34 +334,54 @@ static int __cmd_report(void)
220 perf_session__fprintf(session, stdout); 334 perf_session__fprintf(session, stdout);
221 335
222 if (verbose > 2) 336 if (verbose > 2)
223 dsos__fprintf(stdout); 337 perf_session__fprintf_dsos(session, stdout);
224 338
225 perf_session__collapse_resort(session); 339 next = rb_first(&session->hists_tree);
226 perf_session__output_resort(session, session->events_stats.total); 340 while (next) {
227 fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total); 341 struct hists *hists;
228 perf_session__fprintf_hists(session, NULL, false, stdout);
229 if (sort_order == default_sort_order &&
230 parent_pattern == default_parent_pattern)
231 fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n");
232 342
233 if (show_threads) { 343 hists = rb_entry(next, struct hists, rb_node);
234 bool raw_printing_style = !strcmp(pretty_printing_style, "raw"); 344 hists__collapse_resort(hists);
235 perf_read_values_display(stdout, &show_threads_values, 345 hists__output_resort(hists);
236 raw_printing_style); 346 next = rb_next(&hists->rb_node);
237 perf_read_values_destroy(&show_threads_values);
238 } 347 }
348
349 if (use_browser > 0)
350 hists__tui_browse_tree(&session->hists_tree, help);
351 else
352 hists__tty_browse_tree(&session->hists_tree, help);
353
239out_delete: 354out_delete:
240 perf_session__delete(session); 355 /*
356 * Speed up the exit process, for large files this can
357 * take quite a while.
358 *
359 * XXX Enable this when using valgrind or if we ever
360 * librarize this command.
361 *
362 * Also experiment with obstacks to see how much speed
363 * up we'll get here.
364 *
365 * perf_session__delete(session);
366 */
241 return ret; 367 return ret;
242} 368}
243 369
244static int 370static int
245parse_callchain_opt(const struct option *opt __used, const char *arg, 371parse_callchain_opt(const struct option *opt __used, const char *arg,
246 int unset __used) 372 int unset)
247{ 373{
248 char *tok; 374 char *tok, *tok2;
249 char *endptr; 375 char *endptr;
250 376
377 /*
378 * --no-call-graph
379 */
380 if (unset) {
381 dont_use_callchains = true;
382 return 0;
383 }
384
251 symbol_conf.use_callchain = true; 385 symbol_conf.use_callchain = true;
252 386
253 if (!arg) 387 if (!arg)
@@ -269,7 +403,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
269 403
270 else if (!strncmp(tok, "none", strlen(arg))) { 404 else if (!strncmp(tok, "none", strlen(arg))) {
271 callchain_param.mode = CHAIN_NONE; 405 callchain_param.mode = CHAIN_NONE;
272 symbol_conf.use_callchain = true; 406 symbol_conf.use_callchain = false;
273 407
274 return 0; 408 return 0;
275 } 409 }
@@ -282,10 +416,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
282 if (!tok) 416 if (!tok)
283 goto setup; 417 goto setup;
284 418
419 tok2 = strtok(NULL, ",");
285 callchain_param.min_percent = strtod(tok, &endptr); 420 callchain_param.min_percent = strtod(tok, &endptr);
286 if (tok == endptr) 421 if (tok == endptr)
287 return -1; 422 return -1;
288 423
424 if (tok2)
425 callchain_param.print_limit = strtod(tok2, &endptr);
289setup: 426setup:
290 if (register_callchain_param(&callchain_param) < 0) { 427 if (register_callchain_param(&callchain_param) < 0) {
291 fprintf(stderr, "Can't register callchain params\n"); 428 fprintf(stderr, "Can't register callchain params\n");
@@ -302,12 +439,14 @@ static const char * const report_usage[] = {
302static const struct option options[] = { 439static const struct option options[] = {
303 OPT_STRING('i', "input", &input_name, "file", 440 OPT_STRING('i', "input", &input_name, "file",
304 "input file name"), 441 "input file name"),
305 OPT_BOOLEAN('v', "verbose", &verbose, 442 OPT_INCR('v', "verbose", &verbose,
306 "be more verbose (show symbol address, etc)"), 443 "be more verbose (show symbol address, etc)"),
307 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 444 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
308 "dump raw trace in ASCII"), 445 "dump raw trace in ASCII"),
309 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 446 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
310 "file", "vmlinux pathname"), 447 "file", "vmlinux pathname"),
448 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
449 "file", "kallsyms pathname"),
311 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 450 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
312 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 451 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
313 "load module symbols - WARNING: use only with -k and LIVE kernel"), 452 "load module symbols - WARNING: use only with -k and LIVE kernel"),
@@ -317,16 +456,18 @@ static const struct option options[] = {
317 "Show per-thread event counters"), 456 "Show per-thread event counters"),
318 OPT_STRING(0, "pretty", &pretty_printing_style, "key", 457 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
319 "pretty printing style key: normal raw"), 458 "pretty printing style key: normal raw"),
459 OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
460 OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
320 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 461 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
321 "sort by key(s): pid, comm, dso, symbol, parent"), 462 "sort by key(s): pid, comm, dso, symbol, parent"),
322 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, 463 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
323 "Don't shorten the pathnames taking into account the cwd"), 464 "Show sample percentage for different cpu modes"),
324 OPT_STRING('p', "parent", &parent_pattern, "regex", 465 OPT_STRING('p', "parent", &parent_pattern, "regex",
325 "regex filter to identify parent, see: '--sort parent'"), 466 "regex filter to identify parent, see: '--sort parent'"),
326 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 467 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
327 "Only display entries with parent-match"), 468 "Only display entries with parent-match"),
328 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 469 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
329 "Display callchains using output_type and min percent threshold. " 470 "Display callchains using output_type (graph, flat, fractal, or none) and min percent threshold. "
330 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), 471 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
331 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 472 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
332 "only consider symbols in these dsos"), 473 "only consider symbols in these dsos"),
@@ -340,6 +481,10 @@ static const struct option options[] = {
340 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 481 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
341 "separator for columns, no spaces will be added between " 482 "separator for columns, no spaces will be added between "
342 "columns '.' is reserved."), 483 "columns '.' is reserved."),
484 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
485 "Only display entries resolved to a symbol"),
486 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
487 "Look for files with symbols relative to this directory"),
343 OPT_END() 488 OPT_END()
344}; 489};
345 490
@@ -347,7 +492,38 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
347{ 492{
348 argc = parse_options(argc, argv, options, report_usage, 0); 493 argc = parse_options(argc, argv, options, report_usage, 0);
349 494
350 setup_pager(); 495 if (use_stdio)
496 use_browser = 0;
497 else if (use_tui)
498 use_browser = 1;
499
500 if (strcmp(input_name, "-") != 0)
501 setup_browser();
502 else
503 use_browser = 0;
504 /*
505 * Only in the newt browser we are doing integrated annotation,
506 * so don't allocate extra space that won't be used in the stdio
507 * implementation.
508 */
509 if (use_browser > 0) {
510 symbol_conf.priv_size = sizeof(struct sym_priv);
511 /*
512 * For searching by name on the "Browse map details".
513 * providing it only in verbose mode not to bloat too
514 * much struct symbol.
515 */
516 if (verbose) {
517 /*
518 * XXX: Need to provide a less kludgy way to ask for
519 * more space per symbol, the u32 is for the index on
520 * the ui browser.
521 * See symbol__browser_index.
522 */
523 symbol_conf.priv_size += sizeof(u32);
524 symbol_conf.sort_by_name = true;
525 }
526 }
351 527
352 if (symbol__init() < 0) 528 if (symbol__init() < 0)
353 return -1; 529 return -1;
@@ -355,7 +531,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
355 setup_sorting(report_usage, options); 531 setup_sorting(report_usage, options);
356 532
357 if (parent_pattern != default_parent_pattern) { 533 if (parent_pattern != default_parent_pattern) {
358 sort_dimension__add("parent"); 534 if (sort_dimension__add("parent") < 0)
535 return -1;
359 sort_parent.elide = 1; 536 sort_parent.elide = 1;
360 } else 537 } else
361 symbol_conf.exclude_other = false; 538 symbol_conf.exclude_other = false;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 80209df6cfe8..29e7ffd85690 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -22,7 +22,7 @@
22static char const *input_name = "perf.data"; 22static char const *input_name = "perf.data";
23 23
24static char default_sort_order[] = "avg, max, switch, runtime"; 24static char default_sort_order[] = "avg, max, switch, runtime";
25static char *sort_order = default_sort_order; 25static const char *sort_order = default_sort_order;
26 26
27static int profile_cpu = -1; 27static int profile_cpu = -1;
28 28
@@ -68,10 +68,10 @@ enum sched_event_type {
68 68
69struct sched_atom { 69struct sched_atom {
70 enum sched_event_type type; 70 enum sched_event_type type;
71 int specific_wait;
71 u64 timestamp; 72 u64 timestamp;
72 u64 duration; 73 u64 duration;
73 unsigned long nr; 74 unsigned long nr;
74 int specific_wait;
75 sem_t *wait_sem; 75 sem_t *wait_sem;
76 struct task_desc *wakee; 76 struct task_desc *wakee;
77}; 77};
@@ -105,7 +105,7 @@ static u64 sum_runtime;
105static u64 sum_fluct; 105static u64 sum_fluct;
106static u64 run_avg; 106static u64 run_avg;
107 107
108static unsigned long replay_repeat = 10; 108static unsigned int replay_repeat = 10;
109static unsigned long nr_timestamps; 109static unsigned long nr_timestamps;
110static unsigned long nr_unordered_timestamps; 110static unsigned long nr_unordered_timestamps;
111static unsigned long nr_state_machine_bugs; 111static unsigned long nr_state_machine_bugs;
@@ -489,7 +489,8 @@ static void create_tasks(void)
489 489
490 err = pthread_attr_init(&attr); 490 err = pthread_attr_init(&attr);
491 BUG_ON(err); 491 BUG_ON(err);
492 err = pthread_attr_setstacksize(&attr, (size_t)(16*1024)); 492 err = pthread_attr_setstacksize(&attr,
493 (size_t) max(16 * 1024, PTHREAD_STACK_MIN));
493 BUG_ON(err); 494 BUG_ON(err);
494 err = pthread_mutex_lock(&start_work_mutex); 495 err = pthread_mutex_lock(&start_work_mutex);
495 BUG_ON(err); 496 BUG_ON(err);
@@ -1606,28 +1607,15 @@ process_raw_event(event_t *raw_event __used, struct perf_session *session,
1606 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); 1607 process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
1607} 1608}
1608 1609
1609static int process_sample_event(event_t *event, struct perf_session *session) 1610static int process_sample_event(event_t *event, struct sample_data *sample,
1611 struct perf_session *session)
1610{ 1612{
1611 struct sample_data data;
1612 struct thread *thread; 1613 struct thread *thread;
1613 1614
1614 if (!(session->sample_type & PERF_SAMPLE_RAW)) 1615 if (!(session->sample_type & PERF_SAMPLE_RAW))
1615 return 0; 1616 return 0;
1616 1617
1617 memset(&data, 0, sizeof(data)); 1618 thread = perf_session__findnew(session, sample->pid);
1618 data.time = -1;
1619 data.cpu = -1;
1620 data.period = -1;
1621
1622 event__parse_sample(event, session->sample_type, &data);
1623
1624 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
1625 event->header.misc,
1626 data.pid, data.tid,
1627 (void *)(long)data.ip,
1628 (long long)data.period);
1629
1630 thread = perf_session__findnew(session, data.pid);
1631 if (thread == NULL) { 1619 if (thread == NULL) {
1632 pr_debug("problem processing %d event, skipping it.\n", 1620 pr_debug("problem processing %d event, skipping it.\n",
1633 event->header.type); 1621 event->header.type);
@@ -1636,50 +1624,38 @@ static int process_sample_event(event_t *event, struct perf_session *session)
1636 1624
1637 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1625 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1638 1626
1639 if (profile_cpu != -1 && profile_cpu != (int)data.cpu) 1627 if (profile_cpu != -1 && profile_cpu != (int)sample->cpu)
1640 return 0; 1628 return 0;
1641 1629
1642 process_raw_event(event, session, data.raw_data, data.cpu, data.time, thread); 1630 process_raw_event(event, session, sample->raw_data, sample->cpu,
1643 1631 sample->time, thread);
1644 return 0;
1645}
1646
1647static int process_lost_event(event_t *event __used,
1648 struct perf_session *session __used)
1649{
1650 nr_lost_chunks++;
1651 nr_lost_events += event->lost.lost;
1652
1653 return 0;
1654}
1655
1656static int sample_type_check(struct perf_session *session __used)
1657{
1658 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1659 fprintf(stderr,
1660 "No trace sample to read. Did you call perf record "
1661 "without -R?");
1662 return -1;
1663 }
1664 1632
1665 return 0; 1633 return 0;
1666} 1634}
1667 1635
1668static struct perf_event_ops event_ops = { 1636static struct perf_event_ops event_ops = {
1669 .process_sample_event = process_sample_event, 1637 .sample = process_sample_event,
1670 .process_comm_event = event__process_comm, 1638 .comm = event__process_comm,
1671 .process_lost_event = process_lost_event, 1639 .lost = event__process_lost,
1672 .sample_type_check = sample_type_check, 1640 .fork = event__process_task,
1641 .ordered_samples = true,
1673}; 1642};
1674 1643
1675static int read_events(void) 1644static int read_events(void)
1676{ 1645{
1677 int err; 1646 int err = -EINVAL;
1678 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1647 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1648 0, false, &event_ops);
1679 if (session == NULL) 1649 if (session == NULL)
1680 return -ENOMEM; 1650 return -ENOMEM;
1681 1651
1682 err = perf_session__process_events(session, &event_ops); 1652 if (perf_session__has_traces(session, "record -R")) {
1653 err = perf_session__process_events(session, &event_ops);
1654 nr_events = session->hists.stats.nr_events[0];
1655 nr_lost_events = session->hists.stats.total_lost;
1656 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
1657 }
1658
1683 perf_session__delete(session); 1659 perf_session__delete(session);
1684 return err; 1660 return err;
1685} 1661}
@@ -1804,7 +1780,7 @@ static const char * const sched_usage[] = {
1804static const struct option sched_options[] = { 1780static const struct option sched_options[] = {
1805 OPT_STRING('i', "input", &input_name, "file", 1781 OPT_STRING('i', "input", &input_name, "file",
1806 "input file name"), 1782 "input file name"),
1807 OPT_BOOLEAN('v', "verbose", &verbose, 1783 OPT_INCR('v', "verbose", &verbose,
1808 "be more verbose (show symbol address, etc)"), 1784 "be more verbose (show symbol address, etc)"),
1809 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1785 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1810 "dump raw trace in ASCII"), 1786 "dump raw trace in ASCII"),
@@ -1819,7 +1795,7 @@ static const char * const latency_usage[] = {
1819static const struct option latency_options[] = { 1795static const struct option latency_options[] = {
1820 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1796 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1821 "sort by key(s): runtime, switch, avg, max"), 1797 "sort by key(s): runtime, switch, avg, max"),
1822 OPT_BOOLEAN('v', "verbose", &verbose, 1798 OPT_INCR('v', "verbose", &verbose,
1823 "be more verbose (show symbol address, etc)"), 1799 "be more verbose (show symbol address, etc)"),
1824 OPT_INTEGER('C', "CPU", &profile_cpu, 1800 OPT_INTEGER('C', "CPU", &profile_cpu,
1825 "CPU to profile on"), 1801 "CPU to profile on"),
@@ -1834,9 +1810,9 @@ static const char * const replay_usage[] = {
1834}; 1810};
1835 1811
1836static const struct option replay_options[] = { 1812static const struct option replay_options[] = {
1837 OPT_INTEGER('r', "repeat", &replay_repeat, 1813 OPT_UINTEGER('r', "repeat", &replay_repeat,
1838 "repeat the workload replay N times (-1: infinite)"), 1814 "repeat the workload replay N times (-1: infinite)"),
1839 OPT_BOOLEAN('v', "verbose", &verbose, 1815 OPT_INCR('v', "verbose", &verbose,
1840 "be more verbose (show symbol address, etc)"), 1816 "be more verbose (show symbol address, etc)"),
1841 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1817 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1842 "dump raw trace in ASCII"), 1818 "dump raw trace in ASCII"),
@@ -1864,19 +1840,18 @@ static const char *record_args[] = {
1864 "record", 1840 "record",
1865 "-a", 1841 "-a",
1866 "-R", 1842 "-R",
1867 "-M",
1868 "-f", 1843 "-f",
1869 "-m", "1024", 1844 "-m", "1024",
1870 "-c", "1", 1845 "-c", "1",
1871 "-e", "sched:sched_switch:r", 1846 "-e", "sched:sched_switch",
1872 "-e", "sched:sched_stat_wait:r", 1847 "-e", "sched:sched_stat_wait",
1873 "-e", "sched:sched_stat_sleep:r", 1848 "-e", "sched:sched_stat_sleep",
1874 "-e", "sched:sched_stat_iowait:r", 1849 "-e", "sched:sched_stat_iowait",
1875 "-e", "sched:sched_stat_runtime:r", 1850 "-e", "sched:sched_stat_runtime",
1876 "-e", "sched:sched_process_exit:r", 1851 "-e", "sched:sched_process_exit",
1877 "-e", "sched:sched_process_fork:r", 1852 "-e", "sched:sched_process_fork",
1878 "-e", "sched:sched_wakeup:r", 1853 "-e", "sched:sched_wakeup",
1879 "-e", "sched:sched_migrate_task:r", 1854 "-e", "sched:sched_migrate_task",
1880}; 1855};
1881 1856
1882static int __cmd_record(int argc, const char **argv) 1857static int __cmd_record(int argc, const char **argv)
@@ -1887,6 +1862,9 @@ static int __cmd_record(int argc, const char **argv)
1887 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 1862 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1888 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1863 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1889 1864
1865 if (rec_argv == NULL)
1866 return -ENOMEM;
1867
1890 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1868 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1891 rec_argv[i] = strdup(record_args[i]); 1869 rec_argv[i] = strdup(record_args[i]);
1892 1870
@@ -1906,10 +1884,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __used)
1906 usage_with_options(sched_usage, sched_options); 1884 usage_with_options(sched_usage, sched_options);
1907 1885
1908 /* 1886 /*
1909 * Aliased to 'perf trace' for now: 1887 * Aliased to 'perf script' for now:
1910 */ 1888 */
1911 if (!strcmp(argv[0], "trace")) 1889 if (!strcmp(argv[0], "script"))
1912 return cmd_trace(argc, argv, prefix); 1890 return cmd_script(argc, argv, prefix);
1913 1891
1914 symbol__init(); 1892 symbol__init();
1915 if (!strncmp(argv[0], "rec", 3)) { 1893 if (!strncmp(argv[0], "rec", 3)) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-script.c
index 574a215e800b..150a606002eb 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-script.c
@@ -1,16 +1,24 @@
1#include "builtin.h" 1#include "builtin.h"
2 2
3#include "util/util.h" 3#include "perf.h"
4#include "util/cache.h" 4#include "util/cache.h"
5#include "util/debug.h"
6#include "util/exec_cmd.h"
7#include "util/header.h"
8#include "util/parse-options.h"
9#include "util/session.h"
5#include "util/symbol.h" 10#include "util/symbol.h"
6#include "util/thread.h" 11#include "util/thread.h"
7#include "util/header.h"
8#include "util/exec_cmd.h"
9#include "util/trace-event.h" 12#include "util/trace-event.h"
10#include "util/session.h" 13#include "util/parse-options.h"
14#include "util/util.h"
11 15
12static char const *script_name; 16static char const *script_name;
13static char const *generate_script_lang; 17static char const *generate_script_lang;
18static bool debug_mode;
19static u64 last_timestamp;
20static u64 nr_unordered;
21extern const struct option record_options[];
14 22
15static int default_start_script(const char *script __unused, 23static int default_start_script(const char *script __unused,
16 int argc __unused, 24 int argc __unused,
@@ -40,48 +48,26 @@ static struct scripting_ops *scripting_ops;
40 48
41static void setup_scripting(void) 49static void setup_scripting(void)
42{ 50{
43 /* make sure PERF_EXEC_PATH is set for scripts */
44 perf_set_argv_exec_path(perf_exec_path());
45
46 setup_perl_scripting(); 51 setup_perl_scripting();
52 setup_python_scripting();
47 53
48 scripting_ops = &default_scripting_ops; 54 scripting_ops = &default_scripting_ops;
49} 55}
50 56
51static int cleanup_scripting(void) 57static int cleanup_scripting(void)
52{ 58{
59 pr_debug("\nperf script stopped\n");
60
53 return scripting_ops->stop_script(); 61 return scripting_ops->stop_script();
54} 62}
55 63
56#include "util/parse-options.h"
57
58#include "perf.h"
59#include "util/debug.h"
60
61#include "util/trace-event.h"
62#include "util/exec_cmd.h"
63
64static char const *input_name = "perf.data"; 64static char const *input_name = "perf.data";
65 65
66static int process_sample_event(event_t *event, struct perf_session *session) 66static int process_sample_event(event_t *event, struct sample_data *sample,
67 struct perf_session *session)
67{ 68{
68 struct sample_data data; 69 struct thread *thread = perf_session__findnew(session, event->ip.pid);
69 struct thread *thread;
70
71 memset(&data, 0, sizeof(data));
72 data.time = -1;
73 data.cpu = -1;
74 data.period = 1;
75
76 event__parse_sample(event, session->sample_type, &data);
77 70
78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
79 event->header.misc,
80 data.pid, data.tid,
81 (void *)(long)data.ip,
82 (long long)data.period);
83
84 thread = perf_session__findnew(session, event->ip.pid);
85 if (thread == NULL) { 71 if (thread == NULL) {
86 pr_debug("problem processing %d event, skipping it.\n", 72 pr_debug("problem processing %d event, skipping it.\n",
87 event->header.type); 73 event->header.type);
@@ -89,41 +75,60 @@ static int process_sample_event(event_t *event, struct perf_session *session)
89 } 75 }
90 76
91 if (session->sample_type & PERF_SAMPLE_RAW) { 77 if (session->sample_type & PERF_SAMPLE_RAW) {
78 if (debug_mode) {
79 if (sample->time < last_timestamp) {
80 pr_err("Samples misordered, previous: %llu "
81 "this: %llu\n", last_timestamp,
82 sample->time);
83 nr_unordered++;
84 }
85 last_timestamp = sample->time;
86 return 0;
87 }
92 /* 88 /*
93 * FIXME: better resolve from pid from the struct trace_entry 89 * FIXME: better resolve from pid from the struct trace_entry
94 * field, although it should be the same than this perf 90 * field, although it should be the same than this perf
95 * event pid 91 * event pid
96 */ 92 */
97 scripting_ops->process_event(data.cpu, data.raw_data, 93 scripting_ops->process_event(sample->cpu, sample->raw_data,
98 data.raw_size, 94 sample->raw_size,
99 data.time, thread->comm); 95 sample->time, thread->comm);
100 }
101
102 session->events_stats.total += data.period;
103 return 0;
104}
105
106static int sample_type_check(struct perf_session *session)
107{
108 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
109 fprintf(stderr,
110 "No trace sample to read. Did you call perf record "
111 "without -R?");
112 return -1;
113 } 96 }
114 97
98 session->hists.stats.total_period += sample->period;
115 return 0; 99 return 0;
116} 100}
117 101
118static struct perf_event_ops event_ops = { 102static struct perf_event_ops event_ops = {
119 .process_sample_event = process_sample_event, 103 .sample = process_sample_event,
120 .process_comm_event = event__process_comm, 104 .comm = event__process_comm,
121 .sample_type_check = sample_type_check, 105 .attr = event__process_attr,
106 .event_type = event__process_event_type,
107 .tracing_data = event__process_tracing_data,
108 .build_id = event__process_build_id,
109 .ordering_requires_timestamps = true,
110 .ordered_samples = true,
122}; 111};
123 112
124static int __cmd_trace(struct perf_session *session) 113extern volatile int session_done;
114
115static void sig_handler(int sig __unused)
125{ 116{
126 return perf_session__process_events(session, &event_ops); 117 session_done = 1;
118}
119
120static int __cmd_script(struct perf_session *session)
121{
122 int ret;
123
124 signal(SIGINT, sig_handler);
125
126 ret = perf_session__process_events(session, &event_ops);
127
128 if (debug_mode)
129 pr_err("Misordered timestamps: %llu\n", nr_unordered);
130
131 return ret;
127} 132}
128 133
129struct script_spec { 134struct script_spec {
@@ -132,7 +137,7 @@ struct script_spec {
132 char spec[0]; 137 char spec[0];
133}; 138};
134 139
135LIST_HEAD(script_specs); 140static LIST_HEAD(script_specs);
136 141
137static struct script_spec *script_spec__new(const char *spec, 142static struct script_spec *script_spec__new(const char *spec,
138 struct scripting_ops *ops) 143 struct scripting_ops *ops)
@@ -220,7 +225,7 @@ static void list_available_languages(void)
220 225
221 fprintf(stderr, "\n"); 226 fprintf(stderr, "\n");
222 fprintf(stderr, "Scripting language extensions (used in " 227 fprintf(stderr, "Scripting language extensions (used in "
223 "perf trace -s [spec:]script.[spec]):\n\n"); 228 "perf script -s [spec:]script.[spec]):\n\n");
224 229
225 list_for_each_entry(s, &script_specs, node) 230 list_for_each_entry(s, &script_specs, node)
226 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name); 231 fprintf(stderr, " %-42s [%s]\n", s->spec, s->ops->name);
@@ -235,9 +240,9 @@ static int parse_scriptname(const struct option *opt __used,
235 const char *script, *ext; 240 const char *script, *ext;
236 int len; 241 int len;
237 242
238 if (strcmp(str, "list") == 0) { 243 if (strcmp(str, "lang") == 0) {
239 list_available_languages(); 244 list_available_languages();
240 return 0; 245 exit(0);
241 } 246 }
242 247
243 script = strchr(str, ':'); 248 script = strchr(str, ':');
@@ -257,7 +262,7 @@ static int parse_scriptname(const struct option *opt __used,
257 script++; 262 script++;
258 } else { 263 } else {
259 script = str; 264 script = str;
260 ext = strchr(script, '.'); 265 ext = strrchr(script, '.');
261 if (!ext) { 266 if (!ext) {
262 fprintf(stderr, "invalid script extension"); 267 fprintf(stderr, "invalid script extension");
263 return -1; 268 return -1;
@@ -274,17 +279,34 @@ static int parse_scriptname(const struct option *opt __used,
274 return 0; 279 return 0;
275} 280}
276 281
277#define for_each_lang(scripts_dir, lang_dirent, lang_next) \ 282/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
283static int is_directory(const char *base_path, const struct dirent *dent)
284{
285 char path[PATH_MAX];
286 struct stat st;
287
288 sprintf(path, "%s/%s", base_path, dent->d_name);
289 if (stat(path, &st))
290 return 0;
291
292 return S_ISDIR(st.st_mode);
293}
294
295#define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\
278 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ 296 while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \
279 lang_next) \ 297 lang_next) \
280 if (lang_dirent.d_type == DT_DIR && \ 298 if ((lang_dirent.d_type == DT_DIR || \
299 (lang_dirent.d_type == DT_UNKNOWN && \
300 is_directory(scripts_path, &lang_dirent))) && \
281 (strcmp(lang_dirent.d_name, ".")) && \ 301 (strcmp(lang_dirent.d_name, ".")) && \
282 (strcmp(lang_dirent.d_name, ".."))) 302 (strcmp(lang_dirent.d_name, "..")))
283 303
284#define for_each_script(lang_dir, script_dirent, script_next) \ 304#define for_each_script(lang_path, lang_dir, script_dirent, script_next)\
285 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ 305 while (!readdir_r(lang_dir, &script_dirent, &script_next) && \
286 script_next) \ 306 script_next) \
287 if (script_dirent.d_type != DT_DIR) 307 if (script_dirent.d_type != DT_DIR && \
308 (script_dirent.d_type != DT_UNKNOWN || \
309 !is_directory(lang_path, &script_dirent)))
288 310
289 311
290#define RECORD_SUFFIX "-record" 312#define RECORD_SUFFIX "-record"
@@ -297,13 +319,13 @@ struct script_desc {
297 char *args; 319 char *args;
298}; 320};
299 321
300LIST_HEAD(script_descs); 322static LIST_HEAD(script_descs);
301 323
302static struct script_desc *script_desc__new(const char *name) 324static struct script_desc *script_desc__new(const char *name)
303{ 325{
304 struct script_desc *s = zalloc(sizeof(*s)); 326 struct script_desc *s = zalloc(sizeof(*s));
305 327
306 if (s != NULL) 328 if (s != NULL && name)
307 s->name = strdup(name); 329 s->name = strdup(name);
308 330
309 return s; 331 return s;
@@ -312,6 +334,8 @@ static struct script_desc *script_desc__new(const char *name)
312static void script_desc__delete(struct script_desc *s) 334static void script_desc__delete(struct script_desc *s)
313{ 335{
314 free(s->name); 336 free(s->name);
337 free(s->half_liner);
338 free(s->args);
315 free(s); 339 free(s);
316} 340}
317 341
@@ -351,10 +375,10 @@ out_delete_desc:
351 return NULL; 375 return NULL;
352} 376}
353 377
354static char *ends_with(char *str, const char *suffix) 378static const char *ends_with(const char *str, const char *suffix)
355{ 379{
356 size_t suffix_len = strlen(suffix); 380 size_t suffix_len = strlen(suffix);
357 char *p = str; 381 const char *p = str;
358 382
359 if (strlen(str) > suffix_len) { 383 if (strlen(str) > suffix_len) {
360 p = str + strlen(str) - suffix_len; 384 p = str + strlen(str) - suffix_len;
@@ -437,16 +461,16 @@ static int list_available_scripts(const struct option *opt __used,
437 if (!scripts_dir) 461 if (!scripts_dir)
438 return -1; 462 return -1;
439 463
440 for_each_lang(scripts_dir, lang_dirent, lang_next) { 464 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
441 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 465 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
442 lang_dirent.d_name); 466 lang_dirent.d_name);
443 lang_dir = opendir(lang_path); 467 lang_dir = opendir(lang_path);
444 if (!lang_dir) 468 if (!lang_dir)
445 continue; 469 continue;
446 470
447 for_each_script(lang_dir, script_dirent, script_next) { 471 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
448 script_root = strdup(script_dirent.d_name); 472 script_root = strdup(script_dirent.d_name);
449 str = ends_with(script_root, REPORT_SUFFIX); 473 str = (char *)ends_with(script_root, REPORT_SUFFIX);
450 if (str) { 474 if (str) {
451 *str = '\0'; 475 *str = '\0';
452 desc = script_desc__findnew(script_root); 476 desc = script_desc__findnew(script_root);
@@ -485,16 +509,16 @@ static char *get_script_path(const char *script_root, const char *suffix)
485 if (!scripts_dir) 509 if (!scripts_dir)
486 return NULL; 510 return NULL;
487 511
488 for_each_lang(scripts_dir, lang_dirent, lang_next) { 512 for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
489 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, 513 snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
490 lang_dirent.d_name); 514 lang_dirent.d_name);
491 lang_dir = opendir(lang_path); 515 lang_dir = opendir(lang_path);
492 if (!lang_dir) 516 if (!lang_dir)
493 continue; 517 continue;
494 518
495 for_each_script(lang_dir, script_dirent, script_next) { 519 for_each_script(lang_path, lang_dir, script_dirent, script_next) {
496 __script_root = strdup(script_dirent.d_name); 520 __script_root = strdup(script_dirent.d_name);
497 str = ends_with(__script_root, suffix); 521 str = (char *)ends_with(__script_root, suffix);
498 if (str) { 522 if (str) {
499 *str = '\0'; 523 *str = '\0';
500 if (strcmp(__script_root, script_root)) 524 if (strcmp(__script_root, script_root))
@@ -512,15 +536,47 @@ static char *get_script_path(const char *script_root, const char *suffix)
512 return path; 536 return path;
513} 537}
514 538
515static const char * const trace_usage[] = { 539static bool is_top_script(const char *script_path)
516 "perf trace [<options>] <command>", 540{
541 return ends_with(script_path, "top") == NULL ? false : true;
542}
543
544static int has_required_arg(char *script_path)
545{
546 struct script_desc *desc;
547 int n_args = 0;
548 char *p;
549
550 desc = script_desc__new(NULL);
551
552 if (read_script_info(desc, script_path))
553 goto out;
554
555 if (!desc->args)
556 goto out;
557
558 for (p = desc->args; *p; p++)
559 if (*p == '<')
560 n_args++;
561out:
562 script_desc__delete(desc);
563
564 return n_args;
565}
566
567static const char * const script_usage[] = {
568 "perf script [<options>]",
569 "perf script [<options>] record <script> [<record-options>] <command>",
570 "perf script [<options>] report <script> [script-args]",
571 "perf script [<options>] <script> [<record-options>] <command>",
572 "perf script [<options>] <top-script> [script-args]",
517 NULL 573 NULL
518}; 574};
519 575
520static const struct option options[] = { 576static const struct option options[] = {
521 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 577 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
522 "dump raw trace in ASCII"), 578 "dump raw trace in ASCII"),
523 OPT_BOOLEAN('v', "verbose", &verbose, 579 OPT_INCR('v', "verbose", &verbose,
524 "be more verbose (show symbol address, etc)"), 580 "be more verbose (show symbol address, etc)"),
525 OPT_BOOLEAN('L', "Latency", &latency_format, 581 OPT_BOOLEAN('L', "Latency", &latency_format,
526 "show latency attributes (irqs/preemption disabled, etc)"), 582 "show latency attributes (irqs/preemption disabled, etc)"),
@@ -530,68 +586,195 @@ static const struct option options[] = {
530 "script file name (lang:script name, script name, or *)", 586 "script file name (lang:script name, script name, or *)",
531 parse_scriptname), 587 parse_scriptname),
532 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 588 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
533 "generate perf-trace.xx script in specified language"), 589 "generate perf-script.xx script in specified language"),
590 OPT_STRING('i', "input", &input_name, "file",
591 "input file name"),
592 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
593 "do various checks like samples ordering and lost events"),
534 594
535 OPT_END() 595 OPT_END()
536}; 596};
537 597
538int cmd_trace(int argc, const char **argv, const char *prefix __used) 598static bool have_cmd(int argc, const char **argv)
599{
600 char **__argv = malloc(sizeof(const char *) * argc);
601
602 if (!__argv)
603 die("malloc");
604 memcpy(__argv, argv, sizeof(const char *) * argc);
605 argc = parse_options(argc, (const char **)__argv, record_options,
606 NULL, PARSE_OPT_STOP_AT_NON_OPTION);
607 free(__argv);
608
609 return argc != 0;
610}
611
612int cmd_script(int argc, const char **argv, const char *prefix __used)
539{ 613{
614 char *rec_script_path = NULL;
615 char *rep_script_path = NULL;
540 struct perf_session *session; 616 struct perf_session *session;
541 const char *suffix = NULL; 617 char *script_path = NULL;
542 const char **__argv; 618 const char **__argv;
543 char *script_path; 619 bool system_wide;
544 int i, err; 620 int i, j, err;
545 621
546 if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) { 622 setup_scripting();
547 if (argc < 3) { 623
548 fprintf(stderr, 624 argc = parse_options(argc, argv, options, script_usage,
549 "Please specify a record script\n"); 625 PARSE_OPT_STOP_AT_NON_OPTION);
550 return -1; 626
551 } 627 if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
552 suffix = RECORD_SUFFIX; 628 rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
629 if (!rec_script_path)
630 return cmd_record(argc, argv, NULL);
553 } 631 }
554 632
555 if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) { 633 if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
556 if (argc < 3) { 634 rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
635 if (!rep_script_path) {
557 fprintf(stderr, 636 fprintf(stderr,
558 "Please specify a report script\n"); 637 "Please specify a valid report script"
638 "(see 'perf script -l' for listing)\n");
559 return -1; 639 return -1;
560 } 640 }
561 suffix = REPORT_SUFFIX;
562 } 641 }
563 642
564 if (suffix) { 643 /* make sure PERF_EXEC_PATH is set for scripts */
565 script_path = get_script_path(argv[2], suffix); 644 perf_set_argv_exec_path(perf_exec_path());
566 if (!script_path) { 645
567 fprintf(stderr, "script not found\n"); 646 if (argc && !script_name && !rec_script_path && !rep_script_path) {
568 return -1; 647 int live_pipe[2];
648 int rep_args;
649 pid_t pid;
650
651 rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
652 rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
653
654 if (!rec_script_path && !rep_script_path) {
655 fprintf(stderr, " Couldn't find script %s\n\n See perf"
656 " script -l for available scripts.\n", argv[0]);
657 usage_with_options(script_usage, options);
569 } 658 }
570 659
571 __argv = malloc((argc + 1) * sizeof(const char *)); 660 if (is_top_script(argv[0])) {
572 __argv[0] = "/bin/sh"; 661 rep_args = argc - 1;
573 __argv[1] = script_path; 662 } else {
574 for (i = 3; i < argc; i++) 663 int rec_args;
575 __argv[i - 1] = argv[i]; 664
576 __argv[argc - 1] = NULL; 665 rep_args = has_required_arg(rep_script_path);
666 rec_args = (argc - 1) - rep_args;
667 if (rec_args < 0) {
668 fprintf(stderr, " %s script requires options."
669 "\n\n See perf script -l for available "
670 "scripts and options.\n", argv[0]);
671 usage_with_options(script_usage, options);
672 }
673 }
674
675 if (pipe(live_pipe) < 0) {
676 perror("failed to create pipe");
677 exit(-1);
678 }
679
680 pid = fork();
681 if (pid < 0) {
682 perror("failed to fork");
683 exit(-1);
684 }
685
686 if (!pid) {
687 system_wide = true;
688 j = 0;
689
690 dup2(live_pipe[1], 1);
691 close(live_pipe[0]);
692
693 if (!is_top_script(argv[0]))
694 system_wide = !have_cmd(argc - rep_args,
695 &argv[rep_args]);
696
697 __argv = malloc((argc + 6) * sizeof(const char *));
698 if (!__argv)
699 die("malloc");
700
701 __argv[j++] = "/bin/sh";
702 __argv[j++] = rec_script_path;
703 if (system_wide)
704 __argv[j++] = "-a";
705 __argv[j++] = "-q";
706 __argv[j++] = "-o";
707 __argv[j++] = "-";
708 for (i = rep_args + 1; i < argc; i++)
709 __argv[j++] = argv[i];
710 __argv[j++] = NULL;
711
712 execvp("/bin/sh", (char **)__argv);
713 free(__argv);
714 exit(-1);
715 }
716
717 dup2(live_pipe[0], 0);
718 close(live_pipe[1]);
719
720 __argv = malloc((argc + 4) * sizeof(const char *));
721 if (!__argv)
722 die("malloc");
723 j = 0;
724 __argv[j++] = "/bin/sh";
725 __argv[j++] = rep_script_path;
726 for (i = 1; i < rep_args + 1; i++)
727 __argv[j++] = argv[i];
728 __argv[j++] = "-i";
729 __argv[j++] = "-";
730 __argv[j++] = NULL;
577 731
578 execvp("/bin/sh", (char **)__argv); 732 execvp("/bin/sh", (char **)__argv);
733 free(__argv);
579 exit(-1); 734 exit(-1);
580 } 735 }
581 736
582 setup_scripting(); 737 if (rec_script_path)
738 script_path = rec_script_path;
739 if (rep_script_path)
740 script_path = rep_script_path;
741
742 if (script_path) {
743 system_wide = false;
744 j = 0;
745
746 if (rec_script_path)
747 system_wide = !have_cmd(argc - 1, &argv[1]);
748
749 __argv = malloc((argc + 2) * sizeof(const char *));
750 if (!__argv)
751 die("malloc");
752 __argv[j++] = "/bin/sh";
753 __argv[j++] = script_path;
754 if (system_wide)
755 __argv[j++] = "-a";
756 for (i = 2; i < argc; i++)
757 __argv[j++] = argv[i];
758 __argv[j++] = NULL;
583 759
584 argc = parse_options(argc, argv, options, trace_usage, 760 execvp("/bin/sh", (char **)__argv);
585 PARSE_OPT_STOP_AT_NON_OPTION); 761 free(__argv);
762 exit(-1);
763 }
586 764
587 if (symbol__init() < 0) 765 if (symbol__init() < 0)
588 return -1; 766 return -1;
589 setup_pager(); 767 if (!script_name)
768 setup_pager();
590 769
591 session = perf_session__new(input_name, O_RDONLY, 0); 770 session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
592 if (session == NULL) 771 if (session == NULL)
593 return -ENOMEM; 772 return -ENOMEM;
594 773
774 if (strcmp(input_name, "-") &&
775 !perf_session__has_traces(session, "record -R"))
776 return -EINVAL;
777
595 if (generate_script_lang) { 778 if (generate_script_lang) {
596 struct stat perf_stat; 779 struct stat perf_stat;
597 780
@@ -618,8 +801,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
618 return -1; 801 return -1;
619 } 802 }
620 803
621 perf_header__read(&session->header, input); 804 err = scripting_ops->generate_script("perf-script");
622 err = scripting_ops->generate_script("perf-trace");
623 goto out; 805 goto out;
624 } 806 }
625 807
@@ -627,9 +809,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
627 err = scripting_ops->start_script(script_name, argc, argv); 809 err = scripting_ops->start_script(script_name, argc, argv);
628 if (err) 810 if (err)
629 goto out; 811 goto out;
812 pr_debug("perf script started with script %s\n\n", script_name);
630 } 813 }
631 814
632 err = __cmd_trace(session); 815 err = __cmd_script(session);
633 816
634 perf_session__delete(session); 817 perf_session__delete(session);
635 cleanup_scripting(); 818 cleanup_scripting();
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c70d72003557..0ff11d9b13be 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -43,10 +43,17 @@
43#include "util/parse-options.h" 43#include "util/parse-options.h"
44#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h" 45#include "util/event.h"
46#include "util/evsel.h"
46#include "util/debug.h" 47#include "util/debug.h"
48#include "util/header.h"
49#include "util/cpumap.h"
50#include "util/thread.h"
47 51
48#include <sys/prctl.h> 52#include <sys/prctl.h>
49#include <math.h> 53#include <math.h>
54#include <locale.h>
55
56#define DEFAULT_SEPARATOR " "
50 57
51static struct perf_event_attr default_attrs[] = { 58static struct perf_event_attr default_attrs[] = {
52 59
@@ -64,26 +71,48 @@ static struct perf_event_attr default_attrs[] = {
64 71
65}; 72};
66 73
67static int system_wide = 0; 74static bool system_wide = false;
68static unsigned int nr_cpus = 0; 75static struct cpu_map *cpus;
69static int run_idx = 0; 76static int run_idx = 0;
70 77
71static int run_count = 1; 78static int run_count = 1;
72static int inherit = 1; 79static bool no_inherit = false;
73static int scale = 1; 80static bool scale = true;
81static bool no_aggr = false;
74static pid_t target_pid = -1; 82static pid_t target_pid = -1;
83static pid_t target_tid = -1;
84static struct thread_map *threads;
75static pid_t child_pid = -1; 85static pid_t child_pid = -1;
76static int null_run = 0; 86static bool null_run = false;
77 87static bool big_num = true;
78static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 88static int big_num_opt = -1;
89static const char *cpu_list;
90static const char *csv_sep = NULL;
91static bool csv_output = false;
79 92
80static int event_scaled[MAX_COUNTERS]; 93static volatile int done = 0;
81 94
82struct stats 95struct stats
83{ 96{
84 double n, mean, M2; 97 double n, mean, M2;
85}; 98};
86 99
100struct perf_stat {
101 struct stats res_stats[3];
102};
103
104static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
105{
106 evsel->priv = zalloc(sizeof(struct perf_stat));
107 return evsel->priv == NULL ? -ENOMEM : 0;
108}
109
110static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
111{
112 free(evsel->priv);
113 evsel->priv = NULL;
114}
115
87static void update_stats(struct stats *stats, u64 val) 116static void update_stats(struct stats *stats, u64 val)
88{ 117{
89 double delta; 118 double delta;
@@ -123,55 +152,38 @@ static double stddev_stats(struct stats *stats)
123 return sqrt(variance_mean); 152 return sqrt(variance_mean);
124} 153}
125 154
126struct stats event_res_stats[MAX_COUNTERS][3]; 155struct stats runtime_nsecs_stats[MAX_NR_CPUS];
127struct stats runtime_nsecs_stats; 156struct stats runtime_cycles_stats[MAX_NR_CPUS];
157struct stats runtime_branches_stats[MAX_NR_CPUS];
128struct stats walltime_nsecs_stats; 158struct stats walltime_nsecs_stats;
129struct stats runtime_cycles_stats;
130struct stats runtime_branches_stats;
131
132#define MATCH_EVENT(t, c, counter) \
133 (attrs[counter].type == PERF_TYPE_##t && \
134 attrs[counter].config == PERF_COUNT_##c)
135 159
136#define ERR_PERF_OPEN \ 160static int create_perf_stat_counter(struct perf_evsel *evsel)
137"Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n"
138
139static void create_perf_stat_counter(int counter, int pid)
140{ 161{
141 struct perf_event_attr *attr = attrs + counter; 162 struct perf_event_attr *attr = &evsel->attr;
142 163
143 if (scale) 164 if (scale)
144 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 165 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
145 PERF_FORMAT_TOTAL_TIME_RUNNING; 166 PERF_FORMAT_TOTAL_TIME_RUNNING;
146 167
147 if (system_wide) { 168 if (system_wide)
148 unsigned int cpu; 169 return perf_evsel__open_per_cpu(evsel, cpus);
149 170
150 for (cpu = 0; cpu < nr_cpus; cpu++) { 171 attr->inherit = !no_inherit;
151 fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0); 172 if (target_pid == -1 && target_tid == -1) {
152 if (fd[cpu][counter] < 0 && verbose) 173 attr->disabled = 1;
153 fprintf(stderr, ERR_PERF_OPEN, counter,
154 fd[cpu][counter], strerror(errno));
155 }
156 } else {
157 attr->inherit = inherit;
158 attr->disabled = 1;
159 attr->enable_on_exec = 1; 174 attr->enable_on_exec = 1;
160
161 fd[0][counter] = sys_perf_event_open(attr, pid, -1, -1, 0);
162 if (fd[0][counter] < 0 && verbose)
163 fprintf(stderr, ERR_PERF_OPEN, counter,
164 fd[0][counter], strerror(errno));
165 } 175 }
176
177 return perf_evsel__open_per_thread(evsel, threads);
166} 178}
167 179
168/* 180/*
169 * Does the counter have nsecs as a unit? 181 * Does the counter have nsecs as a unit?
170 */ 182 */
171static inline int nsec_counter(int counter) 183static inline int nsec_counter(struct perf_evsel *evsel)
172{ 184{
173 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || 185 if (perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) ||
174 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 186 perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
175 return 1; 187 return 1;
176 188
177 return 0; 189 return 0;
@@ -179,52 +191,19 @@ static inline int nsec_counter(int counter)
179 191
180/* 192/*
181 * Read out the results of a single counter: 193 * Read out the results of a single counter:
194 * aggregate counts across CPUs in system-wide mode
182 */ 195 */
183static void read_counter(int counter) 196static int read_counter_aggr(struct perf_evsel *counter)
184{ 197{
185 u64 count[3], single_count[3]; 198 struct perf_stat *ps = counter->priv;
186 unsigned int cpu; 199 u64 *count = counter->counts->aggr.values;
187 size_t res, nv;
188 int scaled;
189 int i; 200 int i;
190 201
191 count[0] = count[1] = count[2] = 0; 202 if (__perf_evsel__read(counter, cpus->nr, threads->nr, scale) < 0)
192 203 return -1;
193 nv = scale ? 3 : 1;
194 for (cpu = 0; cpu < nr_cpus; cpu++) {
195 if (fd[cpu][counter] < 0)
196 continue;
197
198 res = read(fd[cpu][counter], single_count, nv * sizeof(u64));
199 assert(res == nv * sizeof(u64));
200
201 close(fd[cpu][counter]);
202 fd[cpu][counter] = -1;
203
204 count[0] += single_count[0];
205 if (scale) {
206 count[1] += single_count[1];
207 count[2] += single_count[2];
208 }
209 }
210
211 scaled = 0;
212 if (scale) {
213 if (count[2] == 0) {
214 event_scaled[counter] = -1;
215 count[0] = 0;
216 return;
217 }
218
219 if (count[2] < count[1]) {
220 event_scaled[counter] = 1;
221 count[0] = (unsigned long long)
222 ((double)count[0] * count[1] / count[2] + 0.5);
223 }
224 }
225 204
226 for (i = 0; i < 3; i++) 205 for (i = 0; i < 3; i++)
227 update_stats(&event_res_stats[counter][i], count[i]); 206 update_stats(&ps->res_stats[i], count[i]);
228 207
229 if (verbose) { 208 if (verbose) {
230 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), 209 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter),
@@ -234,140 +213,230 @@ static void read_counter(int counter)
234 /* 213 /*
235 * Save the full runtime - to allow normalization during printout: 214 * Save the full runtime - to allow normalization during printout:
236 */ 215 */
237 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 216 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
238 update_stats(&runtime_nsecs_stats, count[0]); 217 update_stats(&runtime_nsecs_stats[0], count[0]);
239 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) 218 if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
240 update_stats(&runtime_cycles_stats, count[0]); 219 update_stats(&runtime_cycles_stats[0], count[0]);
241 if (MATCH_EVENT(HARDWARE, HW_BRANCH_INSTRUCTIONS, counter)) 220 if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
242 update_stats(&runtime_branches_stats, count[0]); 221 update_stats(&runtime_branches_stats[0], count[0]);
222
223 return 0;
224}
225
226/*
227 * Read out the results of a single counter:
228 * do not aggregate counts across CPUs in system-wide mode
229 */
230static int read_counter(struct perf_evsel *counter)
231{
232 u64 *count;
233 int cpu;
234
235 for (cpu = 0; cpu < cpus->nr; cpu++) {
236 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
237 return -1;
238
239 count = counter->counts->cpu[cpu].values;
240
241 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK))
242 update_stats(&runtime_nsecs_stats[cpu], count[0]);
243 if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
244 update_stats(&runtime_cycles_stats[cpu], count[0]);
245 if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
246 update_stats(&runtime_branches_stats[cpu], count[0]);
247 }
248
249 return 0;
243} 250}
244 251
245static int run_perf_stat(int argc __used, const char **argv) 252static int run_perf_stat(int argc __used, const char **argv)
246{ 253{
247 unsigned long long t0, t1; 254 unsigned long long t0, t1;
255 struct perf_evsel *counter;
248 int status = 0; 256 int status = 0;
249 int counter;
250 int pid;
251 int child_ready_pipe[2], go_pipe[2]; 257 int child_ready_pipe[2], go_pipe[2];
258 const bool forks = (argc > 0);
252 char buf; 259 char buf;
253 260
254 if (!system_wide) 261 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
255 nr_cpus = 1;
256
257 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) {
258 perror("failed to create pipes"); 262 perror("failed to create pipes");
259 exit(1); 263 exit(1);
260 } 264 }
261 265
262 if ((pid = fork()) < 0) 266 if (forks) {
263 perror("failed to fork"); 267 if ((child_pid = fork()) < 0)
264 268 perror("failed to fork");
265 if (!pid) { 269
266 close(child_ready_pipe[0]); 270 if (!child_pid) {
267 close(go_pipe[1]); 271 close(child_ready_pipe[0]);
268 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 272 close(go_pipe[1]);
273 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
274
275 /*
276 * Do a dummy execvp to get the PLT entry resolved,
277 * so we avoid the resolver overhead on the real
278 * execvp call.
279 */
280 execvp("", (char **)argv);
281
282 /*
283 * Tell the parent we're ready to go
284 */
285 close(child_ready_pipe[1]);
286
287 /*
288 * Wait until the parent tells us to go.
289 */
290 if (read(go_pipe[0], &buf, 1) == -1)
291 perror("unable to read pipe");
292
293 execvp(argv[0], (char **)argv);
294
295 perror(argv[0]);
296 exit(-1);
297 }
269 298
270 /* 299 if (target_tid == -1 && target_pid == -1 && !system_wide)
271 * Do a dummy execvp to get the PLT entry resolved, 300 threads->map[0] = child_pid;
272 * so we avoid the resolver overhead on the real
273 * execvp call.
274 */
275 execvp("", (char **)argv);
276 301
277 /* 302 /*
278 * Tell the parent we're ready to go 303 * Wait for the child to be ready to exec.
279 */ 304 */
280 close(child_ready_pipe[1]); 305 close(child_ready_pipe[1]);
281 306 close(go_pipe[0]);
282 /* 307 if (read(child_ready_pipe[0], &buf, 1) == -1)
283 * Wait until the parent tells us to go.
284 */
285 if (read(go_pipe[0], &buf, 1) == -1)
286 perror("unable to read pipe"); 308 perror("unable to read pipe");
287 309 close(child_ready_pipe[0]);
288 execvp(argv[0], (char **)argv);
289
290 perror(argv[0]);
291 exit(-1);
292 } 310 }
293 311
294 child_pid = pid; 312 list_for_each_entry(counter, &evsel_list, node) {
295 313 if (create_perf_stat_counter(counter) < 0) {
296 /* 314 if (errno == -EPERM || errno == -EACCES) {
297 * Wait for the child to be ready to exec. 315 error("You may not have permission to collect %sstats.\n"
298 */ 316 "\t Consider tweaking"
299 close(child_ready_pipe[1]); 317 " /proc/sys/kernel/perf_event_paranoid or running as root.",
300 close(go_pipe[0]); 318 system_wide ? "system-wide " : "");
301 if (read(child_ready_pipe[0], &buf, 1) == -1) 319 } else if (errno == ENOENT) {
302 perror("unable to read pipe"); 320 error("%s event is not supported. ", event_name(counter));
303 close(child_ready_pipe[0]); 321 } else {
304 322 error("open_counter returned with %d (%s). "
305 for (counter = 0; counter < nr_counters; counter++) 323 "/bin/dmesg may provide additional information.\n",
306 create_perf_stat_counter(counter, pid); 324 errno, strerror(errno));
325 }
326 if (child_pid != -1)
327 kill(child_pid, SIGTERM);
328 die("Not all events could be opened.\n");
329 return -1;
330 }
331 }
307 332
308 /* 333 /*
309 * Enable counters and exec the command: 334 * Enable counters and exec the command:
310 */ 335 */
311 t0 = rdclock(); 336 t0 = rdclock();
312 337
313 close(go_pipe[1]); 338 if (forks) {
314 wait(&status); 339 close(go_pipe[1]);
340 wait(&status);
341 } else {
342 while(!done) sleep(1);
343 }
315 344
316 t1 = rdclock(); 345 t1 = rdclock();
317 346
318 update_stats(&walltime_nsecs_stats, t1 - t0); 347 update_stats(&walltime_nsecs_stats, t1 - t0);
319 348
320 for (counter = 0; counter < nr_counters; counter++) 349 if (no_aggr) {
321 read_counter(counter); 350 list_for_each_entry(counter, &evsel_list, node) {
351 read_counter(counter);
352 perf_evsel__close_fd(counter, cpus->nr, 1);
353 }
354 } else {
355 list_for_each_entry(counter, &evsel_list, node) {
356 read_counter_aggr(counter);
357 perf_evsel__close_fd(counter, cpus->nr, threads->nr);
358 }
359 }
322 360
323 return WEXITSTATUS(status); 361 return WEXITSTATUS(status);
324} 362}
325 363
326static void print_noise(int counter, double avg) 364static void print_noise(struct perf_evsel *evsel, double avg)
327{ 365{
366 struct perf_stat *ps;
367
328 if (run_count == 1) 368 if (run_count == 1)
329 return; 369 return;
330 370
371 ps = evsel->priv;
331 fprintf(stderr, " ( +- %7.3f%% )", 372 fprintf(stderr, " ( +- %7.3f%% )",
332 100 * stddev_stats(&event_res_stats[counter][0]) / avg); 373 100 * stddev_stats(&ps->res_stats[0]) / avg);
333} 374}
334 375
335static void nsec_printout(int counter, double avg) 376static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
336{ 377{
337 double msecs = avg / 1e6; 378 double msecs = avg / 1e6;
379 char cpustr[16] = { '\0', };
380 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-24s";
338 381
339 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter)); 382 if (no_aggr)
383 sprintf(cpustr, "CPU%*d%s",
384 csv_output ? 0 : -4,
385 cpus->map[cpu], csv_sep);
340 386
341 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { 387 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
388
389 if (csv_output)
390 return;
391
392 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
342 fprintf(stderr, " # %10.3f CPUs ", 393 fprintf(stderr, " # %10.3f CPUs ",
343 avg / avg_stats(&walltime_nsecs_stats)); 394 avg / avg_stats(&walltime_nsecs_stats));
344 }
345} 395}
346 396
347static void abs_printout(int counter, double avg) 397static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
348{ 398{
349 double total, ratio = 0.0; 399 double total, ratio = 0.0;
400 char cpustr[16] = { '\0', };
401 const char *fmt;
350 402
351 fprintf(stderr, " %14.0f %-24s", avg, event_name(counter)); 403 if (csv_output)
404 fmt = "%s%.0f%s%s";
405 else if (big_num)
406 fmt = "%s%'18.0f%s%-24s";
407 else
408 fmt = "%s%18.0f%s%-24s";
352 409
353 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { 410 if (no_aggr)
354 total = avg_stats(&runtime_cycles_stats); 411 sprintf(cpustr, "CPU%*d%s",
412 csv_output ? 0 : -4,
413 cpus->map[cpu], csv_sep);
414 else
415 cpu = 0;
416
417 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
418
419 if (csv_output)
420 return;
421
422 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
423 total = avg_stats(&runtime_cycles_stats[cpu]);
355 424
356 if (total) 425 if (total)
357 ratio = avg / total; 426 ratio = avg / total;
358 427
359 fprintf(stderr, " # %10.3f IPC ", ratio); 428 fprintf(stderr, " # %10.3f IPC ", ratio);
360 } else if (MATCH_EVENT(HARDWARE, HW_BRANCH_MISSES, counter) && 429 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) &&
361 runtime_branches_stats.n != 0) { 430 runtime_branches_stats[cpu].n != 0) {
362 total = avg_stats(&runtime_branches_stats); 431 total = avg_stats(&runtime_branches_stats[cpu]);
363 432
364 if (total) 433 if (total)
365 ratio = avg * 100 / total; 434 ratio = avg * 100 / total;
366 435
367 fprintf(stderr, " # %10.3f %% ", ratio); 436 fprintf(stderr, " # %10.3f %% ", ratio);
368 437
369 } else if (runtime_nsecs_stats.n != 0) { 438 } else if (runtime_nsecs_stats[cpu].n != 0) {
370 total = avg_stats(&runtime_nsecs_stats); 439 total = avg_stats(&runtime_nsecs_stats[cpu]);
371 440
372 if (total) 441 if (total)
373 ratio = 1000.0 * avg / total; 442 ratio = 1000.0 * avg / total;
@@ -378,30 +447,38 @@ static void abs_printout(int counter, double avg)
378 447
379/* 448/*
380 * Print out the results of a single counter: 449 * Print out the results of a single counter:
450 * aggregated counts in system-wide mode
381 */ 451 */
382static void print_counter(int counter) 452static void print_counter_aggr(struct perf_evsel *counter)
383{ 453{
384 double avg = avg_stats(&event_res_stats[counter][0]); 454 struct perf_stat *ps = counter->priv;
385 int scaled = event_scaled[counter]; 455 double avg = avg_stats(&ps->res_stats[0]);
456 int scaled = counter->counts->scaled;
386 457
387 if (scaled == -1) { 458 if (scaled == -1) {
388 fprintf(stderr, " %14s %-24s\n", 459 fprintf(stderr, "%*s%s%-24s\n",
389 "<not counted>", event_name(counter)); 460 csv_output ? 0 : 18,
461 "<not counted>", csv_sep, event_name(counter));
390 return; 462 return;
391 } 463 }
392 464
393 if (nsec_counter(counter)) 465 if (nsec_counter(counter))
394 nsec_printout(counter, avg); 466 nsec_printout(-1, counter, avg);
395 else 467 else
396 abs_printout(counter, avg); 468 abs_printout(-1, counter, avg);
469
470 if (csv_output) {
471 fputc('\n', stderr);
472 return;
473 }
397 474
398 print_noise(counter, avg); 475 print_noise(counter, avg);
399 476
400 if (scaled) { 477 if (scaled) {
401 double avg_enabled, avg_running; 478 double avg_enabled, avg_running;
402 479
403 avg_enabled = avg_stats(&event_res_stats[counter][1]); 480 avg_enabled = avg_stats(&ps->res_stats[1]);
404 avg_running = avg_stats(&event_res_stats[counter][2]); 481 avg_running = avg_stats(&ps->res_stats[2]);
405 482
406 fprintf(stderr, " (scaled from %.2f%%)", 483 fprintf(stderr, " (scaled from %.2f%%)",
407 100 * avg_running / avg_enabled); 484 100 * avg_running / avg_enabled);
@@ -410,41 +487,101 @@ static void print_counter(int counter)
410 fprintf(stderr, "\n"); 487 fprintf(stderr, "\n");
411} 488}
412 489
413static void print_stat(int argc, const char **argv) 490/*
491 * Print out the results of a single counter:
492 * does not use aggregated count in system-wide
493 */
494static void print_counter(struct perf_evsel *counter)
414{ 495{
415 int i, counter; 496 u64 ena, run, val;
497 int cpu;
498
499 for (cpu = 0; cpu < cpus->nr; cpu++) {
500 val = counter->counts->cpu[cpu].val;
501 ena = counter->counts->cpu[cpu].ena;
502 run = counter->counts->cpu[cpu].run;
503 if (run == 0 || ena == 0) {
504 fprintf(stderr, "CPU%*d%s%*s%s%-24s",
505 csv_output ? 0 : -4,
506 cpus->map[cpu], csv_sep,
507 csv_output ? 0 : 18,
508 "<not counted>", csv_sep,
509 event_name(counter));
510
511 fprintf(stderr, "\n");
512 continue;
513 }
416 514
417 fflush(stdout); 515 if (nsec_counter(counter))
516 nsec_printout(cpu, counter, val);
517 else
518 abs_printout(cpu, counter, val);
418 519
419 fprintf(stderr, "\n"); 520 if (!csv_output) {
420 fprintf(stderr, " Performance counter stats for \'%s", argv[0]); 521 print_noise(counter, 1.0);
421 522
422 for (i = 1; i < argc; i++) 523 if (run != ena) {
423 fprintf(stderr, " %s", argv[i]); 524 fprintf(stderr, " (scaled from %.2f%%)",
525 100.0 * run / ena);
526 }
527 }
528 fprintf(stderr, "\n");
529 }
530}
424 531
425 fprintf(stderr, "\'"); 532static void print_stat(int argc, const char **argv)
426 if (run_count > 1) 533{
427 fprintf(stderr, " (%d runs)", run_count); 534 struct perf_evsel *counter;
428 fprintf(stderr, ":\n\n"); 535 int i;
429 536
430 for (counter = 0; counter < nr_counters; counter++) 537 fflush(stdout);
431 print_counter(counter);
432 538
433 fprintf(stderr, "\n"); 539 if (!csv_output) {
434 fprintf(stderr, " %14.9f seconds time elapsed", 540 fprintf(stderr, "\n");
435 avg_stats(&walltime_nsecs_stats)/1e9); 541 fprintf(stderr, " Performance counter stats for ");
436 if (run_count > 1) { 542 if(target_pid == -1 && target_tid == -1) {
437 fprintf(stderr, " ( +- %7.3f%% )", 543 fprintf(stderr, "\'%s", argv[0]);
544 for (i = 1; i < argc; i++)
545 fprintf(stderr, " %s", argv[i]);
546 } else if (target_pid != -1)
547 fprintf(stderr, "process id \'%d", target_pid);
548 else
549 fprintf(stderr, "thread id \'%d", target_tid);
550
551 fprintf(stderr, "\'");
552 if (run_count > 1)
553 fprintf(stderr, " (%d runs)", run_count);
554 fprintf(stderr, ":\n\n");
555 }
556
557 if (no_aggr) {
558 list_for_each_entry(counter, &evsel_list, node)
559 print_counter(counter);
560 } else {
561 list_for_each_entry(counter, &evsel_list, node)
562 print_counter_aggr(counter);
563 }
564
565 if (!csv_output) {
566 fprintf(stderr, "\n");
567 fprintf(stderr, " %18.9f seconds time elapsed",
568 avg_stats(&walltime_nsecs_stats)/1e9);
569 if (run_count > 1) {
570 fprintf(stderr, " ( +- %7.3f%% )",
438 100*stddev_stats(&walltime_nsecs_stats) / 571 100*stddev_stats(&walltime_nsecs_stats) /
439 avg_stats(&walltime_nsecs_stats)); 572 avg_stats(&walltime_nsecs_stats));
573 }
574 fprintf(stderr, "\n\n");
440 } 575 }
441 fprintf(stderr, "\n\n");
442} 576}
443 577
444static volatile int signr = -1; 578static volatile int signr = -1;
445 579
446static void skip_signal(int signo) 580static void skip_signal(int signo)
447{ 581{
582 if(child_pid == -1)
583 done = 1;
584
448 signr = signo; 585 signr = signo;
449} 586}
450 587
@@ -461,51 +598,127 @@ static void sig_atexit(void)
461} 598}
462 599
463static const char * const stat_usage[] = { 600static const char * const stat_usage[] = {
464 "perf stat [<options>] <command>", 601 "perf stat [<options>] [<command>]",
465 NULL 602 NULL
466}; 603};
467 604
605static int stat__set_big_num(const struct option *opt __used,
606 const char *s __used, int unset)
607{
608 big_num_opt = unset ? 0 : 1;
609 return 0;
610}
611
468static const struct option options[] = { 612static const struct option options[] = {
469 OPT_CALLBACK('e', "event", NULL, "event", 613 OPT_CALLBACK('e', "event", NULL, "event",
470 "event selector. use 'perf list' to list available events", 614 "event selector. use 'perf list' to list available events",
471 parse_events), 615 parse_events),
472 OPT_BOOLEAN('i', "inherit", &inherit, 616 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
473 "child tasks inherit counters"), 617 "child tasks do not inherit counters"),
474 OPT_INTEGER('p', "pid", &target_pid, 618 OPT_INTEGER('p', "pid", &target_pid,
475 "stat events on existing pid"), 619 "stat events on existing process id"),
620 OPT_INTEGER('t', "tid", &target_tid,
621 "stat events on existing thread id"),
476 OPT_BOOLEAN('a', "all-cpus", &system_wide, 622 OPT_BOOLEAN('a', "all-cpus", &system_wide,
477 "system-wide collection from all CPUs"), 623 "system-wide collection from all CPUs"),
478 OPT_BOOLEAN('c', "scale", &scale, 624 OPT_BOOLEAN('c', "scale", &scale,
479 "scale/normalize counters"), 625 "scale/normalize counters"),
480 OPT_BOOLEAN('v', "verbose", &verbose, 626 OPT_INCR('v', "verbose", &verbose,
481 "be more verbose (show counter open errors, etc)"), 627 "be more verbose (show counter open errors, etc)"),
482 OPT_INTEGER('r', "repeat", &run_count, 628 OPT_INTEGER('r', "repeat", &run_count,
483 "repeat command and print average + stddev (max: 100)"), 629 "repeat command and print average + stddev (max: 100)"),
484 OPT_BOOLEAN('n', "null", &null_run, 630 OPT_BOOLEAN('n', "null", &null_run,
485 "null run - dont start any counters"), 631 "null run - dont start any counters"),
632 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
633 "print large numbers with thousands\' separators",
634 stat__set_big_num),
635 OPT_STRING('C', "cpu", &cpu_list, "cpu",
636 "list of cpus to monitor in system-wide"),
637 OPT_BOOLEAN('A', "no-aggr", &no_aggr,
638 "disable CPU count aggregation"),
639 OPT_STRING('x', "field-separator", &csv_sep, "separator",
640 "print counts with custom separator"),
486 OPT_END() 641 OPT_END()
487}; 642};
488 643
489int cmd_stat(int argc, const char **argv, const char *prefix __used) 644int cmd_stat(int argc, const char **argv, const char *prefix __used)
490{ 645{
491 int status; 646 struct perf_evsel *pos;
647 int status = -ENOMEM;
648
649 setlocale(LC_ALL, "");
492 650
493 argc = parse_options(argc, argv, options, stat_usage, 651 argc = parse_options(argc, argv, options, stat_usage,
494 PARSE_OPT_STOP_AT_NON_OPTION); 652 PARSE_OPT_STOP_AT_NON_OPTION);
495 if (!argc) 653
654 if (csv_sep)
655 csv_output = true;
656 else
657 csv_sep = DEFAULT_SEPARATOR;
658
659 /*
660 * let the spreadsheet do the pretty-printing
661 */
662 if (csv_output) {
663 /* User explicitely passed -B? */
664 if (big_num_opt == 1) {
665 fprintf(stderr, "-B option not supported with -x\n");
666 usage_with_options(stat_usage, options);
667 } else /* Nope, so disable big number formatting */
668 big_num = false;
669 } else if (big_num_opt == 0) /* User passed --no-big-num */
670 big_num = false;
671
672 if (!argc && target_pid == -1 && target_tid == -1)
496 usage_with_options(stat_usage, options); 673 usage_with_options(stat_usage, options);
497 if (run_count <= 0) 674 if (run_count <= 0)
498 usage_with_options(stat_usage, options); 675 usage_with_options(stat_usage, options);
499 676
677 /* no_aggr is for system-wide only */
678 if (no_aggr && !system_wide)
679 usage_with_options(stat_usage, options);
680
500 /* Set attrs and nr_counters if no event is selected and !null_run */ 681 /* Set attrs and nr_counters if no event is selected and !null_run */
501 if (!null_run && !nr_counters) { 682 if (!null_run && !nr_counters) {
502 memcpy(attrs, default_attrs, sizeof(default_attrs)); 683 size_t c;
684
503 nr_counters = ARRAY_SIZE(default_attrs); 685 nr_counters = ARRAY_SIZE(default_attrs);
686
687 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
688 pos = perf_evsel__new(&default_attrs[c],
689 nr_counters);
690 if (pos == NULL)
691 goto out;
692 list_add(&pos->node, &evsel_list);
693 }
694 }
695
696 if (target_pid != -1)
697 target_tid = target_pid;
698
699 threads = thread_map__new(target_pid, target_tid);
700 if (threads == NULL) {
701 pr_err("Problems finding threads of monitor\n");
702 usage_with_options(stat_usage, options);
703 }
704
705 if (system_wide)
706 cpus = cpu_map__new(cpu_list);
707 else
708 cpus = cpu_map__dummy_new();
709
710 if (cpus == NULL) {
711 perror("failed to parse CPUs map");
712 usage_with_options(stat_usage, options);
713 return -1;
504 } 714 }
505 715
506 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 716 list_for_each_entry(pos, &evsel_list, node) {
507 assert(nr_cpus <= MAX_NR_CPUS); 717 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
508 assert((int)nr_cpus >= 0); 718 perf_evsel__alloc_counts(pos, cpus->nr) < 0 ||
719 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
720 goto out_free_fd;
721 }
509 722
510 /* 723 /*
511 * We dont want to block the signals - that would cause 724 * We dont want to block the signals - that would cause
@@ -525,7 +738,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
525 status = run_perf_stat(argc, argv); 738 status = run_perf_stat(argc, argv);
526 } 739 }
527 740
528 print_stat(argc, argv); 741 if (status != -1)
529 742 print_stat(argc, argv);
743out_free_fd:
744 list_for_each_entry(pos, &evsel_list, node)
745 perf_evsel__free_stat_priv(pos);
746 perf_evsel_list__delete();
747out:
748 thread_map__delete(threads);
749 threads = NULL;
530 return status; 750 return status;
531} 751}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
new file mode 100644
index 000000000000..ed5696198d3d
--- /dev/null
+++ b/tools/perf/builtin-test.c
@@ -0,0 +1,497 @@
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/parse-options.h"
11#include "util/session.h"
12#include "util/symbol.h"
13#include "util/thread.h"
14
15static long page_size;
16
17static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
18{
19 bool *visited = symbol__priv(sym);
20 *visited = true;
21 return 0;
22}
23
24static int test__vmlinux_matches_kallsyms(void)
25{
26 int err = -1;
27 struct rb_node *nd;
28 struct symbol *sym;
29 struct map *kallsyms_map, *vmlinux_map;
30 struct machine kallsyms, vmlinux;
31 enum map_type type = MAP__FUNCTION;
32 struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
33
34 /*
35 * Step 1:
36 *
37 * Init the machines that will hold kernel, modules obtained from
38 * both vmlinux + .ko files and from /proc/kallsyms split by modules.
39 */
40 machine__init(&kallsyms, "", HOST_KERNEL_ID);
41 machine__init(&vmlinux, "", HOST_KERNEL_ID);
42
43 /*
44 * Step 2:
45 *
46 * Create the kernel maps for kallsyms and the DSO where we will then
47 * load /proc/kallsyms. Also create the modules maps from /proc/modules
48 * and find the .ko files that match them in /lib/modules/`uname -r`/.
49 */
50 if (machine__create_kernel_maps(&kallsyms) < 0) {
51 pr_debug("machine__create_kernel_maps ");
52 return -1;
53 }
54
55 /*
56 * Step 3:
57 *
58 * Load and split /proc/kallsyms into multiple maps, one per module.
59 */
60 if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) {
61 pr_debug("dso__load_kallsyms ");
62 goto out;
63 }
64
65 /*
66 * Step 4:
67 *
68 * kallsyms will be internally on demand sorted by name so that we can
69 * find the reference relocation * symbol, i.e. the symbol we will use
70 * to see if the running kernel was relocated by checking if it has the
71 * same value in the vmlinux file we load.
72 */
73 kallsyms_map = machine__kernel_map(&kallsyms, type);
74
75 sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL);
76 if (sym == NULL) {
77 pr_debug("dso__find_symbol_by_name ");
78 goto out;
79 }
80
81 ref_reloc_sym.addr = sym->start;
82
83 /*
84 * Step 5:
85 *
86 * Now repeat step 2, this time for the vmlinux file we'll auto-locate.
87 */
88 if (machine__create_kernel_maps(&vmlinux) < 0) {
89 pr_debug("machine__create_kernel_maps ");
90 goto out;
91 }
92
93 vmlinux_map = machine__kernel_map(&vmlinux, type);
94 map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym;
95
96 /*
97 * Step 6:
98 *
99 * Locate a vmlinux file in the vmlinux path that has a buildid that
100 * matches the one of the running kernel.
101 *
102 * While doing that look if we find the ref reloc symbol, if we find it
103 * we'll have its ref_reloc_symbol.unrelocated_addr and then
104 * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
105 * to fixup the symbols.
106 */
107 if (machine__load_vmlinux_path(&vmlinux, type,
108 vmlinux_matches_kallsyms_filter) <= 0) {
109 pr_debug("machine__load_vmlinux_path ");
110 goto out;
111 }
112
113 err = 0;
114 /*
115 * Step 7:
116 *
117 * Now look at the symbols in the vmlinux DSO and check if we find all of them
118 * in the kallsyms dso. For the ones that are in both, check its names and
119 * end addresses too.
120 */
121 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
122 struct symbol *pair, *first_pair;
123 bool backwards = true;
124
125 sym = rb_entry(nd, struct symbol, rb_node);
126
127 if (sym->start == sym->end)
128 continue;
129
130 first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
131 pair = first_pair;
132
133 if (pair && pair->start == sym->start) {
134next_pair:
135 if (strcmp(sym->name, pair->name) == 0) {
136 /*
137 * kallsyms don't have the symbol end, so we
138 * set that by using the next symbol start - 1,
139 * in some cases we get this up to a page
140 * wrong, trace_kmalloc when I was developing
141 * this code was one such example, 2106 bytes
142 * off the real size. More than that and we
143 * _really_ have a problem.
144 */
145 s64 skew = sym->end - pair->end;
146 if (llabs(skew) < page_size)
147 continue;
148
149 pr_debug("%#Lx: diff end addr for %s v: %#Lx k: %#Lx\n",
150 sym->start, sym->name, sym->end, pair->end);
151 } else {
152 struct rb_node *nnd;
153detour:
154 nnd = backwards ? rb_prev(&pair->rb_node) :
155 rb_next(&pair->rb_node);
156 if (nnd) {
157 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
158
159 if (next->start == sym->start) {
160 pair = next;
161 goto next_pair;
162 }
163 }
164
165 if (backwards) {
166 backwards = false;
167 pair = first_pair;
168 goto detour;
169 }
170
171 pr_debug("%#Lx: diff name v: %s k: %s\n",
172 sym->start, sym->name, pair->name);
173 }
174 } else
175 pr_debug("%#Lx: %s not on kallsyms\n", sym->start, sym->name);
176
177 err = -1;
178 }
179
180 if (!verbose)
181 goto out;
182
183 pr_info("Maps only in vmlinux:\n");
184
185 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
186 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
187 /*
188 * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
189 * the kernel will have the path for the vmlinux file being used,
190 * so use the short name, less descriptive but the same ("[kernel]" in
191 * both cases.
192 */
193 pair = map_groups__find_by_name(&kallsyms.kmaps, type,
194 (pos->dso->kernel ?
195 pos->dso->short_name :
196 pos->dso->name));
197 if (pair)
198 pair->priv = 1;
199 else
200 map__fprintf(pos, stderr);
201 }
202
203 pr_info("Maps in vmlinux with a different name in kallsyms:\n");
204
205 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
206 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
207
208 pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
209 if (pair == NULL || pair->priv)
210 continue;
211
212 if (pair->start == pos->start) {
213 pair->priv = 1;
214 pr_info(" %Lx-%Lx %Lx %s in kallsyms as",
215 pos->start, pos->end, pos->pgoff, pos->dso->name);
216 if (pos->pgoff != pair->pgoff || pos->end != pair->end)
217 pr_info(": \n*%Lx-%Lx %Lx",
218 pair->start, pair->end, pair->pgoff);
219 pr_info(" %s\n", pair->dso->name);
220 pair->priv = 1;
221 }
222 }
223
224 pr_info("Maps only in kallsyms:\n");
225
226 for (nd = rb_first(&kallsyms.kmaps.maps[type]);
227 nd; nd = rb_next(nd)) {
228 struct map *pos = rb_entry(nd, struct map, rb_node);
229
230 if (!pos->priv)
231 map__fprintf(pos, stderr);
232 }
233out:
234 return err;
235}
236
237#include "util/cpumap.h"
238#include "util/evsel.h"
239#include <sys/types.h>
240
241static int trace_event__id(const char *event_name)
242{
243 char *filename;
244 int err = -1, fd;
245
246 if (asprintf(&filename,
247 "/sys/kernel/debug/tracing/events/syscalls/%s/id",
248 event_name) < 0)
249 return -1;
250
251 fd = open(filename, O_RDONLY);
252 if (fd >= 0) {
253 char id[16];
254 if (read(fd, id, sizeof(id)) > 0)
255 err = atoi(id);
256 close(fd);
257 }
258
259 free(filename);
260 return err;
261}
262
263static int test__open_syscall_event(void)
264{
265 int err = -1, fd;
266 struct thread_map *threads;
267 struct perf_evsel *evsel;
268 struct perf_event_attr attr;
269 unsigned int nr_open_calls = 111, i;
270 int id = trace_event__id("sys_enter_open");
271
272 if (id < 0) {
273 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
274 return -1;
275 }
276
277 threads = thread_map__new(-1, getpid());
278 if (threads == NULL) {
279 pr_debug("thread_map__new\n");
280 return -1;
281 }
282
283 memset(&attr, 0, sizeof(attr));
284 attr.type = PERF_TYPE_TRACEPOINT;
285 attr.config = id;
286 evsel = perf_evsel__new(&attr, 0);
287 if (evsel == NULL) {
288 pr_debug("perf_evsel__new\n");
289 goto out_thread_map_delete;
290 }
291
292 if (perf_evsel__open_per_thread(evsel, threads) < 0) {
293 pr_debug("failed to open counter: %s, "
294 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
295 strerror(errno));
296 goto out_evsel_delete;
297 }
298
299 for (i = 0; i < nr_open_calls; ++i) {
300 fd = open("/etc/passwd", O_RDONLY);
301 close(fd);
302 }
303
304 if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
305 pr_debug("perf_evsel__open_read_on_cpu\n");
306 goto out_close_fd;
307 }
308
309 if (evsel->counts->cpu[0].val != nr_open_calls) {
310 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %Ld\n",
311 nr_open_calls, evsel->counts->cpu[0].val);
312 goto out_close_fd;
313 }
314
315 err = 0;
316out_close_fd:
317 perf_evsel__close_fd(evsel, 1, threads->nr);
318out_evsel_delete:
319 perf_evsel__delete(evsel);
320out_thread_map_delete:
321 thread_map__delete(threads);
322 return err;
323}
324
325#include <sched.h>
326
327static int test__open_syscall_event_on_all_cpus(void)
328{
329 int err = -1, fd, cpu;
330 struct thread_map *threads;
331 struct cpu_map *cpus;
332 struct perf_evsel *evsel;
333 struct perf_event_attr attr;
334 unsigned int nr_open_calls = 111, i;
335 cpu_set_t *cpu_set;
336 size_t cpu_set_size;
337 int id = trace_event__id("sys_enter_open");
338
339 if (id < 0) {
340 pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
341 return -1;
342 }
343
344 threads = thread_map__new(-1, getpid());
345 if (threads == NULL) {
346 pr_debug("thread_map__new\n");
347 return -1;
348 }
349
350 cpus = cpu_map__new(NULL);
351 if (threads == NULL) {
352 pr_debug("thread_map__new\n");
353 return -1;
354 }
355
356 cpu_set = CPU_ALLOC(cpus->nr);
357
358 if (cpu_set == NULL)
359 goto out_thread_map_delete;
360
361 cpu_set_size = CPU_ALLOC_SIZE(cpus->nr);
362 CPU_ZERO_S(cpu_set_size, cpu_set);
363
364 memset(&attr, 0, sizeof(attr));
365 attr.type = PERF_TYPE_TRACEPOINT;
366 attr.config = id;
367 evsel = perf_evsel__new(&attr, 0);
368 if (evsel == NULL) {
369 pr_debug("perf_evsel__new\n");
370 goto out_cpu_free;
371 }
372
373 if (perf_evsel__open(evsel, cpus, threads) < 0) {
374 pr_debug("failed to open counter: %s, "
375 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
376 strerror(errno));
377 goto out_evsel_delete;
378 }
379
380 for (cpu = 0; cpu < cpus->nr; ++cpu) {
381 unsigned int ncalls = nr_open_calls + cpu;
382
383 CPU_SET(cpu, cpu_set);
384 sched_setaffinity(0, cpu_set_size, cpu_set);
385 for (i = 0; i < ncalls; ++i) {
386 fd = open("/etc/passwd", O_RDONLY);
387 close(fd);
388 }
389 CPU_CLR(cpu, cpu_set);
390 }
391
392 /*
393 * Here we need to explicitely preallocate the counts, as if
394 * we use the auto allocation it will allocate just for 1 cpu,
395 * as we start by cpu 0.
396 */
397 if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
398 pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
399 goto out_close_fd;
400 }
401
402 for (cpu = 0; cpu < cpus->nr; ++cpu) {
403 unsigned int expected;
404
405 if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
406 pr_debug("perf_evsel__open_read_on_cpu\n");
407 goto out_close_fd;
408 }
409
410 expected = nr_open_calls + cpu;
411 if (evsel->counts->cpu[cpu].val != expected) {
412 pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %Ld\n",
413 expected, cpu, evsel->counts->cpu[cpu].val);
414 goto out_close_fd;
415 }
416 }
417
418 err = 0;
419out_close_fd:
420 perf_evsel__close_fd(evsel, 1, threads->nr);
421out_evsel_delete:
422 perf_evsel__delete(evsel);
423out_cpu_free:
424 CPU_FREE(cpu_set);
425out_thread_map_delete:
426 thread_map__delete(threads);
427 return err;
428}
429
430static struct test {
431 const char *desc;
432 int (*func)(void);
433} tests[] = {
434 {
435 .desc = "vmlinux symtab matches kallsyms",
436 .func = test__vmlinux_matches_kallsyms,
437 },
438 {
439 .desc = "detect open syscall event",
440 .func = test__open_syscall_event,
441 },
442 {
443 .desc = "detect open syscall event on all cpus",
444 .func = test__open_syscall_event_on_all_cpus,
445 },
446 {
447 .func = NULL,
448 },
449};
450
451static int __cmd_test(void)
452{
453 int i = 0;
454
455 page_size = sysconf(_SC_PAGE_SIZE);
456
457 while (tests[i].func) {
458 int err;
459 pr_info("%2d: %s:", i + 1, tests[i].desc);
460 pr_debug("\n--- start ---\n");
461 err = tests[i].func();
462 pr_debug("---- end ----\n%s:", tests[i].desc);
463 pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
464 ++i;
465 }
466
467 return 0;
468}
469
470static const char * const test_usage[] = {
471 "perf test [<options>]",
472 NULL,
473};
474
475static const struct option test_options[] = {
476 OPT_INTEGER('v', "verbose", &verbose,
477 "be more verbose (show symbol address, etc)"),
478 OPT_END()
479};
480
481int cmd_test(int argc, const char **argv, const char *prefix __used)
482{
483 argc = parse_options(argc, argv, test_options, test_usage, 0);
484 if (argc)
485 usage_with_options(test_usage, test_options);
486
487 symbol_conf.priv_size = sizeof(int);
488 symbol_conf.sort_by_name = true;
489 symbol_conf.try_vmlinux_path = true;
490
491 if (symbol__init() < 0)
492 return -1;
493
494 setup_pager();
495
496 return __cmd_test();
497}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 3f8bbcfb1e9b..746cf03cb05d 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -21,7 +21,6 @@
21#include "util/cache.h" 21#include "util/cache.h"
22#include <linux/rbtree.h> 22#include <linux/rbtree.h>
23#include "util/symbol.h" 23#include "util/symbol.h"
24#include "util/string.h"
25#include "util/callchain.h" 24#include "util/callchain.h"
26#include "util/strlist.h" 25#include "util/strlist.h"
27 26
@@ -33,6 +32,10 @@
33#include "util/session.h" 32#include "util/session.h"
34#include "util/svghelper.h" 33#include "util/svghelper.h"
35 34
35#define SUPPORT_OLD_POWER_EVENTS 1
36#define PWR_EVENT_EXIT -1
37
38
36static char const *input_name = "perf.data"; 39static char const *input_name = "perf.data";
37static char const *output_name = "output.svg"; 40static char const *output_name = "output.svg";
38 41
@@ -43,7 +46,7 @@ static u64 turbo_frequency;
43 46
44static u64 first_time, last_time; 47static u64 first_time, last_time;
45 48
46static int power_only; 49static bool power_only;
47 50
48 51
49struct per_pid; 52struct per_pid;
@@ -78,8 +81,6 @@ struct per_pid {
78 81
79 struct per_pidcomm *all; 82 struct per_pidcomm *all;
80 struct per_pidcomm *current; 83 struct per_pidcomm *current;
81
82 int painted;
83}; 84};
84 85
85 86
@@ -146,9 +147,6 @@ struct wake_event {
146static struct power_event *power_events; 147static struct power_event *power_events;
147static struct wake_event *wake_events; 148static struct wake_event *wake_events;
148 149
149struct sample_wrapper *all_samples;
150
151
152struct process_filter; 150struct process_filter;
153struct process_filter { 151struct process_filter {
154 char *name; 152 char *name;
@@ -278,19 +276,22 @@ static int cpus_cstate_state[MAX_CPUS];
278static u64 cpus_pstate_start_times[MAX_CPUS]; 276static u64 cpus_pstate_start_times[MAX_CPUS];
279static u64 cpus_pstate_state[MAX_CPUS]; 277static u64 cpus_pstate_state[MAX_CPUS];
280 278
281static int process_comm_event(event_t *event, struct perf_session *session __used) 279static int process_comm_event(event_t *event, struct sample_data *sample __used,
280 struct perf_session *session __used)
282{ 281{
283 pid_set_comm(event->comm.tid, event->comm.comm); 282 pid_set_comm(event->comm.tid, event->comm.comm);
284 return 0; 283 return 0;
285} 284}
286 285
287static int process_fork_event(event_t *event, struct perf_session *session __used) 286static int process_fork_event(event_t *event, struct sample_data *sample __used,
287 struct perf_session *session __used)
288{ 288{
289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); 289 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
290 return 0; 290 return 0;
291} 291}
292 292
293static int process_exit_event(event_t *event, struct perf_session *session __used) 293static int process_exit_event(event_t *event, struct sample_data *sample __used,
294 struct perf_session *session __used)
294{ 295{
295 pid_exit(event->fork.pid, event->fork.time); 296 pid_exit(event->fork.pid, event->fork.time);
296 return 0; 297 return 0;
@@ -304,10 +305,20 @@ struct trace_entry {
304 int lock_depth; 305 int lock_depth;
305}; 306};
306 307
307struct power_entry { 308#ifdef SUPPORT_OLD_POWER_EVENTS
309static int use_old_power_events;
310struct power_entry_old {
308 struct trace_entry te; 311 struct trace_entry te;
309 s64 type; 312 u64 type;
310 s64 value; 313 u64 value;
314 u64 cpu_id;
315};
316#endif
317
318struct power_processor_entry {
319 struct trace_entry te;
320 u32 state;
321 u32 cpu_id;
311}; 322};
312 323
313#define TASK_COMM_LEN 16 324#define TASK_COMM_LEN 16
@@ -460,8 +471,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
460 if (p->current->state != TYPE_NONE) 471 if (p->current->state != TYPE_NONE)
461 pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp); 472 pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp);
462 473
463 p->current->state_since = timestamp; 474 p->current->state_since = timestamp;
464 p->current->state = TYPE_RUNNING; 475 p->current->state = TYPE_RUNNING;
465 } 476 }
466 477
467 if (prev_p->current) { 478 if (prev_p->current) {
@@ -475,48 +486,65 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
475} 486}
476 487
477 488
478static int process_sample_event(event_t *event, struct perf_session *session) 489static int process_sample_event(event_t *event __used,
490 struct sample_data *sample,
491 struct perf_session *session)
479{ 492{
480 struct sample_data data;
481 struct trace_entry *te; 493 struct trace_entry *te;
482 494
483 memset(&data, 0, sizeof(data));
484
485 event__parse_sample(event, session->sample_type, &data);
486
487 if (session->sample_type & PERF_SAMPLE_TIME) { 495 if (session->sample_type & PERF_SAMPLE_TIME) {
488 if (!first_time || first_time > data.time) 496 if (!first_time || first_time > sample->time)
489 first_time = data.time; 497 first_time = sample->time;
490 if (last_time < data.time) 498 if (last_time < sample->time)
491 last_time = data.time; 499 last_time = sample->time;
492 } 500 }
493 501
494 te = (void *)data.raw_data; 502 te = (void *)sample->raw_data;
495 if (session->sample_type & PERF_SAMPLE_RAW && data.raw_size > 0) { 503 if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) {
496 char *event_str; 504 char *event_str;
497 struct power_entry *pe; 505#ifdef SUPPORT_OLD_POWER_EVENTS
498 506 struct power_entry_old *peo;
499 pe = (void *)te; 507 peo = (void *)te;
500 508#endif
501 event_str = perf_header__find_event(te->type); 509 event_str = perf_header__find_event(te->type);
502 510
503 if (!event_str) 511 if (!event_str)
504 return 0; 512 return 0;
505 513
506 if (strcmp(event_str, "power:power_start") == 0) 514 if (strcmp(event_str, "power:cpu_idle") == 0) {
507 c_state_start(data.cpu, data.time, pe->value); 515 struct power_processor_entry *ppe = (void *)te;
516 if (ppe->state == (u32)PWR_EVENT_EXIT)
517 c_state_end(ppe->cpu_id, sample->time);
518 else
519 c_state_start(ppe->cpu_id, sample->time,
520 ppe->state);
521 }
522 else if (strcmp(event_str, "power:cpu_frequency") == 0) {
523 struct power_processor_entry *ppe = (void *)te;
524 p_state_change(ppe->cpu_id, sample->time, ppe->state);
525 }
508 526
509 if (strcmp(event_str, "power:power_end") == 0) 527 else if (strcmp(event_str, "sched:sched_wakeup") == 0)
510 c_state_end(data.cpu, data.time); 528 sched_wakeup(sample->cpu, sample->time, sample->pid, te);
511 529
512 if (strcmp(event_str, "power:power_frequency") == 0) 530 else if (strcmp(event_str, "sched:sched_switch") == 0)
513 p_state_change(data.cpu, data.time, pe->value); 531 sched_switch(sample->cpu, sample->time, te);
514 532
515 if (strcmp(event_str, "sched:sched_wakeup") == 0) 533#ifdef SUPPORT_OLD_POWER_EVENTS
516 sched_wakeup(data.cpu, data.time, data.pid, te); 534 if (use_old_power_events) {
535 if (strcmp(event_str, "power:power_start") == 0)
536 c_state_start(peo->cpu_id, sample->time,
537 peo->value);
517 538
518 if (strcmp(event_str, "sched:sched_switch") == 0) 539 else if (strcmp(event_str, "power:power_end") == 0)
519 sched_switch(data.cpu, data.time, te); 540 c_state_end(sample->cpu, sample->time);
541
542 else if (strcmp(event_str,
543 "power:power_frequency") == 0)
544 p_state_change(peo->cpu_id, sample->time,
545 peo->value);
546 }
547#endif
520 } 548 }
521 return 0; 549 return 0;
522} 550}
@@ -569,88 +597,6 @@ static void end_sample_processing(void)
569 } 597 }
570} 598}
571 599
572static u64 sample_time(event_t *event, const struct perf_session *session)
573{
574 int cursor;
575
576 cursor = 0;
577 if (session->sample_type & PERF_SAMPLE_IP)
578 cursor++;
579 if (session->sample_type & PERF_SAMPLE_TID)
580 cursor++;
581 if (session->sample_type & PERF_SAMPLE_TIME)
582 return event->sample.array[cursor];
583 return 0;
584}
585
586
587/*
588 * We first queue all events, sorted backwards by insertion.
589 * The order will get flipped later.
590 */
591static int queue_sample_event(event_t *event, struct perf_session *session)
592{
593 struct sample_wrapper *copy, *prev;
594 int size;
595
596 size = event->sample.header.size + sizeof(struct sample_wrapper) + 8;
597
598 copy = malloc(size);
599 if (!copy)
600 return 1;
601
602 memset(copy, 0, size);
603
604 copy->next = NULL;
605 copy->timestamp = sample_time(event, session);
606
607 memcpy(&copy->data, event, event->sample.header.size);
608
609 /* insert in the right place in the list */
610
611 if (!all_samples) {
612 /* first sample ever */
613 all_samples = copy;
614 return 0;
615 }
616
617 if (all_samples->timestamp < copy->timestamp) {
618 /* insert at the head of the list */
619 copy->next = all_samples;
620 all_samples = copy;
621 return 0;
622 }
623
624 prev = all_samples;
625 while (prev->next) {
626 if (prev->next->timestamp < copy->timestamp) {
627 copy->next = prev->next;
628 prev->next = copy;
629 return 0;
630 }
631 prev = prev->next;
632 }
633 /* insert at the end of the list */
634 prev->next = copy;
635
636 return 0;
637}
638
639static void sort_queued_samples(void)
640{
641 struct sample_wrapper *cursor, *next;
642
643 cursor = all_samples;
644 all_samples = NULL;
645
646 while (cursor) {
647 next = cursor->next;
648 cursor->next = all_samples;
649 all_samples = cursor;
650 cursor = next;
651 }
652}
653
654/* 600/*
655 * Sort the pid datastructure 601 * Sort the pid datastructure
656 */ 602 */
@@ -1014,54 +960,30 @@ static void write_svg_file(const char *filename)
1014 svg_close(); 960 svg_close();
1015} 961}
1016 962
1017static void process_samples(struct perf_session *session)
1018{
1019 struct sample_wrapper *cursor;
1020 event_t *event;
1021
1022 sort_queued_samples();
1023
1024 cursor = all_samples;
1025 while (cursor) {
1026 event = (void *)&cursor->data;
1027 cursor = cursor->next;
1028 process_sample_event(event, session);
1029 }
1030}
1031
1032static int sample_type_check(struct perf_session *session)
1033{
1034 if (!(session->sample_type & PERF_SAMPLE_RAW)) {
1035 fprintf(stderr, "No trace samples found in the file.\n"
1036 "Have you used 'perf timechart record' to record it?\n");
1037 return -1;
1038 }
1039
1040 return 0;
1041}
1042
1043static struct perf_event_ops event_ops = { 963static struct perf_event_ops event_ops = {
1044 .process_comm_event = process_comm_event, 964 .comm = process_comm_event,
1045 .process_fork_event = process_fork_event, 965 .fork = process_fork_event,
1046 .process_exit_event = process_exit_event, 966 .exit = process_exit_event,
1047 .process_sample_event = queue_sample_event, 967 .sample = process_sample_event,
1048 .sample_type_check = sample_type_check, 968 .ordered_samples = true,
1049}; 969};
1050 970
1051static int __cmd_timechart(void) 971static int __cmd_timechart(void)
1052{ 972{
1053 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 973 struct perf_session *session = perf_session__new(input_name, O_RDONLY,
1054 int ret; 974 0, false, &event_ops);
975 int ret = -EINVAL;
1055 976
1056 if (session == NULL) 977 if (session == NULL)
1057 return -ENOMEM; 978 return -ENOMEM;
1058 979
980 if (!perf_session__has_traces(session, "timechart record"))
981 goto out_delete;
982
1059 ret = perf_session__process_events(session, &event_ops); 983 ret = perf_session__process_events(session, &event_ops);
1060 if (ret) 984 if (ret)
1061 goto out_delete; 985 goto out_delete;
1062 986
1063 process_samples(session);
1064
1065 end_sample_processing(); 987 end_sample_processing();
1066 988
1067 sort_pids(); 989 sort_pids();
@@ -1080,11 +1002,11 @@ static const char * const timechart_usage[] = {
1080 NULL 1002 NULL
1081}; 1003};
1082 1004
1083static const char *record_args[] = { 1005#ifdef SUPPORT_OLD_POWER_EVENTS
1006static const char * const record_old_args[] = {
1084 "record", 1007 "record",
1085 "-a", 1008 "-a",
1086 "-R", 1009 "-R",
1087 "-M",
1088 "-f", 1010 "-f",
1089 "-c", "1", 1011 "-c", "1",
1090 "-e", "power:power_start", 1012 "-e", "power:power_start",
@@ -1093,16 +1015,43 @@ static const char *record_args[] = {
1093 "-e", "sched:sched_wakeup", 1015 "-e", "sched:sched_wakeup",
1094 "-e", "sched:sched_switch", 1016 "-e", "sched:sched_switch",
1095}; 1017};
1018#endif
1019
1020static const char * const record_new_args[] = {
1021 "record",
1022 "-a",
1023 "-R",
1024 "-f",
1025 "-c", "1",
1026 "-e", "power:cpu_frequency",
1027 "-e", "power:cpu_idle",
1028 "-e", "sched:sched_wakeup",
1029 "-e", "sched:sched_switch",
1030};
1096 1031
1097static int __cmd_record(int argc, const char **argv) 1032static int __cmd_record(int argc, const char **argv)
1098{ 1033{
1099 unsigned int rec_argc, i, j; 1034 unsigned int rec_argc, i, j;
1100 const char **rec_argv; 1035 const char **rec_argv;
1036 const char * const *record_args = record_new_args;
1037 unsigned int record_elems = ARRAY_SIZE(record_new_args);
1038
1039#ifdef SUPPORT_OLD_POWER_EVENTS
1040 if (!is_valid_tracepoint("power:cpu_idle") &&
1041 is_valid_tracepoint("power:power_start")) {
1042 use_old_power_events = 1;
1043 record_args = record_old_args;
1044 record_elems = ARRAY_SIZE(record_old_args);
1045 }
1046#endif
1101 1047
1102 rec_argc = ARRAY_SIZE(record_args) + argc - 1; 1048 rec_argc = record_elems + argc - 1;
1103 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 1049 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1104 1050
1105 for (i = 0; i < ARRAY_SIZE(record_args); i++) 1051 if (rec_argv == NULL)
1052 return -ENOMEM;
1053
1054 for (i = 0; i < record_elems; i++)
1106 rec_argv[i] = strdup(record_args[i]); 1055 rec_argv[i] = strdup(record_args[i]);
1107 1056
1108 for (j = 1; j < (unsigned int)argc; j++, i++) 1057 for (j = 1; j < (unsigned int)argc; j++, i++)
@@ -1131,6 +1080,8 @@ static const struct option options[] = {
1131 OPT_CALLBACK('p', "process", NULL, "process", 1080 OPT_CALLBACK('p', "process", NULL, "process",
1132 "process selector. Pass a pid or process name.", 1081 "process selector. Pass a pid or process name.",
1133 parse_process), 1082 parse_process),
1083 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
1084 "Look for files with symbols relative to this directory"),
1134 OPT_END() 1085 OPT_END()
1135}; 1086};
1136 1087
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ddc584b64871..05344c6210ac 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -21,6 +21,7 @@
21#include "perf.h" 21#include "perf.h"
22 22
23#include "util/color.h" 23#include "util/color.h"
24#include "util/evsel.h"
24#include "util/session.h" 25#include "util/session.h"
25#include "util/symbol.h" 26#include "util/symbol.h"
26#include "util/thread.h" 27#include "util/thread.h"
@@ -28,6 +29,8 @@
28#include <linux/rbtree.h> 29#include <linux/rbtree.h>
29#include "util/parse-options.h" 30#include "util/parse-options.h"
30#include "util/parse-events.h" 31#include "util/parse-events.h"
32#include "util/cpumap.h"
33#include "util/xyarray.h"
31 34
32#include "util/debug.h" 35#include "util/debug.h"
33 36
@@ -54,9 +57,9 @@
54#include <linux/unistd.h> 57#include <linux/unistd.h>
55#include <linux/types.h> 58#include <linux/types.h>
56 59
57static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 60#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
58 61
59static int system_wide = 0; 62static bool system_wide = false;
60 63
61static int default_interval = 0; 64static int default_interval = 0;
62 65
@@ -64,18 +67,19 @@ static int count_filter = 5;
64static int print_entries; 67static int print_entries;
65 68
66static int target_pid = -1; 69static int target_pid = -1;
67static int inherit = 0; 70static int target_tid = -1;
68static int profile_cpu = -1; 71static struct thread_map *threads;
69static int nr_cpus = 0; 72static bool inherit = false;
70static unsigned int realtime_prio = 0; 73static struct cpu_map *cpus;
71static int group = 0; 74static int realtime_prio = 0;
75static bool group = false;
72static unsigned int page_size; 76static unsigned int page_size;
73static unsigned int mmap_pages = 16; 77static unsigned int mmap_pages = 16;
74static int freq = 1000; /* 1 KHz */ 78static int freq = 1000; /* 1 KHz */
75 79
76static int delay_secs = 2; 80static int delay_secs = 2;
77static int zero = 0; 81static bool zero = false;
78static int dump_symtab = 0; 82static bool dump_symtab = false;
79 83
80static bool hide_kernel_symbols = false; 84static bool hide_kernel_symbols = false;
81static bool hide_user_symbols = false; 85static bool hide_user_symbols = false;
@@ -92,11 +96,14 @@ struct source_line {
92 struct source_line *next; 96 struct source_line *next;
93}; 97};
94 98
95static char *sym_filter = NULL; 99static const char *sym_filter = NULL;
96struct sym_entry *sym_filter_entry = NULL; 100struct sym_entry *sym_filter_entry = NULL;
101struct sym_entry *sym_filter_entry_sched = NULL;
97static int sym_pcnt_filter = 5; 102static int sym_pcnt_filter = 5;
98static int sym_counter = 0; 103static int sym_counter = 0;
104static struct perf_evsel *sym_evsel = NULL;
99static int display_weighted = -1; 105static int display_weighted = -1;
106static const char *cpu_list;
100 107
101/* 108/*
102 * Symbols 109 * Symbols
@@ -131,7 +138,7 @@ static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
131 return ((void *)self) + symbol_conf.priv_size; 138 return ((void *)self) + symbol_conf.priv_size;
132} 139}
133 140
134static void get_term_dimensions(struct winsize *ws) 141void get_term_dimensions(struct winsize *ws)
135{ 142{
136 char *s = getenv("LINES"); 143 char *s = getenv("LINES");
137 144
@@ -167,7 +174,7 @@ static void sig_winch_handler(int sig __used)
167 update_print_entries(&winsize); 174 update_print_entries(&winsize);
168} 175}
169 176
170static void parse_source(struct sym_entry *syme) 177static int parse_source(struct sym_entry *syme)
171{ 178{
172 struct symbol *sym; 179 struct symbol *sym;
173 struct sym_entry_source *source; 180 struct sym_entry_source *source;
@@ -178,12 +185,21 @@ static void parse_source(struct sym_entry *syme)
178 u64 len; 185 u64 len;
179 186
180 if (!syme) 187 if (!syme)
181 return; 188 return -1;
189
190 sym = sym_entry__symbol(syme);
191 map = syme->map;
192
193 /*
194 * We can't annotate with just /proc/kallsyms
195 */
196 if (map->dso->origin == DSO__ORIG_KERNEL)
197 return -1;
182 198
183 if (syme->src == NULL) { 199 if (syme->src == NULL) {
184 syme->src = zalloc(sizeof(*source)); 200 syme->src = zalloc(sizeof(*source));
185 if (syme->src == NULL) 201 if (syme->src == NULL)
186 return; 202 return -1;
187 pthread_mutex_init(&syme->src->lock, NULL); 203 pthread_mutex_init(&syme->src->lock, NULL);
188 } 204 }
189 205
@@ -193,29 +209,25 @@ static void parse_source(struct sym_entry *syme)
193 pthread_mutex_lock(&source->lock); 209 pthread_mutex_lock(&source->lock);
194 goto out_assign; 210 goto out_assign;
195 } 211 }
196
197 sym = sym_entry__symbol(syme);
198 map = syme->map;
199 path = map->dso->long_name; 212 path = map->dso->long_name;
200 213
201 len = sym->end - sym->start; 214 len = sym->end - sym->start;
202 215
203 sprintf(command, 216 sprintf(command,
204 "objdump --start-address=0x%016Lx " 217 "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
205 "--stop-address=0x%016Lx -dS %s", 218 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
206 map->unmap_ip(map, sym->start), 219 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
207 map->unmap_ip(map, sym->end), path);
208 220
209 file = popen(command, "r"); 221 file = popen(command, "r");
210 if (!file) 222 if (!file)
211 return; 223 return -1;
212 224
213 pthread_mutex_lock(&source->lock); 225 pthread_mutex_lock(&source->lock);
214 source->lines_tail = &source->lines; 226 source->lines_tail = &source->lines;
215 while (!feof(file)) { 227 while (!feof(file)) {
216 struct source_line *src; 228 struct source_line *src;
217 size_t dummy = 0; 229 size_t dummy = 0;
218 char *c; 230 char *c, *sep;
219 231
220 src = malloc(sizeof(struct source_line)); 232 src = malloc(sizeof(struct source_line));
221 assert(src != NULL); 233 assert(src != NULL);
@@ -234,19 +246,17 @@ static void parse_source(struct sym_entry *syme)
234 *source->lines_tail = src; 246 *source->lines_tail = src;
235 source->lines_tail = &src->next; 247 source->lines_tail = &src->next;
236 248
237 if (strlen(src->line)>8 && src->line[8] == ':') { 249 src->eip = strtoull(src->line, &sep, 16);
238 src->eip = strtoull(src->line, NULL, 16); 250 if (*sep == ':')
239 src->eip = map->unmap_ip(map, src->eip); 251 src->eip = map__objdump_2ip(map, src->eip);
240 } 252 else /* this line has no ip info (e.g. source line) */
241 if (strlen(src->line)>8 && src->line[16] == ':') { 253 src->eip = 0;
242 src->eip = strtoull(src->line, NULL, 16);
243 src->eip = map->unmap_ip(map, src->eip);
244 }
245 } 254 }
246 pclose(file); 255 pclose(file);
247out_assign: 256out_assign:
248 sym_filter_entry = syme; 257 sym_filter_entry = syme;
249 pthread_mutex_unlock(&source->lock); 258 pthread_mutex_unlock(&source->lock);
259 return 0;
250} 260}
251 261
252static void __zero_source_counters(struct sym_entry *syme) 262static void __zero_source_counters(struct sym_entry *syme)
@@ -276,6 +286,9 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
276 goto out_unlock; 286 goto out_unlock;
277 287
278 for (line = syme->src->lines; line; line = line->next) { 288 for (line = syme->src->lines; line; line = line->next) {
289 /* skip lines without IP info */
290 if (line->eip == 0)
291 continue;
279 if (line->eip == ip) { 292 if (line->eip == ip) {
280 line->count[counter]++; 293 line->count[counter]++;
281 break; 294 break;
@@ -287,17 +300,20 @@ out_unlock:
287 pthread_mutex_unlock(&syme->src->lock); 300 pthread_mutex_unlock(&syme->src->lock);
288} 301}
289 302
303#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
304
290static void lookup_sym_source(struct sym_entry *syme) 305static void lookup_sym_source(struct sym_entry *syme)
291{ 306{
292 struct symbol *symbol = sym_entry__symbol(syme); 307 struct symbol *symbol = sym_entry__symbol(syme);
293 struct source_line *line; 308 struct source_line *line;
294 char pattern[PATH_MAX]; 309 char pattern[PATTERN_LEN + 1];
295 310
296 sprintf(pattern, "<%s>:", symbol->name); 311 sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
312 map__rip_2objdump(syme->map, symbol->start));
297 313
298 pthread_mutex_lock(&syme->src->lock); 314 pthread_mutex_lock(&syme->src->lock);
299 for (line = syme->src->lines; line; line = line->next) { 315 for (line = syme->src->lines; line; line = line->next) {
300 if (strstr(line->line, pattern)) { 316 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
301 syme->src->source = line; 317 syme->src->source = line;
302 break; 318 break;
303 } 319 }
@@ -339,7 +355,7 @@ static void show_details(struct sym_entry *syme)
339 return; 355 return;
340 356
341 symbol = sym_entry__symbol(syme); 357 symbol = sym_entry__symbol(syme);
342 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); 358 printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name);
343 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 359 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
344 360
345 pthread_mutex_lock(&syme->src->lock); 361 pthread_mutex_lock(&syme->src->lock);
@@ -406,7 +422,9 @@ static double sym_weight(const struct sym_entry *sym)
406} 422}
407 423
408static long samples; 424static long samples;
409static long userspace_samples; 425static long kernel_samples, us_samples;
426static long exact_samples;
427static long guest_us_samples, guest_kernel_samples;
410static const char CONSOLE_CLEAR[] = ""; 428static const char CONSOLE_CLEAR[] = "";
411 429
412static void __list_insert_active_sym(struct sym_entry *syme) 430static void __list_insert_active_sym(struct sym_entry *syme)
@@ -444,17 +462,23 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
444static void print_sym_table(void) 462static void print_sym_table(void)
445{ 463{
446 int printed = 0, j; 464 int printed = 0, j;
447 int counter, snap = !display_weighted ? sym_counter : 0; 465 struct perf_evsel *counter;
466 int snap = !display_weighted ? sym_counter : 0;
448 float samples_per_sec = samples/delay_secs; 467 float samples_per_sec = samples/delay_secs;
449 float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 468 float ksamples_per_sec = kernel_samples/delay_secs;
469 float us_samples_per_sec = (us_samples)/delay_secs;
470 float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
471 float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
472 float esamples_percent = (100.0*exact_samples)/samples;
450 float sum_ksamples = 0.0; 473 float sum_ksamples = 0.0;
451 struct sym_entry *syme, *n; 474 struct sym_entry *syme, *n;
452 struct rb_root tmp = RB_ROOT; 475 struct rb_root tmp = RB_ROOT;
453 struct rb_node *nd; 476 struct rb_node *nd;
454 int sym_width = 0, dso_width = 0, max_dso_width; 477 int sym_width = 0, dso_width = 0, dso_short_width = 0;
455 const int win_width = winsize.ws_col - 1; 478 const int win_width = winsize.ws_col - 1;
456 479
457 samples = userspace_samples = 0; 480 samples = us_samples = kernel_samples = exact_samples = 0;
481 guest_kernel_samples = guest_us_samples = 0;
458 482
459 /* Sort the active symbols */ 483 /* Sort the active symbols */
460 pthread_mutex_lock(&active_symbols_lock); 484 pthread_mutex_lock(&active_symbols_lock);
@@ -485,12 +509,35 @@ static void print_sym_table(void)
485 puts(CONSOLE_CLEAR); 509 puts(CONSOLE_CLEAR);
486 510
487 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 511 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
488 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", 512 if (!perf_guest) {
489 samples_per_sec, 513 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
490 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 514 " exact: %4.1f%% [",
515 samples_per_sec,
516 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
517 samples_per_sec)),
518 esamples_percent);
519 } else {
520 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
521 " guest kernel:%4.1f%% guest us:%4.1f%%"
522 " exact: %4.1f%% [",
523 samples_per_sec,
524 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
525 samples_per_sec)),
526 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
527 samples_per_sec)),
528 100.0 - (100.0 * ((samples_per_sec -
529 guest_kernel_samples_per_sec) /
530 samples_per_sec)),
531 100.0 - (100.0 * ((samples_per_sec -
532 guest_us_samples_per_sec) /
533 samples_per_sec)),
534 esamples_percent);
535 }
491 536
492 if (nr_counters == 1 || !display_weighted) { 537 if (nr_counters == 1 || !display_weighted) {
493 printf("%Ld", (u64)attrs[0].sample_period); 538 struct perf_evsel *first;
539 first = list_entry(evsel_list.next, struct perf_evsel, node);
540 printf("%Ld", first->attr.sample_period);
494 if (freq) 541 if (freq)
495 printf("Hz "); 542 printf("Hz ");
496 else 543 else
@@ -498,9 +545,9 @@ static void print_sym_table(void)
498 } 545 }
499 546
500 if (!display_weighted) 547 if (!display_weighted)
501 printf("%s", event_name(sym_counter)); 548 printf("%s", event_name(sym_evsel));
502 else for (counter = 0; counter < nr_counters; counter++) { 549 else list_for_each_entry(counter, &evsel_list, node) {
503 if (counter) 550 if (counter->idx)
504 printf("/"); 551 printf("/");
505 552
506 printf("%s", event_name(counter)); 553 printf("%s", event_name(counter));
@@ -510,16 +557,18 @@ static void print_sym_table(void)
510 557
511 if (target_pid != -1) 558 if (target_pid != -1)
512 printf(" (target_pid: %d", target_pid); 559 printf(" (target_pid: %d", target_pid);
560 else if (target_tid != -1)
561 printf(" (target_tid: %d", target_tid);
513 else 562 else
514 printf(" (all"); 563 printf(" (all");
515 564
516 if (profile_cpu != -1) 565 if (cpu_list)
517 printf(", cpu: %d)\n", profile_cpu); 566 printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list);
518 else { 567 else {
519 if (target_pid != -1) 568 if (target_tid != -1)
520 printf(")\n"); 569 printf(")\n");
521 else 570 else
522 printf(", %d CPUs)\n", nr_cpus); 571 printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : "");
523 } 572 }
524 573
525 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 574 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
@@ -541,15 +590,20 @@ static void print_sym_table(void)
541 if (syme->map->dso->long_name_len > dso_width) 590 if (syme->map->dso->long_name_len > dso_width)
542 dso_width = syme->map->dso->long_name_len; 591 dso_width = syme->map->dso->long_name_len;
543 592
593 if (syme->map->dso->short_name_len > dso_short_width)
594 dso_short_width = syme->map->dso->short_name_len;
595
544 if (syme->name_len > sym_width) 596 if (syme->name_len > sym_width)
545 sym_width = syme->name_len; 597 sym_width = syme->name_len;
546 } 598 }
547 599
548 printed = 0; 600 printed = 0;
549 601
550 max_dso_width = winsize.ws_col - sym_width - 29; 602 if (sym_width + dso_width > winsize.ws_col - 29) {
551 if (dso_width > max_dso_width) 603 dso_width = dso_short_width;
552 dso_width = max_dso_width; 604 if (sym_width + dso_width > winsize.ws_col - 29)
605 sym_width = winsize.ws_col - dso_width - 29;
606 }
553 putchar('\n'); 607 putchar('\n');
554 if (nr_counters == 1) 608 if (nr_counters == 1)
555 printf(" samples pcnt"); 609 printf(" samples pcnt");
@@ -573,7 +627,6 @@ static void print_sym_table(void)
573 627
574 syme = rb_entry(nd, struct sym_entry, rb_node); 628 syme = rb_entry(nd, struct sym_entry, rb_node);
575 sym = sym_entry__symbol(syme); 629 sym = sym_entry__symbol(syme);
576
577 if (++printed > print_entries || (int)syme->snap_count < count_filter) 630 if (++printed > print_entries || (int)syme->snap_count < count_filter)
578 continue; 631 continue;
579 632
@@ -667,7 +720,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
667 } 720 }
668 721
669 if (!found) { 722 if (!found) {
670 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); 723 fprintf(stderr, "Sorry, %s is not active.\n", buf);
671 sleep(1); 724 sleep(1);
672 return; 725 return;
673 } else 726 } else
@@ -691,21 +744,19 @@ static void print_mapped_keys(void)
691 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); 744 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries);
692 745
693 if (nr_counters > 1) 746 if (nr_counters > 1)
694 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); 747 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel));
695 748
696 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 749 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
697 750
698 if (symbol_conf.vmlinux_name) { 751 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
699 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 752 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
700 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 753 fprintf(stdout, "\t[S] stop annotation.\n");
701 fprintf(stdout, "\t[S] stop annotation.\n");
702 }
703 754
704 if (nr_counters > 1) 755 if (nr_counters > 1)
705 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 756 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
706 757
707 fprintf(stdout, 758 fprintf(stdout,
708 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 759 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
709 hide_kernel_symbols ? "yes" : "no"); 760 hide_kernel_symbols ? "yes" : "no");
710 fprintf(stdout, 761 fprintf(stdout,
711 "\t[U] hide user symbols. \t(%s)\n", 762 "\t[U] hide user symbols. \t(%s)\n",
@@ -725,14 +776,13 @@ static int key_mapped(int c)
725 case 'Q': 776 case 'Q':
726 case 'K': 777 case 'K':
727 case 'U': 778 case 'U':
779 case 'F':
780 case 's':
781 case 'S':
728 return 1; 782 return 1;
729 case 'E': 783 case 'E':
730 case 'w': 784 case 'w':
731 return nr_counters > 1 ? 1 : 0; 785 return nr_counters > 1 ? 1 : 0;
732 case 'F':
733 case 's':
734 case 'S':
735 return symbol_conf.vmlinux_name ? 1 : 0;
736 default: 786 default:
737 break; 787 break;
738 } 788 }
@@ -740,7 +790,7 @@ static int key_mapped(int c)
740 return 0; 790 return 0;
741} 791}
742 792
743static void handle_keypress(int c) 793static void handle_keypress(struct perf_session *session, int c)
744{ 794{
745 if (!key_mapped(c)) { 795 if (!key_mapped(c)) {
746 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 796 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -781,19 +831,23 @@ static void handle_keypress(int c)
781 break; 831 break;
782 case 'E': 832 case 'E':
783 if (nr_counters > 1) { 833 if (nr_counters > 1) {
784 int i;
785
786 fprintf(stderr, "\nAvailable events:"); 834 fprintf(stderr, "\nAvailable events:");
787 for (i = 0; i < nr_counters; i++) 835
788 fprintf(stderr, "\n\t%d %s", i, event_name(i)); 836 list_for_each_entry(sym_evsel, &evsel_list, node)
837 fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel));
789 838
790 prompt_integer(&sym_counter, "Enter details event counter"); 839 prompt_integer(&sym_counter, "Enter details event counter");
791 840
792 if (sym_counter >= nr_counters) { 841 if (sym_counter >= nr_counters) {
793 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); 842 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node);
794 sym_counter = 0; 843 sym_counter = 0;
844 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel));
795 sleep(1); 845 sleep(1);
846 break;
796 } 847 }
848 list_for_each_entry(sym_evsel, &evsel_list, node)
849 if (sym_evsel->idx == sym_counter)
850 break;
797 } else sym_counter = 0; 851 } else sym_counter = 0;
798 break; 852 break;
799 case 'f': 853 case 'f':
@@ -809,7 +863,7 @@ static void handle_keypress(int c)
809 case 'Q': 863 case 'Q':
810 printf("exiting.\n"); 864 printf("exiting.\n");
811 if (dump_symtab) 865 if (dump_symtab)
812 dsos__fprintf(stderr); 866 perf_session__fprintf_dsos(session, stderr);
813 exit(0); 867 exit(0);
814 case 's': 868 case 's':
815 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 869 prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -833,7 +887,7 @@ static void handle_keypress(int c)
833 display_weighted = ~display_weighted; 887 display_weighted = ~display_weighted;
834 break; 888 break;
835 case 'z': 889 case 'z':
836 zero = ~zero; 890 zero = !zero;
837 break; 891 break;
838 default: 892 default:
839 break; 893 break;
@@ -845,6 +899,7 @@ static void *display_thread(void *arg __used)
845 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 899 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
846 struct termios tc, save; 900 struct termios tc, save;
847 int delay_msecs, c; 901 int delay_msecs, c;
902 struct perf_session *session = (struct perf_session *) arg;
848 903
849 tcgetattr(0, &save); 904 tcgetattr(0, &save);
850 tc = save; 905 tc = save;
@@ -865,7 +920,7 @@ repeat:
865 c = getc(stdin); 920 c = getc(stdin);
866 tcsetattr(0, TCSAFLUSH, &save); 921 tcsetattr(0, TCSAFLUSH, &save);
867 922
868 handle_keypress(c); 923 handle_keypress(session, c);
869 goto repeat; 924 goto repeat;
870 925
871 return NULL; 926 return NULL;
@@ -910,8 +965,12 @@ static int symbol_filter(struct map *map, struct symbol *sym)
910 syme = symbol__priv(sym); 965 syme = symbol__priv(sym);
911 syme->map = map; 966 syme->map = map;
912 syme->src = NULL; 967 syme->src = NULL;
913 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 968
914 sym_filter_entry = syme; 969 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
970 /* schedule initial sym_filter_entry setup */
971 sym_filter_entry_sched = syme;
972 sym_filter = NULL;
973 }
915 974
916 for (i = 0; skip_symbols[i]; i++) { 975 for (i = 0; skip_symbols[i]; i++) {
917 if (!strcmp(skip_symbols[i], name)) { 976 if (!strcmp(skip_symbols[i], name)) {
@@ -927,68 +986,130 @@ static int symbol_filter(struct map *map, struct symbol *sym)
927} 986}
928 987
929static void event__process_sample(const event_t *self, 988static void event__process_sample(const event_t *self,
930 struct perf_session *session, int counter) 989 struct sample_data *sample,
990 struct perf_session *session,
991 struct perf_evsel *evsel)
931{ 992{
932 u64 ip = self->ip.ip; 993 u64 ip = self->ip.ip;
933 struct sym_entry *syme; 994 struct sym_entry *syme;
934 struct addr_location al; 995 struct addr_location al;
996 struct machine *machine;
935 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 997 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
936 998
999 ++samples;
1000
937 switch (origin) { 1001 switch (origin) {
938 case PERF_RECORD_MISC_USER: 1002 case PERF_RECORD_MISC_USER:
1003 ++us_samples;
939 if (hide_user_symbols) 1004 if (hide_user_symbols)
940 return; 1005 return;
1006 machine = perf_session__find_host_machine(session);
941 break; 1007 break;
942 case PERF_RECORD_MISC_KERNEL: 1008 case PERF_RECORD_MISC_KERNEL:
1009 ++kernel_samples;
943 if (hide_kernel_symbols) 1010 if (hide_kernel_symbols)
944 return; 1011 return;
1012 machine = perf_session__find_host_machine(session);
1013 break;
1014 case PERF_RECORD_MISC_GUEST_KERNEL:
1015 ++guest_kernel_samples;
1016 machine = perf_session__find_machine(session, self->ip.pid);
945 break; 1017 break;
1018 case PERF_RECORD_MISC_GUEST_USER:
1019 ++guest_us_samples;
1020 /*
1021 * TODO: we don't process guest user from host side
1022 * except simple counting.
1023 */
1024 return;
946 default: 1025 default:
947 return; 1026 return;
948 } 1027 }
949 1028
950 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || 1029 if (!machine && perf_guest) {
951 al.sym == NULL || al.filtered) 1030 pr_err("Can't find guest [%d]'s kernel information\n",
1031 self->ip.pid);
1032 return;
1033 }
1034
1035 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP)
1036 exact_samples++;
1037
1038 if (event__preprocess_sample(self, session, &al, sample,
1039 symbol_filter) < 0 ||
1040 al.filtered)
952 return; 1041 return;
953 1042
1043 if (al.sym == NULL) {
1044 /*
1045 * As we do lazy loading of symtabs we only will know if the
1046 * specified vmlinux file is invalid when we actually have a
1047 * hit in kernel space and then try to load it. So if we get
1048 * here and there are _no_ symbols in the DSO backing the
1049 * kernel map, bail out.
1050 *
1051 * We may never get here, for instance, if we use -K/
1052 * --hide-kernel-symbols, even if the user specifies an
1053 * invalid --vmlinux ;-)
1054 */
1055 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
1056 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
1057 pr_err("The %s file can't be used\n",
1058 symbol_conf.vmlinux_name);
1059 exit(1);
1060 }
1061
1062 return;
1063 }
1064
1065 /* let's see, whether we need to install initial sym_filter_entry */
1066 if (sym_filter_entry_sched) {
1067 sym_filter_entry = sym_filter_entry_sched;
1068 sym_filter_entry_sched = NULL;
1069 if (parse_source(sym_filter_entry) < 0) {
1070 struct symbol *sym = sym_entry__symbol(sym_filter_entry);
1071
1072 pr_err("Can't annotate %s", sym->name);
1073 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) {
1074 pr_err(": No vmlinux file was found in the path:\n");
1075 machine__fprintf_vmlinux_path(machine, stderr);
1076 } else
1077 pr_err(".\n");
1078 exit(1);
1079 }
1080 }
1081
954 syme = symbol__priv(al.sym); 1082 syme = symbol__priv(al.sym);
955 if (!syme->skip) { 1083 if (!syme->skip) {
956 syme->count[counter]++; 1084 syme->count[evsel->idx]++;
957 syme->origin = origin; 1085 syme->origin = origin;
958 record_precise_ip(syme, counter, ip); 1086 record_precise_ip(syme, evsel->idx, ip);
959 pthread_mutex_lock(&active_symbols_lock); 1087 pthread_mutex_lock(&active_symbols_lock);
960 if (list_empty(&syme->node) || !syme->node.next) 1088 if (list_empty(&syme->node) || !syme->node.next)
961 __list_insert_active_sym(syme); 1089 __list_insert_active_sym(syme);
962 pthread_mutex_unlock(&active_symbols_lock); 1090 pthread_mutex_unlock(&active_symbols_lock);
963 if (origin == PERF_RECORD_MISC_USER)
964 ++userspace_samples;
965 ++samples;
966 } 1091 }
967} 1092}
968 1093
969static int event__process(event_t *event, struct perf_session *session)
970{
971 switch (event->header.type) {
972 case PERF_RECORD_COMM:
973 event__process_comm(event, session);
974 break;
975 case PERF_RECORD_MMAP:
976 event__process_mmap(event, session);
977 break;
978 default:
979 break;
980 }
981
982 return 0;
983}
984
985struct mmap_data { 1094struct mmap_data {
986 int counter;
987 void *base; 1095 void *base;
988 int mask; 1096 int mask;
989 unsigned int prev; 1097 unsigned int prev;
990}; 1098};
991 1099
1100static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel,
1101 int ncpus, int nthreads)
1102{
1103 evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data));
1104 return evsel->priv != NULL ? 0 : -ENOMEM;
1105}
1106
1107static void perf_evsel__free_mmap(struct perf_evsel *evsel)
1108{
1109 xyarray__delete(evsel->priv);
1110 evsel->priv = NULL;
1111}
1112
992static unsigned int mmap_read_head(struct mmap_data *md) 1113static unsigned int mmap_read_head(struct mmap_data *md)
993{ 1114{
994 struct perf_event_mmap_page *pc = md->base; 1115 struct perf_event_mmap_page *pc = md->base;
@@ -1001,11 +1122,15 @@ static unsigned int mmap_read_head(struct mmap_data *md)
1001} 1122}
1002 1123
1003static void perf_session__mmap_read_counter(struct perf_session *self, 1124static void perf_session__mmap_read_counter(struct perf_session *self,
1004 struct mmap_data *md) 1125 struct perf_evsel *evsel,
1126 int cpu, int thread_idx)
1005{ 1127{
1128 struct xyarray *mmap_array = evsel->priv;
1129 struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx);
1006 unsigned int head = mmap_read_head(md); 1130 unsigned int head = mmap_read_head(md);
1007 unsigned int old = md->prev; 1131 unsigned int old = md->prev;
1008 unsigned char *data = md->base + page_size; 1132 unsigned char *data = md->base + page_size;
1133 struct sample_data sample;
1009 int diff; 1134 int diff;
1010 1135
1011 /* 1136 /*
@@ -1053,42 +1178,51 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1053 event = &event_copy; 1178 event = &event_copy;
1054 } 1179 }
1055 1180
1181 event__parse_sample(event, self, &sample);
1056 if (event->header.type == PERF_RECORD_SAMPLE) 1182 if (event->header.type == PERF_RECORD_SAMPLE)
1057 event__process_sample(event, self, md->counter); 1183 event__process_sample(event, &sample, self, evsel);
1058 else 1184 else
1059 event__process(event, self); 1185 event__process(event, &sample, self);
1060 old += size; 1186 old += size;
1061 } 1187 }
1062 1188
1063 md->prev = old; 1189 md->prev = old;
1064} 1190}
1065 1191
1066static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 1192static struct pollfd *event_array;
1067static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1068 1193
1069static void perf_session__mmap_read(struct perf_session *self) 1194static void perf_session__mmap_read(struct perf_session *self)
1070{ 1195{
1071 int i, counter; 1196 struct perf_evsel *counter;
1072 1197 int i, thread_index;
1073 for (i = 0; i < nr_cpus; i++) { 1198
1074 for (counter = 0; counter < nr_counters; counter++) 1199 for (i = 0; i < cpus->nr; i++) {
1075 perf_session__mmap_read_counter(self, &mmap_array[i][counter]); 1200 list_for_each_entry(counter, &evsel_list, node) {
1201 for (thread_index = 0;
1202 thread_index < threads->nr;
1203 thread_index++) {
1204 perf_session__mmap_read_counter(self,
1205 counter, i, thread_index);
1206 }
1207 }
1076 } 1208 }
1077} 1209}
1078 1210
1079int nr_poll; 1211int nr_poll;
1080int group_fd; 1212int group_fd;
1081 1213
1082static void start_counter(int i, int counter) 1214static void start_counter(int i, struct perf_evsel *evsel)
1083{ 1215{
1216 struct xyarray *mmap_array = evsel->priv;
1217 struct mmap_data *mm;
1084 struct perf_event_attr *attr; 1218 struct perf_event_attr *attr;
1085 int cpu; 1219 int cpu = -1;
1220 int thread_index;
1086 1221
1087 cpu = profile_cpu; 1222 if (target_tid == -1)
1088 if (target_pid == -1 && profile_cpu == -1) 1223 cpu = cpus->map[i];
1089 cpu = i;
1090 1224
1091 attr = attrs + counter; 1225 attr = &evsel->attr;
1092 1226
1093 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 1227 attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
1094 1228
@@ -1101,87 +1235,92 @@ static void start_counter(int i, int counter)
1101 attr->inherit = (cpu < 0) && inherit; 1235 attr->inherit = (cpu < 0) && inherit;
1102 attr->mmap = 1; 1236 attr->mmap = 1;
1103 1237
1238 for (thread_index = 0; thread_index < threads->nr; thread_index++) {
1104try_again: 1239try_again:
1105 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1240 FD(evsel, i, thread_index) = sys_perf_event_open(attr,
1106 1241 threads->map[thread_index], cpu, group_fd, 0);
1107 if (fd[i][counter] < 0) { 1242
1108 int err = errno; 1243 if (FD(evsel, i, thread_index) < 0) {
1244 int err = errno;
1245
1246 if (err == EPERM || err == EACCES)
1247 die("Permission error - are you root?\n"
1248 "\t Consider tweaking"
1249 " /proc/sys/kernel/perf_event_paranoid.\n");
1250 /*
1251 * If it's cycles then fall back to hrtimer
1252 * based cpu-clock-tick sw counter, which
1253 * is always available even if no PMU support:
1254 */
1255 if (attr->type == PERF_TYPE_HARDWARE
1256 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1257
1258 if (verbose)
1259 warning(" ... trying to fall back to cpu-clock-ticks\n");
1260
1261 attr->type = PERF_TYPE_SOFTWARE;
1262 attr->config = PERF_COUNT_SW_CPU_CLOCK;
1263 goto try_again;
1264 }
1265 printf("\n");
1266 error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n",
1267 FD(evsel, i, thread_index), strerror(err));
1268 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1269 exit(-1);
1270 }
1271 assert(FD(evsel, i, thread_index) >= 0);
1272 fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK);
1109 1273
1110 if (err == EPERM || err == EACCES)
1111 die("No permission - are you root?\n");
1112 /* 1274 /*
1113 * If it's cycles then fall back to hrtimer 1275 * First counter acts as the group leader:
1114 * based cpu-clock-tick sw counter, which
1115 * is always available even if no PMU support:
1116 */ 1276 */
1117 if (attr->type == PERF_TYPE_HARDWARE 1277 if (group && group_fd == -1)
1118 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 1278 group_fd = FD(evsel, i, thread_index);
1119 1279
1120 if (verbose) 1280 event_array[nr_poll].fd = FD(evsel, i, thread_index);
1121 warning(" ... trying to fall back to cpu-clock-ticks\n"); 1281 event_array[nr_poll].events = POLLIN;
1122 1282 nr_poll++;
1123 attr->type = PERF_TYPE_SOFTWARE; 1283
1124 attr->config = PERF_COUNT_SW_CPU_CLOCK; 1284 mm = xyarray__entry(mmap_array, i, thread_index);
1125 goto try_again; 1285 mm->prev = 0;
1126 } 1286 mm->mask = mmap_pages*page_size - 1;
1127 printf("\n"); 1287 mm->base = mmap(NULL, (mmap_pages+1)*page_size,
1128 error("perfcounter syscall returned with %d (%s)\n", 1288 PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0);
1129 fd[i][counter], strerror(err)); 1289 if (mm->base == MAP_FAILED)
1130 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 1290 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1131 exit(-1);
1132 } 1291 }
1133 assert(fd[i][counter] >= 0);
1134 fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
1135
1136 /*
1137 * First counter acts as the group leader:
1138 */
1139 if (group && group_fd == -1)
1140 group_fd = fd[i][counter];
1141
1142 event_array[nr_poll].fd = fd[i][counter];
1143 event_array[nr_poll].events = POLLIN;
1144 nr_poll++;
1145
1146 mmap_array[i][counter].counter = counter;
1147 mmap_array[i][counter].prev = 0;
1148 mmap_array[i][counter].mask = mmap_pages*page_size - 1;
1149 mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
1150 PROT_READ, MAP_SHARED, fd[i][counter], 0);
1151 if (mmap_array[i][counter].base == MAP_FAILED)
1152 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1153} 1292}
1154 1293
1155static int __cmd_top(void) 1294static int __cmd_top(void)
1156{ 1295{
1157 pthread_t thread; 1296 pthread_t thread;
1158 int i, counter; 1297 struct perf_evsel *counter;
1159 int ret; 1298 int i, ret;
1160 /* 1299 /*
1161 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 1300 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1162 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 1301 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1163 */ 1302 */
1164 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false); 1303 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
1165 if (session == NULL) 1304 if (session == NULL)
1166 return -ENOMEM; 1305 return -ENOMEM;
1167 1306
1168 if (target_pid != -1) 1307 if (target_tid != -1)
1169 event__synthesize_thread(target_pid, event__process, session); 1308 event__synthesize_thread(target_tid, event__process, session);
1170 else 1309 else
1171 event__synthesize_threads(event__process, session); 1310 event__synthesize_threads(event__process, session);
1172 1311
1173 for (i = 0; i < nr_cpus; i++) { 1312 for (i = 0; i < cpus->nr; i++) {
1174 group_fd = -1; 1313 group_fd = -1;
1175 for (counter = 0; counter < nr_counters; counter++) 1314 list_for_each_entry(counter, &evsel_list, node)
1176 start_counter(i, counter); 1315 start_counter(i, counter);
1177 } 1316 }
1178 1317
1179 /* Wait for a minimal set of events before starting the snapshot */ 1318 /* Wait for a minimal set of events before starting the snapshot */
1180 poll(event_array, nr_poll, 100); 1319 poll(&event_array[0], nr_poll, 100);
1181 1320
1182 perf_session__mmap_read(session); 1321 perf_session__mmap_read(session);
1183 1322
1184 if (pthread_create(&thread, NULL, display_thread, NULL)) { 1323 if (pthread_create(&thread, NULL, display_thread, session)) {
1185 printf("Could not create display thread.\n"); 1324 printf("Could not create display thread.\n");
1186 exit(-1); 1325 exit(-1);
1187 } 1326 }
@@ -1220,17 +1359,18 @@ static const struct option options[] = {
1220 OPT_INTEGER('c', "count", &default_interval, 1359 OPT_INTEGER('c', "count", &default_interval,
1221 "event period to sample"), 1360 "event period to sample"),
1222 OPT_INTEGER('p', "pid", &target_pid, 1361 OPT_INTEGER('p', "pid", &target_pid,
1223 "profile events on existing pid"), 1362 "profile events on existing process id"),
1363 OPT_INTEGER('t', "tid", &target_tid,
1364 "profile events on existing thread id"),
1224 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1365 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1225 "system-wide collection from all CPUs"), 1366 "system-wide collection from all CPUs"),
1226 OPT_INTEGER('C', "CPU", &profile_cpu, 1367 OPT_STRING('C', "cpu", &cpu_list, "cpu",
1227 "CPU to profile on"), 1368 "list of cpus to monitor"),
1228 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1369 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1229 "file", "vmlinux pathname"), 1370 "file", "vmlinux pathname"),
1230 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 1371 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1231 "hide kernel symbols"), 1372 "hide kernel symbols"),
1232 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1373 OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"),
1233 "number of mmap data pages"),
1234 OPT_INTEGER('r', "realtime", &realtime_prio, 1374 OPT_INTEGER('r', "realtime", &realtime_prio,
1235 "collect data with this RT SCHED_FIFO priority"), 1375 "collect data with this RT SCHED_FIFO priority"),
1236 OPT_INTEGER('d', "delay", &delay_secs, 1376 OPT_INTEGER('d', "delay", &delay_secs,
@@ -1244,7 +1384,7 @@ static const struct option options[] = {
1244 OPT_BOOLEAN('i', "inherit", &inherit, 1384 OPT_BOOLEAN('i', "inherit", &inherit,
1245 "child tasks inherit counters"), 1385 "child tasks inherit counters"),
1246 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1386 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1247 "symbol to annotate - requires -k option"), 1387 "symbol to annotate"),
1248 OPT_BOOLEAN('z', "zero", &zero, 1388 OPT_BOOLEAN('z', "zero", &zero,
1249 "zero history across updates"), 1389 "zero history across updates"),
1250 OPT_INTEGER('F', "freq", &freq, 1390 OPT_INTEGER('F', "freq", &freq,
@@ -1253,14 +1393,15 @@ static const struct option options[] = {
1253 "display this many functions"), 1393 "display this many functions"),
1254 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 1394 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1255 "hide user symbols"), 1395 "hide user symbols"),
1256 OPT_BOOLEAN('v', "verbose", &verbose, 1396 OPT_INCR('v', "verbose", &verbose,
1257 "be more verbose (show counter open errors, etc)"), 1397 "be more verbose (show counter open errors, etc)"),
1258 OPT_END() 1398 OPT_END()
1259}; 1399};
1260 1400
1261int cmd_top(int argc, const char **argv, const char *prefix __used) 1401int cmd_top(int argc, const char **argv, const char *prefix __used)
1262{ 1402{
1263 int counter; 1403 struct perf_evsel *pos;
1404 int status = -ENOMEM;
1264 1405
1265 page_size = sysconf(_SC_PAGE_SIZE); 1406 page_size = sysconf(_SC_PAGE_SIZE);
1266 1407
@@ -1268,28 +1409,35 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1268 if (argc) 1409 if (argc)
1269 usage_with_options(top_usage, options); 1410 usage_with_options(top_usage, options);
1270 1411
1412 if (target_pid != -1)
1413 target_tid = target_pid;
1414
1415 threads = thread_map__new(target_pid, target_tid);
1416 if (threads == NULL) {
1417 pr_err("Problems finding threads of monitor\n");
1418 usage_with_options(top_usage, options);
1419 }
1420
1421 event_array = malloc((sizeof(struct pollfd) *
1422 MAX_NR_CPUS * MAX_COUNTERS * threads->nr));
1423 if (!event_array)
1424 return -ENOMEM;
1425
1271 /* CPU and PID are mutually exclusive */ 1426 /* CPU and PID are mutually exclusive */
1272 if (target_pid != -1 && profile_cpu != -1) { 1427 if (target_tid > 0 && cpu_list) {
1273 printf("WARNING: PID switch overriding CPU\n"); 1428 printf("WARNING: PID switch overriding CPU\n");
1274 sleep(1); 1429 sleep(1);
1275 profile_cpu = -1; 1430 cpu_list = NULL;
1276 } 1431 }
1277 1432
1278 if (!nr_counters) 1433 if (!nr_counters && perf_evsel_list__create_default() < 0) {
1279 nr_counters = 1; 1434 pr_err("Not enough memory for event selector list\n");
1280 1435 return -ENOMEM;
1281 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1436 }
1282 (nr_counters + 1) * sizeof(unsigned long));
1283 if (symbol_conf.vmlinux_name == NULL)
1284 symbol_conf.try_vmlinux_path = true;
1285 if (symbol__init() < 0)
1286 return -1;
1287 1437
1288 if (delay_secs < 1) 1438 if (delay_secs < 1)
1289 delay_secs = 1; 1439 delay_secs = 1;
1290 1440
1291 parse_source(sym_filter_entry);
1292
1293 /* 1441 /*
1294 * User specified count overrides default frequency. 1442 * User specified count overrides default frequency.
1295 */ 1443 */
@@ -1302,22 +1450,35 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1302 exit(EXIT_FAILURE); 1450 exit(EXIT_FAILURE);
1303 } 1451 }
1304 1452
1305 /* 1453 if (target_tid != -1)
1306 * Fill in the ones not specifically initialized via -c: 1454 cpus = cpu_map__dummy_new();
1307 */ 1455 else
1308 for (counter = 0; counter < nr_counters; counter++) { 1456 cpus = cpu_map__new(cpu_list);
1309 if (attrs[counter].sample_period) 1457
1458 if (cpus == NULL)
1459 usage_with_options(top_usage, options);
1460
1461 list_for_each_entry(pos, &evsel_list, node) {
1462 if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 ||
1463 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0)
1464 goto out_free_fd;
1465 /*
1466 * Fill in the ones not specifically initialized via -c:
1467 */
1468 if (pos->attr.sample_period)
1310 continue; 1469 continue;
1311 1470
1312 attrs[counter].sample_period = default_interval; 1471 pos->attr.sample_period = default_interval;
1313 } 1472 }
1314 1473
1315 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 1474 sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node);
1316 assert(nr_cpus <= MAX_NR_CPUS);
1317 assert(nr_cpus >= 0);
1318 1475
1319 if (target_pid != -1 || profile_cpu != -1) 1476 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1320 nr_cpus = 1; 1477 (nr_counters + 1) * sizeof(unsigned long));
1478
1479 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1480 if (symbol__init() < 0)
1481 return -1;
1321 1482
1322 get_term_dimensions(&winsize); 1483 get_term_dimensions(&winsize);
1323 if (print_entries == 0) { 1484 if (print_entries == 0) {
@@ -1325,5 +1486,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1325 signal(SIGWINCH, sig_winch_handler); 1486 signal(SIGWINCH, sig_winch_handler);
1326 } 1487 }
1327 1488
1328 return __cmd_top(); 1489 status = __cmd_top();
1490out_free_fd:
1491 list_for_each_entry(pos, &evsel_list, node)
1492 perf_evsel__free_mmap(pos);
1493 perf_evsel_list__delete();
1494
1495 return status;
1329} 1496}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 18035b1f16c7..c7798c7f24ed 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -16,6 +16,7 @@ extern int check_pager_config(const char *cmd);
16 16
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_bench(int argc, const char **argv, const char *prefix); 18extern int cmd_bench(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 20extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_diff(int argc, const char **argv, const char *prefix); 21extern int cmd_diff(int argc, const char **argv, const char *prefix);
21extern int cmd_help(int argc, const char **argv, const char *prefix); 22extern int cmd_help(int argc, const char **argv, const char *prefix);
@@ -26,9 +27,13 @@ extern int cmd_report(int argc, const char **argv, const char *prefix);
26extern int cmd_stat(int argc, const char **argv, const char *prefix); 27extern int cmd_stat(int argc, const char **argv, const char *prefix);
27extern int cmd_timechart(int argc, const char **argv, const char *prefix); 28extern int cmd_timechart(int argc, const char **argv, const char *prefix);
28extern int cmd_top(int argc, const char **argv, const char *prefix); 29extern int cmd_top(int argc, const char **argv, const char *prefix);
29extern int cmd_trace(int argc, const char **argv, const char *prefix); 30extern int cmd_script(int argc, const char **argv, const char *prefix);
30extern int cmd_version(int argc, const char **argv, const char *prefix); 31extern int cmd_version(int argc, const char **argv, const char *prefix);
31extern int cmd_probe(int argc, const char **argv, const char *prefix); 32extern int cmd_probe(int argc, const char **argv, const char *prefix);
32extern int cmd_kmem(int argc, const char **argv, const char *prefix); 33extern int cmd_kmem(int argc, const char **argv, const char *prefix);
34extern int cmd_lock(int argc, const char **argv, const char *prefix);
35extern int cmd_kvm(int argc, const char **argv, const char *prefix);
36extern int cmd_test(int argc, const char **argv, const char *prefix);
37extern int cmd_inject(int argc, const char **argv, const char *prefix);
33 38
34#endif 39#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 71dc7c3fe7b2..16b5088cf8f4 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -3,9 +3,12 @@
3# command name category [deprecated] [common] 3# command name category [deprecated] [common]
4# 4#
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-archive mainporcelain common
6perf-bench mainporcelain common 7perf-bench mainporcelain common
8perf-buildid-cache mainporcelain common
7perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
8perf-diff mainporcelain common 10perf-diff mainporcelain common
11perf-inject mainporcelain common
9perf-list mainporcelain common 12perf-list mainporcelain common
10perf-sched mainporcelain common 13perf-sched mainporcelain common
11perf-record mainporcelain common 14perf-record mainporcelain common
@@ -13,6 +16,9 @@ perf-report mainporcelain common
13perf-stat mainporcelain common 16perf-stat mainporcelain common
14perf-timechart mainporcelain common 17perf-timechart mainporcelain common
15perf-top mainporcelain common 18perf-top mainporcelain common
16perf-trace mainporcelain common 19perf-script mainporcelain common
17perf-probe mainporcelain common 20perf-probe mainporcelain common
18perf-kmem mainporcelain common 21perf-kmem mainporcelain common
22perf-lock mainporcelain common
23perf-kvm mainporcelain common
24perf-test mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index 8d0de5130db3..bd0bb1b1279b 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -101,10 +101,10 @@ enum hw_event_ids {
101 */ 101 */
102 PERF_COUNT_HW_CPU_CYCLES = 0, 102 PERF_COUNT_HW_CPU_CYCLES = 0,
103 PERF_COUNT_HW_INSTRUCTIONS = 1, 103 PERF_COUNT_HW_INSTRUCTIONS = 1,
104 PERF_COUNT_HW_CACHE_REFERENCES = 2, 104 PERF_COUNT_HW_CACHE_REFERENCES = 2,
105 PERF_COUNT_HW_CACHE_MISSES = 3, 105 PERF_COUNT_HW_CACHE_MISSES = 3,
106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, 106 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
107 PERF_COUNT_HW_BRANCH_MISSES = 5, 107 PERF_COUNT_HW_BRANCH_MISSES = 5,
108 PERF_COUNT_HW_BUS_CYCLES = 6, 108 PERF_COUNT_HW_BUS_CYCLES = 6,
109}; 109};
110 110
@@ -131,8 +131,8 @@ software events, selected by 'event_id':
131 */ 131 */
132enum sw_event_ids { 132enum sw_event_ids {
133 PERF_COUNT_SW_CPU_CLOCK = 0, 133 PERF_COUNT_SW_CPU_CLOCK = 0,
134 PERF_COUNT_SW_TASK_CLOCK = 1, 134 PERF_COUNT_SW_TASK_CLOCK = 1,
135 PERF_COUNT_SW_PAGE_FAULTS = 2, 135 PERF_COUNT_SW_PAGE_FAULTS = 2,
136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3, 136 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
137 PERF_COUNT_SW_CPU_MIGRATIONS = 4, 137 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, 138 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
diff --git a/tools/perf/feature-tests.mak b/tools/perf/feature-tests.mak
new file mode 100644
index 000000000000..b041ca67a2cb
--- /dev/null
+++ b/tools/perf/feature-tests.mak
@@ -0,0 +1,130 @@
1define SOURCE_HELLO
2#include <stdio.h>
3int main(void)
4{
5 return puts(\"hi\");
6}
7endef
8
9ifndef NO_DWARF
10define SOURCE_DWARF
11#include <dwarf.h>
12#include <elfutils/libdw.h>
13#include <elfutils/version.h>
14#ifndef _ELFUTILS_PREREQ
15#error
16#endif
17
18int main(void)
19{
20 Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
21 return (long)dbg;
22}
23endef
24endif
25
26define SOURCE_LIBELF
27#include <libelf.h>
28
29int main(void)
30{
31 Elf *elf = elf_begin(0, ELF_C_READ, 0);
32 return (long)elf;
33}
34endef
35
36define SOURCE_GLIBC
37#include <gnu/libc-version.h>
38
39int main(void)
40{
41 const char *version = gnu_get_libc_version();
42 return (long)version;
43}
44endef
45
46define SOURCE_ELF_MMAP
47#include <libelf.h>
48int main(void)
49{
50 Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
51 return (long)elf;
52}
53endef
54
55ifndef NO_NEWT
56define SOURCE_NEWT
57#include <newt.h>
58
59int main(void)
60{
61 newtInit();
62 newtCls();
63 return newtFinished();
64}
65endef
66endif
67
68ifndef NO_LIBPERL
69define SOURCE_PERL_EMBED
70#include <EXTERN.h>
71#include <perl.h>
72
73int main(void)
74{
75perl_alloc();
76return 0;
77}
78endef
79endif
80
81ifndef NO_LIBPYTHON
82define SOURCE_PYTHON_EMBED
83#include <Python.h>
84
85int main(void)
86{
87 Py_Initialize();
88 return 0;
89}
90endef
91endif
92
93define SOURCE_BFD
94#include <bfd.h>
95
96int main(void)
97{
98 bfd_demangle(0, 0, 0);
99 return 0;
100}
101endef
102
103define SOURCE_CPLUS_DEMANGLE
104extern char *cplus_demangle(const char *, int);
105
106int main(void)
107{
108 cplus_demangle(0, 0);
109 return 0;
110}
111endef
112
113define SOURCE_STRLCPY
114#include <stdlib.h>
115extern size_t strlcpy(char *dest, const char *src, size_t size);
116
117int main(void)
118{
119 strlcpy(NULL, NULL, 0);
120 return 0;
121}
122endef
123
124# try-cc
125# Usage: option = $(call try-cc, source-to-build, cc-options)
126try-cc = $(shell sh -c \
127 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
128 echo "$(1)" | \
129 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
130 rm -f "$$TMP"')
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
new file mode 100644
index 000000000000..677e59d62a8d
--- /dev/null
+++ b/tools/perf/perf-archive.sh
@@ -0,0 +1,46 @@
1#!/bin/bash
2# perf archive
3# Arnaldo Carvalho de Melo <acme@redhat.com>
4
5PERF_DATA=perf.data
6if [ $# -ne 0 ] ; then
7 PERF_DATA=$1
8fi
9
10#
11# PERF_BUILDID_DIR environment variable set by perf
12# path to buildid directory, default to $HOME/.debug
13#
14if [ -z $PERF_BUILDID_DIR ]; then
15 PERF_BUILDID_DIR=~/.debug/
16else
17 # append / to make substitutions work
18 PERF_BUILDID_DIR=$PERF_BUILDID_DIR/
19fi
20
21BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
22NOBUILDID=0000000000000000000000000000000000000000
23
24perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
25if [ ! -s $BUILDIDS ] ; then
26 echo "perf archive: no build-ids found"
27 rm -f $BUILDIDS
28 exit 1
29fi
30
31MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
32
33cut -d ' ' -f 1 $BUILDIDS | \
34while read build_id ; do
35 linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2}
36 filename=$(readlink -f $linkname)
37 echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST
38 echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST
39done
40
41tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
42rm -f $MANIFEST $BUILDIDS
43echo -e "Now please run:\n"
44echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
45echo "wherever you need to run 'perf report' on."
46exit 0
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 873e55fab375..595d0f4a7103 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -13,7 +13,6 @@
13#include "util/quote.h" 13#include "util/quote.h"
14#include "util/run-command.h" 14#include "util/run-command.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16#include "util/string.h"
17#include "util/debugfs.h" 16#include "util/debugfs.h"
18 17
19const char perf_usage_string[] = 18const char perf_usage_string[] =
@@ -22,7 +21,9 @@ const char perf_usage_string[] =
22const char perf_more_info_string[] = 21const char perf_more_info_string[] =
23 "See 'perf help COMMAND' for more information on a specific command."; 22 "See 'perf help COMMAND' for more information on a specific command.";
24 23
24int use_browser = -1;
25static int use_pager = -1; 25static int use_pager = -1;
26
26struct pager_config { 27struct pager_config {
27 const char *cmd; 28 const char *cmd;
28 int val; 29 int val;
@@ -48,7 +49,26 @@ int check_pager_config(const char *cmd)
48 return c.val; 49 return c.val;
49} 50}
50 51
51static void commit_pager_choice(void) { 52static int tui_command_config(const char *var, const char *value, void *data)
53{
54 struct pager_config *c = data;
55 if (!prefixcmp(var, "tui.") && !strcmp(var + 4, c->cmd))
56 c->val = perf_config_bool(var, value);
57 return 0;
58}
59
60/* returns 0 for "no tui", 1 for "use tui", and -1 for "not specified" */
61static int check_tui_config(const char *cmd)
62{
63 struct pager_config c;
64 c.cmd = cmd;
65 c.val = -1;
66 perf_config(tui_command_config, &c);
67 return c.val;
68}
69
70static void commit_pager_choice(void)
71{
52 switch (use_pager) { 72 switch (use_pager) {
53 case 0: 73 case 0:
54 setenv("PERF_PAGER", "cat", 1); 74 setenv("PERF_PAGER", "cat", 1);
@@ -70,7 +90,7 @@ static void set_debugfs_path(void)
70 "tracing/events"); 90 "tracing/events");
71} 91}
72 92
73static int handle_options(const char*** argv, int* argc, int* envchanged) 93static int handle_options(const char ***argv, int *argc, int *envchanged)
74{ 94{
75 int handled = 0; 95 int handled = 0;
76 96
@@ -109,7 +129,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
109 *envchanged = 1; 129 *envchanged = 1;
110 } else if (!strcmp(cmd, "--perf-dir")) { 130 } else if (!strcmp(cmd, "--perf-dir")) {
111 if (*argc < 2) { 131 if (*argc < 2) {
112 fprintf(stderr, "No directory given for --perf-dir.\n" ); 132 fprintf(stderr, "No directory given for --perf-dir.\n");
113 usage(perf_usage_string); 133 usage(perf_usage_string);
114 } 134 }
115 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1); 135 setenv(PERF_DIR_ENVIRONMENT, (*argv)[1], 1);
@@ -124,7 +144,7 @@ static int handle_options(const char*** argv, int* argc, int* envchanged)
124 *envchanged = 1; 144 *envchanged = 1;
125 } else if (!strcmp(cmd, "--work-tree")) { 145 } else if (!strcmp(cmd, "--work-tree")) {
126 if (*argc < 2) { 146 if (*argc < 2) {
127 fprintf(stderr, "No directory given for --work-tree.\n" ); 147 fprintf(stderr, "No directory given for --work-tree.\n");
128 usage(perf_usage_string); 148 usage(perf_usage_string);
129 } 149 }
130 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1); 150 setenv(PERF_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
@@ -168,7 +188,7 @@ static int handle_alias(int *argcp, const char ***argv)
168{ 188{
169 int envchanged = 0, ret = 0, saved_errno = errno; 189 int envchanged = 0, ret = 0, saved_errno = errno;
170 int count, option_count; 190 int count, option_count;
171 const char** new_argv; 191 const char **new_argv;
172 const char *alias_command; 192 const char *alias_command;
173 char *alias_string; 193 char *alias_string;
174 194
@@ -210,11 +230,11 @@ static int handle_alias(int *argcp, const char ***argv)
210 if (!strcmp(alias_command, new_argv[0])) 230 if (!strcmp(alias_command, new_argv[0]))
211 die("recursive alias: %s", alias_command); 231 die("recursive alias: %s", alias_command);
212 232
213 new_argv = realloc(new_argv, sizeof(char*) * 233 new_argv = realloc(new_argv, sizeof(char *) *
214 (count + *argcp + 1)); 234 (count + *argcp + 1));
215 /* insert after command name */ 235 /* insert after command name */
216 memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); 236 memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp);
217 new_argv[count+*argcp] = NULL; 237 new_argv[count + *argcp] = NULL;
218 238
219 *argv = new_argv; 239 *argv = new_argv;
220 *argcp += count - 1; 240 *argcp += count - 1;
@@ -253,6 +273,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
253 if (p->option & RUN_SETUP) 273 if (p->option & RUN_SETUP)
254 prefix = NULL; /* setup_perf_directory(); */ 274 prefix = NULL; /* setup_perf_directory(); */
255 275
276 if (use_browser == -1)
277 use_browser = check_tui_config(p->cmd);
278
256 if (use_pager == -1 && p->option & RUN_SETUP) 279 if (use_pager == -1 && p->option & RUN_SETUP)
257 use_pager = check_pager_config(p->cmd); 280 use_pager = check_pager_config(p->cmd);
258 if (use_pager == -1 && p->option & USE_PAGER) 281 if (use_pager == -1 && p->option & USE_PAGER)
@@ -261,6 +284,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
261 set_debugfs_path(); 284 set_debugfs_path();
262 285
263 status = p->fn(argc, argv, prefix); 286 status = p->fn(argc, argv, prefix);
287 exit_browser(status);
288
264 if (status) 289 if (status)
265 return status & 0xff; 290 return status & 0xff;
266 291
@@ -285,6 +310,7 @@ static void handle_internal_command(int argc, const char **argv)
285{ 310{
286 const char *cmd = argv[0]; 311 const char *cmd = argv[0];
287 static struct cmd_struct commands[] = { 312 static struct cmd_struct commands[] = {
313 { "buildid-cache", cmd_buildid_cache, 0 },
288 { "buildid-list", cmd_buildid_list, 0 }, 314 { "buildid-list", cmd_buildid_list, 0 },
289 { "diff", cmd_diff, 0 }, 315 { "diff", cmd_diff, 0 },
290 { "help", cmd_help, 0 }, 316 { "help", cmd_help, 0 },
@@ -297,10 +323,14 @@ static void handle_internal_command(int argc, const char **argv)
297 { "top", cmd_top, 0 }, 323 { "top", cmd_top, 0 },
298 { "annotate", cmd_annotate, 0 }, 324 { "annotate", cmd_annotate, 0 },
299 { "version", cmd_version, 0 }, 325 { "version", cmd_version, 0 },
300 { "trace", cmd_trace, 0 }, 326 { "script", cmd_script, 0 },
301 { "sched", cmd_sched, 0 }, 327 { "sched", cmd_sched, 0 },
302 { "probe", cmd_probe, 0 }, 328 { "probe", cmd_probe, 0 },
303 { "kmem", cmd_kmem, 0 }, 329 { "kmem", cmd_kmem, 0 },
330 { "lock", cmd_lock, 0 },
331 { "kvm", cmd_kvm, 0 },
332 { "test", cmd_test, 0 },
333 { "inject", cmd_inject, 0 },
304 }; 334 };
305 unsigned int i; 335 unsigned int i;
306 static const char ext[] = STRIP_EXTENSION; 336 static const char ext[] = STRIP_EXTENSION;
@@ -388,7 +418,7 @@ static int run_argv(int *argcp, const char ***argv)
388/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ 418/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */
389static void get_debugfs_mntpt(void) 419static void get_debugfs_mntpt(void)
390{ 420{
391 const char *path = debugfs_find_mountpoint(); 421 const char *path = debugfs_mount(NULL);
392 422
393 if (path) 423 if (path)
394 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt)); 424 strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt));
@@ -428,6 +458,8 @@ int main(int argc, const char **argv)
428 handle_options(&argv, &argc, NULL); 458 handle_options(&argv, &argc, NULL);
429 commit_pager_choice(); 459 commit_pager_choice();
430 set_debugfs_path(); 460 set_debugfs_path();
461 set_buildid_dir();
462
431 if (argc > 0) { 463 if (argc > 0) {
432 if (!prefixcmp(argv[0], "--")) 464 if (!prefixcmp(argv[0], "--"))
433 argv[0] += 2; 465 argv[0] += 2;
@@ -442,15 +474,15 @@ int main(int argc, const char **argv)
442 474
443 /* 475 /*
444 * We use PATH to find perf commands, but we prepend some higher 476 * We use PATH to find perf commands, but we prepend some higher
445 * precidence paths: the "--exec-path" option, the PERF_EXEC_PATH 477 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
446 * environment, and the $(perfexecdir) from the Makefile at build 478 * environment, and the $(perfexecdir) from the Makefile at build
447 * time. 479 * time.
448 */ 480 */
449 setup_path(); 481 setup_path();
450 482
451 while (1) { 483 while (1) {
452 static int done_help = 0; 484 static int done_help;
453 static int was_alias = 0; 485 static int was_alias;
454 486
455 was_alias = run_argv(&argc, &argv); 487 was_alias = run_argv(&argc, &argv);
456 if (errno != ENOENT) 488 if (errno != ENOENT)
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 75f941bfba9e..95aaf565c704 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -1,6 +1,10 @@
1#ifndef _PERF_PERF_H 1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H 2#define _PERF_PERF_H
3 3
4struct winsize;
5
6void get_term_dimensions(struct winsize *ws);
7
4#if defined(__i386__) 8#if defined(__i386__)
5#include "../../arch/x86/include/asm/unistd.h" 9#include "../../arch/x86/include/asm/unistd.h"
6#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
@@ -65,12 +69,22 @@
65 * Use the __kuser_memory_barrier helper in the CPU helper page. See 69 * Use the __kuser_memory_barrier helper in the CPU helper page. See
66 * arch/arm/kernel/entry-armv.S in the kernel source for details. 70 * arch/arm/kernel/entry-armv.S in the kernel source for details.
67 */ 71 */
68#define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \ 72#define rmb() ((void(*)(void))0xffff0fa0)()
69 "sub pc, r0, #95" ::: "r0", "lr", "cc", \
70 "memory")
71#define cpu_relax() asm volatile("":::"memory") 73#define cpu_relax() asm volatile("":::"memory")
72#endif 74#endif
73 75
76#ifdef __mips__
77#include "../../arch/mips/include/asm/unistd.h"
78#define rmb() asm volatile( \
79 ".set mips2\n\t" \
80 "sync\n\t" \
81 ".set mips0" \
82 : /* no output */ \
83 : /* no input */ \
84 : "memory")
85#define cpu_relax() asm volatile("" ::: "memory")
86#endif
87
74#include <time.h> 88#include <time.h>
75#include <unistd.h> 89#include <unistd.h>
76#include <sys/types.h> 90#include <sys/types.h>
@@ -78,6 +92,7 @@
78 92
79#include "../../include/linux/perf_event.h" 93#include "../../include/linux/perf_event.h"
80#include "util/types.h" 94#include "util/types.h"
95#include <stdbool.h>
81 96
82/* 97/*
83 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all 98 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
@@ -104,8 +119,6 @@ static inline unsigned long long rdclock(void)
104#define __user 119#define __user
105#define asmlinkage 120#define asmlinkage
106 121
107#define __used __attribute__((__unused__))
108
109#define unlikely(x) __builtin_expect(!!(x), 0) 122#define unlikely(x) __builtin_expect(!!(x), 0)
110#define min(x, y) ({ \ 123#define min(x, y) ({ \
111 typeof(x) _min1 = (x); \ 124 typeof(x) _min1 = (x); \
@@ -131,4 +144,6 @@ struct ip_callchain {
131 u64 ips[0]; 144 u64 ips[0];
132}; 145};
133 146
147extern bool perf_host, perf_guest;
148
134#endif 149#endif
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
index af78d9a52a7d..790ceba6ad3f 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
@@ -8,7 +8,7 @@
8 8
9#line 1 "Context.xs" 9#line 1 "Context.xs"
10/* 10/*
11 * Context.xs. XS interfaces for perf trace. 11 * Context.xs. XS interfaces for perf script.
12 * 12 *
13 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> 13 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
14 * 14 *
@@ -31,13 +31,14 @@
31#include "EXTERN.h" 31#include "EXTERN.h"
32#include "perl.h" 32#include "perl.h"
33#include "XSUB.h" 33#include "XSUB.h"
34#include "../../../util/trace-event-perl.h" 34#include "../../../perf.h"
35#include "../../../util/trace-event.h"
35 36
36#ifndef PERL_UNUSED_VAR 37#ifndef PERL_UNUSED_VAR
37# define PERL_UNUSED_VAR(var) if (0) var = var 38# define PERL_UNUSED_VAR(var) if (0) var = var
38#endif 39#endif
39 40
40#line 41 "Context.c" 41#line 42 "Context.c"
41 42
42XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */ 43XS(XS_Perf__Trace__Context_common_pc); /* prototype to pass -Wmissing-prototypes */
43XS(XS_Perf__Trace__Context_common_pc) 44XS(XS_Perf__Trace__Context_common_pc)
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
index fb78006c165e..c1e2ed1ed34e 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
@@ -1,5 +1,5 @@
1/* 1/*
2 * Context.xs. XS interfaces for perf trace. 2 * Context.xs. XS interfaces for perf script.
3 * 3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> 4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 * 5 *
@@ -22,7 +22,8 @@
22#include "EXTERN.h" 22#include "EXTERN.h"
23#include "perl.h" 23#include "perl.h"
24#include "XSUB.h" 24#include "XSUB.h"
25#include "../../../util/trace-event-perl.h" 25#include "../../../perf.h"
26#include "../../../util/script-event.h"
26 27
27MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context 28MODULE = Perf::Trace::Context PACKAGE = Perf::Trace::Context
28PROTOTYPES: ENABLE 29PROTOTYPES: ENABLE
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/README b/tools/perf/scripts/perl/Perf-Trace-Util/README
index 9a9707630791..2f0c7f3043ee 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/README
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/README
@@ -1,7 +1,7 @@
1Perf-Trace-Util version 0.01 1Perf-Trace-Util version 0.01
2============================ 2============================
3 3
4This module contains utility functions for use with perf trace. 4This module contains utility functions for use with perf script.
5 5
6Core.pm and Util.pm are pure Perl modules; Core.pm contains routines 6Core.pm and Util.pm are pure Perl modules; Core.pm contains routines
7that the core perf support for Perl calls on and should always be 7that the core perf support for Perl calls on and should always be
@@ -33,7 +33,7 @@ After you do that:
33 33
34INSTALLATION 34INSTALLATION
35 35
36Building perf with perf trace Perl scripting should install this 36Building perf with perf script Perl scripting should install this
37module in the right place. 37module in the right place.
38 38
39You should make sure libperl and ExtUtils/Embed.pm are installed first 39You should make sure libperl and ExtUtils/Embed.pm are installed first
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
index 6c7f3659cb17..4e2f6039ac92 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Context.pm
@@ -34,7 +34,7 @@ Perf::Trace::Context - Perl extension for accessing functions in perf.
34 34
35=head1 SEE ALSO 35=head1 SEE ALSO
36 36
37Perf (trace) documentation 37Perf (script) documentation
38 38
39=head1 AUTHOR 39=head1 AUTHOR
40 40
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
index 9df376a9f629..9158458d3eeb 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Core.pm
@@ -163,7 +163,7 @@ sub dump_symbolic_fields
163__END__ 163__END__
164=head1 NAME 164=head1 NAME
165 165
166Perf::Trace::Core - Perl extension for perf trace 166Perf::Trace::Core - Perl extension for perf script
167 167
168=head1 SYNOPSIS 168=head1 SYNOPSIS
169 169
@@ -171,7 +171,7 @@ Perf::Trace::Core - Perl extension for perf trace
171 171
172=head1 SEE ALSO 172=head1 SEE ALSO
173 173
174Perf (trace) documentation 174Perf (script) documentation
175 175
176=head1 AUTHOR 176=head1 AUTHOR
177 177
diff --git a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
index 052f132ced24..053500114625 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
@@ -15,6 +15,7 @@ our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
15 15
16our @EXPORT = qw( 16our @EXPORT = qw(
17avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs 17avg nsecs nsecs_secs nsecs_nsecs nsecs_usecs print_nsecs
18clear_term
18); 19);
19 20
20our $VERSION = '0.01'; 21our $VERSION = '0.01';
@@ -44,7 +45,7 @@ sub nsecs_secs {
44sub nsecs_nsecs { 45sub nsecs_nsecs {
45 my ($nsecs) = @_; 46 my ($nsecs) = @_;
46 47
47 return $nsecs - nsecs_secs($nsecs); 48 return $nsecs % $NSECS_PER_SEC;
48} 49}
49 50
50sub nsecs_str { 51sub nsecs_str {
@@ -55,11 +56,16 @@ sub nsecs_str {
55 return $str; 56 return $str;
56} 57}
57 58
59sub clear_term
60{
61 print "\x1b[H\x1b[2J";
62}
63
581; 641;
59__END__ 65__END__
60=head1 NAME 66=head1 NAME
61 67
62Perf::Trace::Util - Perl extension for perf trace 68Perf::Trace::Util - Perl extension for perf script
63 69
64=head1 SYNOPSIS 70=head1 SYNOPSIS
65 71
@@ -67,7 +73,7 @@ Perf::Trace::Util - Perl extension for perf trace
67 73
68=head1 SEE ALSO 74=head1 SEE ALSO
69 75
70Perf (trace) documentation 76Perf (script) documentation
71 77
72=head1 AUTHOR 78=head1 AUTHOR
73 79
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-record b/tools/perf/scripts/perl/bin/check-perf-trace-record
index c7ec5de2f535..423ad6aed056 100644
--- a/tools/perf/scripts/perl/bin/check-perf-trace-record
+++ b/tools/perf/scripts/perl/bin/check-perf-trace-record
@@ -1,7 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -c 1 -f -a -M -R -e kmem:kmalloc -e irq:softirq_entry 2perf record -a -e kmem:kmalloc -e irq:softirq_entry -e kmem:kfree
3
4
5
6
7
diff --git a/tools/perf/scripts/perl/bin/check-perf-trace-report b/tools/perf/scripts/perl/bin/check-perf-trace-report
deleted file mode 100644
index 7fc4a033dd49..000000000000
--- a/tools/perf/scripts/perl/bin/check-perf-trace-report
+++ /dev/null
@@ -1,6 +0,0 @@
1#!/bin/bash
2# description: useless but exhaustive test script
3perf trace -s ~/libexec/perf-core/scripts/perl/check-perf-trace.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-record b/tools/perf/scripts/perl/bin/failed-syscalls-record
new file mode 100644
index 000000000000..8104895a7b67
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e raw_syscalls:sys_exit $@
diff --git a/tools/perf/scripts/perl/bin/failed-syscalls-report b/tools/perf/scripts/perl/bin/failed-syscalls-report
new file mode 100644
index 000000000000..9f83cc1ad8ba
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-report
@@ -0,0 +1,10 @@
1#!/bin/bash
2# description: system-wide failed syscalls
3# args: [comm]
4if [ $# -gt 0 ] ; then
5 if ! expr match "$1" "-" > /dev/null ; then
6 comm=$1
7 shift
8 fi
9fi
10perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/failed-syscalls.pl $comm
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-record b/tools/perf/scripts/perl/bin/rw-by-file-record
index b25056ebf963..33efc8673aae 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-record
+++ b/tools/perf/scripts/perl/bin/rw-by-file-record
@@ -1,2 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_enter_write 2perf record -e syscalls:sys_enter_read -e syscalls:sys_enter_write $@
3
diff --git a/tools/perf/scripts/perl/bin/rw-by-file-report b/tools/perf/scripts/perl/bin/rw-by-file-report
index eddb9ccce6a5..77200b3f3100 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -1,7 +1,10 @@
1#!/bin/bash 1#!/bin/bash
2# description: r/w activity for a program, by file 2# description: r/w activity for a program, by file
3# args: <comm> 3# args: <comm>
4perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $1 4if [ $# -lt 1 ] ; then
5 5 echo "usage: rw-by-file <comm>"
6 6 exit
7 7fi
8comm=$1
9shift
10perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-file.pl $comm
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
index 8903979c5b6c..7cb9db230448 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-record
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -c 1 -f -a -M -R -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write 2perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-report b/tools/perf/scripts/perl/bin/rw-by-pid-report
index 7f44c25cc857..a27b9f311f95 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -1,6 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide r/w activity 2# description: system-wide r/w activity
3perf trace -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl 3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-pid.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/rwtop-record b/tools/perf/scripts/perl/bin/rwtop-record
new file mode 100644
index 000000000000..7cb9db230448
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rwtop-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write $@
diff --git a/tools/perf/scripts/perl/bin/rwtop-report b/tools/perf/scripts/perl/bin/rwtop-report
new file mode 100644
index 000000000000..83e11ec2e190
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rwtop-report
@@ -0,0 +1,20 @@
1#!/bin/bash
2# description: system-wide r/w top
3# args: [interval]
4n_args=0
5for i in "$@"
6do
7 if expr match "$i" "-" > /dev/null ; then
8 break
9 fi
10 n_args=$(( $n_args + 1 ))
11done
12if [ "$n_args" -gt 1 ] ; then
13 echo "usage: rwtop-report [interval]"
14 exit
15fi
16if [ "$n_args" -gt 0 ] ; then
17 interval=$1
18 shift
19fi
20perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/rwtop.pl $interval
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
index 6abedda911a4..464251a1bd7e 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-record
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-record
@@ -1,5 +1,5 @@
1#!/bin/bash 1#!/bin/bash
2perf record -c 1 -f -a -M -R -e sched:sched_switch -e sched:sched_wakeup 2perf record -e sched:sched_switch -e sched:sched_wakeup $@
3 3
4 4
5 5
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-report b/tools/perf/scripts/perl/bin/wakeup-latency-report
index fce3adcb3249..889e8130cca5 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -1,6 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2# description: system-wide min/max/avg wakeup latency 2# description: system-wide min/max/avg wakeup latency
3perf trace -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl 3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/wakeup-latency.pl
4
5
6
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
index fce6637b19ba..8edda9078d5d 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-record
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-record
@@ -1,2 +1,2 @@
1#!/bin/bash 1#!/bin/bash
2perf record -c 1 -f -a -M -R -e workqueue:workqueue_creation -e workqueue:workqueue_destruction -e workqueue:workqueue_execution -e workqueue:workqueue_insertion 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
index 71cfbd182fb9..6d91411d248c 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -1,7 +1,3 @@
1#!/bin/bash 1#!/bin/bash
2# description: workqueue stats (ins/exe/create/destroy) 2# description: workqueue stats (ins/exe/create/destroy)
3perf trace -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl 3perf script $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
4
5
6
7
diff --git a/tools/perf/scripts/perl/check-perf-trace.pl b/tools/perf/scripts/perl/check-perf-trace.pl
index 4e7dc0a407a5..4e7076c20616 100644
--- a/tools/perf/scripts/perl/check-perf-trace.pl
+++ b/tools/perf/scripts/perl/check-perf-trace.pl
@@ -1,4 +1,4 @@
1# perf trace event handlers, generated by perf trace -g perl 1# perf script event handlers, generated by perf script -g perl
2# (c) 2009, Tom Zanussi <tzanussi@gmail.com> 2# (c) 2009, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2 3# Licensed under the terms of the GNU GPL License version 2
4 4
diff --git a/tools/perf/scripts/perl/failed-syscalls.pl b/tools/perf/scripts/perl/failed-syscalls.pl
new file mode 100644
index 000000000000..94bc25a347eb
--- /dev/null
+++ b/tools/perf/scripts/perl/failed-syscalls.pl
@@ -0,0 +1,42 @@
1# failed system call counts
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide failed system call totals
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
9use lib "./Perf-Trace-Util/lib";
10use Perf::Trace::Core;
11use Perf::Trace::Context;
12use Perf::Trace::Util;
13
14my $for_comm = shift;
15
16my %failed_syscalls;
17
18sub raw_syscalls::sys_exit
19{
20 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
21 $common_pid, $common_comm,
22 $id, $ret) = @_;
23
24 if ($ret < 0) {
25 $failed_syscalls{$common_comm}++;
26 }
27}
28
29sub trace_end
30{
31 printf("\nfailed syscalls by comm:\n\n");
32
33 printf("%-20s %10s\n", "comm", "# errors");
34 printf("%-20s %6s %10s\n", "--------------------", "----------");
35
36 foreach my $comm (sort {$failed_syscalls{$b} <=> $failed_syscalls{$a}}
37 keys %failed_syscalls) {
38 next if ($for_comm && $comm ne $for_comm);
39
40 printf("%-20s %10s\n", $comm, $failed_syscalls{$comm});
41 }
42}
diff --git a/tools/perf/scripts/perl/rw-by-file.pl b/tools/perf/scripts/perl/rw-by-file.pl
index 2a39097687b9..74844ee2be3e 100644
--- a/tools/perf/scripts/perl/rw-by-file.pl
+++ b/tools/perf/scripts/perl/rw-by-file.pl
@@ -18,7 +18,7 @@ use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core; 18use Perf::Trace::Core;
19use Perf::Trace::Util; 19use Perf::Trace::Util;
20 20
21my $usage = "perf trace -s rw-by-file.pl <comm>\n"; 21my $usage = "perf script -s rw-by-file.pl <comm>\n";
22 22
23my $for_comm = shift or die $usage; 23my $for_comm = shift or die $usage;
24 24
diff --git a/tools/perf/scripts/perl/rw-by-pid.pl b/tools/perf/scripts/perl/rw-by-pid.pl
index da601fae1a00..9db23c9daf55 100644
--- a/tools/perf/scripts/perl/rw-by-pid.pl
+++ b/tools/perf/scripts/perl/rw-by-pid.pl
@@ -79,12 +79,12 @@ sub trace_end
79 printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------", 79 printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
80 "-----------", "----------", "----------"); 80 "-----------", "----------", "----------");
81 81
82 foreach my $pid (sort {$reads{$b}{bytes_read} <=> 82 foreach my $pid (sort { ($reads{$b}{bytes_read} || 0) <=>
83 $reads{$a}{bytes_read}} keys %reads) { 83 ($reads{$a}{bytes_read} || 0) } keys %reads) {
84 my $comm = $reads{$pid}{comm}; 84 my $comm = $reads{$pid}{comm} || "";
85 my $total_reads = $reads{$pid}{total_reads}; 85 my $total_reads = $reads{$pid}{total_reads} || 0;
86 my $bytes_requested = $reads{$pid}{bytes_requested}; 86 my $bytes_requested = $reads{$pid}{bytes_requested} || 0;
87 my $bytes_read = $reads{$pid}{bytes_read}; 87 my $bytes_read = $reads{$pid}{bytes_read} || 0;
88 88
89 printf("%6s %-20s %10s %10s %10s\n", $pid, $comm, 89 printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
90 $total_reads, $bytes_requested, $bytes_read); 90 $total_reads, $bytes_requested, $bytes_read);
@@ -96,16 +96,23 @@ sub trace_end
96 printf("%6s %20s %6s %10s\n", "------", "--------------------", 96 printf("%6s %20s %6s %10s\n", "------", "--------------------",
97 "------", "----------"); 97 "------", "----------");
98 98
99 foreach my $pid (keys %reads) { 99 my @errcounts = ();
100 my $comm = $reads{$pid}{comm};
101 foreach my $err (sort {$reads{$b}{comm} cmp $reads{$a}{comm}}
102 keys %{$reads{$pid}{errors}}) {
103 my $errors = $reads{$pid}{errors}{$err};
104 100
105 printf("%6d %-20s %6d %10s\n", $pid, $comm, $err, $errors); 101 foreach my $pid (keys %reads) {
102 foreach my $error (keys %{$reads{$pid}{errors}}) {
103 my $comm = $reads{$pid}{comm} || "";
104 my $errcount = $reads{$pid}{errors}{$error} || 0;
105 push @errcounts, [$pid, $comm, $error, $errcount];
106 } 106 }
107 } 107 }
108 108
109 @errcounts = sort { $b->[3] <=> $a->[3] } @errcounts;
110
111 for my $i (0 .. $#errcounts) {
112 printf("%6d %-20s %6d %10s\n", $errcounts[$i][0],
113 $errcounts[$i][1], $errcounts[$i][2], $errcounts[$i][3]);
114 }
115
109 printf("\nwrite counts by pid:\n\n"); 116 printf("\nwrite counts by pid:\n\n");
110 117
111 printf("%6s %20s %10s %10s\n", "pid", "comm", 118 printf("%6s %20s %10s %10s\n", "pid", "comm",
@@ -113,11 +120,11 @@ sub trace_end
113 printf("%6s %-20s %10s %10s\n", "------", "--------------------", 120 printf("%6s %-20s %10s %10s\n", "------", "--------------------",
114 "-----------", "----------"); 121 "-----------", "----------");
115 122
116 foreach my $pid (sort {$writes{$b}{bytes_written} <=> 123 foreach my $pid (sort { ($writes{$b}{bytes_written} || 0) <=>
117 $writes{$a}{bytes_written}} keys %writes) { 124 ($writes{$a}{bytes_written} || 0)} keys %writes) {
118 my $comm = $writes{$pid}{comm}; 125 my $comm = $writes{$pid}{comm} || "";
119 my $total_writes = $writes{$pid}{total_writes}; 126 my $total_writes = $writes{$pid}{total_writes} || 0;
120 my $bytes_written = $writes{$pid}{bytes_written}; 127 my $bytes_written = $writes{$pid}{bytes_written} || 0;
121 128
122 printf("%6s %-20s %10s %10s\n", $pid, $comm, 129 printf("%6s %-20s %10s %10s\n", $pid, $comm,
123 $total_writes, $bytes_written); 130 $total_writes, $bytes_written);
@@ -129,16 +136,23 @@ sub trace_end
129 printf("%6s %20s %6s %10s\n", "------", "--------------------", 136 printf("%6s %20s %6s %10s\n", "------", "--------------------",
130 "------", "----------"); 137 "------", "----------");
131 138
132 foreach my $pid (keys %writes) { 139 @errcounts = ();
133 my $comm = $writes{$pid}{comm};
134 foreach my $err (sort {$writes{$b}{comm} cmp $writes{$a}{comm}}
135 keys %{$writes{$pid}{errors}}) {
136 my $errors = $writes{$pid}{errors}{$err};
137 140
138 printf("%6d %-20s %6d %10s\n", $pid, $comm, $err, $errors); 141 foreach my $pid (keys %writes) {
142 foreach my $error (keys %{$writes{$pid}{errors}}) {
143 my $comm = $writes{$pid}{comm} || "";
144 my $errcount = $writes{$pid}{errors}{$error} || 0;
145 push @errcounts, [$pid, $comm, $error, $errcount];
139 } 146 }
140 } 147 }
141 148
149 @errcounts = sort { $b->[3] <=> $a->[3] } @errcounts;
150
151 for my $i (0 .. $#errcounts) {
152 printf("%6d %-20s %6d %10s\n", $errcounts[$i][0],
153 $errcounts[$i][1], $errcounts[$i][2], $errcounts[$i][3]);
154 }
155
142 print_unhandled(); 156 print_unhandled();
143} 157}
144 158
diff --git a/tools/perf/scripts/perl/rwtop.pl b/tools/perf/scripts/perl/rwtop.pl
new file mode 100644
index 000000000000..4bb3ecd33472
--- /dev/null
+++ b/tools/perf/scripts/perl/rwtop.pl
@@ -0,0 +1,199 @@
1#!/usr/bin/perl -w
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4
5# read/write top
6#
7# Periodically displays system-wide r/w call activity, broken down by
8# pid. If an [interval] arg is specified, the display will be
9# refreshed every [interval] seconds. The default interval is 3
10# seconds.
11
12use 5.010000;
13use strict;
14use warnings;
15
16use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
17use lib "./Perf-Trace-Util/lib";
18use Perf::Trace::Core;
19use Perf::Trace::Util;
20
21my $default_interval = 3;
22my $nlines = 20;
23my $print_thread;
24my $print_pending = 0;
25
26my %reads;
27my %writes;
28
29my $interval = shift;
30if (!$interval) {
31 $interval = $default_interval;
32}
33
34sub syscalls::sys_exit_read
35{
36 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
37 $common_pid, $common_comm,
38 $nr, $ret) = @_;
39
40 print_check();
41
42 if ($ret > 0) {
43 $reads{$common_pid}{bytes_read} += $ret;
44 } else {
45 if (!defined ($reads{$common_pid}{bytes_read})) {
46 $reads{$common_pid}{bytes_read} = 0;
47 }
48 $reads{$common_pid}{errors}{$ret}++;
49 }
50}
51
52sub syscalls::sys_enter_read
53{
54 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
55 $common_pid, $common_comm,
56 $nr, $fd, $buf, $count) = @_;
57
58 print_check();
59
60 $reads{$common_pid}{bytes_requested} += $count;
61 $reads{$common_pid}{total_reads}++;
62 $reads{$common_pid}{comm} = $common_comm;
63}
64
65sub syscalls::sys_exit_write
66{
67 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
68 $common_pid, $common_comm,
69 $nr, $ret) = @_;
70
71 print_check();
72
73 if ($ret <= 0) {
74 $writes{$common_pid}{errors}{$ret}++;
75 }
76}
77
78sub syscalls::sys_enter_write
79{
80 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
81 $common_pid, $common_comm,
82 $nr, $fd, $buf, $count) = @_;
83
84 print_check();
85
86 $writes{$common_pid}{bytes_written} += $count;
87 $writes{$common_pid}{total_writes}++;
88 $writes{$common_pid}{comm} = $common_comm;
89}
90
91sub trace_begin
92{
93 $SIG{ALRM} = \&set_print_pending;
94 alarm 1;
95}
96
97sub trace_end
98{
99 print_unhandled();
100 print_totals();
101}
102
103sub print_check()
104{
105 if ($print_pending == 1) {
106 $print_pending = 0;
107 print_totals();
108 }
109}
110
111sub set_print_pending()
112{
113 $print_pending = 1;
114 alarm $interval;
115}
116
117sub print_totals
118{
119 my $count;
120
121 $count = 0;
122
123 clear_term();
124
125 printf("\nread counts by pid:\n\n");
126
127 printf("%6s %20s %10s %10s %10s\n", "pid", "comm",
128 "# reads", "bytes_req", "bytes_read");
129 printf("%6s %-20s %10s %10s %10s\n", "------", "--------------------",
130 "----------", "----------", "----------");
131
132 foreach my $pid (sort { ($reads{$b}{bytes_read} || 0) <=>
133 ($reads{$a}{bytes_read} || 0) } keys %reads) {
134 my $comm = $reads{$pid}{comm} || "";
135 my $total_reads = $reads{$pid}{total_reads} || 0;
136 my $bytes_requested = $reads{$pid}{bytes_requested} || 0;
137 my $bytes_read = $reads{$pid}{bytes_read} || 0;
138
139 printf("%6s %-20s %10s %10s %10s\n", $pid, $comm,
140 $total_reads, $bytes_requested, $bytes_read);
141
142 if (++$count == $nlines) {
143 last;
144 }
145 }
146
147 $count = 0;
148
149 printf("\nwrite counts by pid:\n\n");
150
151 printf("%6s %20s %10s %13s\n", "pid", "comm",
152 "# writes", "bytes_written");
153 printf("%6s %-20s %10s %13s\n", "------", "--------------------",
154 "----------", "-------------");
155
156 foreach my $pid (sort { ($writes{$b}{bytes_written} || 0) <=>
157 ($writes{$a}{bytes_written} || 0)} keys %writes) {
158 my $comm = $writes{$pid}{comm} || "";
159 my $total_writes = $writes{$pid}{total_writes} || 0;
160 my $bytes_written = $writes{$pid}{bytes_written} || 0;
161
162 printf("%6s %-20s %10s %13s\n", $pid, $comm,
163 $total_writes, $bytes_written);
164
165 if (++$count == $nlines) {
166 last;
167 }
168 }
169
170 %reads = ();
171 %writes = ();
172}
173
174my %unhandled;
175
176sub print_unhandled
177{
178 if ((scalar keys %unhandled) == 0) {
179 return;
180 }
181
182 print "\nunhandled events:\n\n";
183
184 printf("%-40s %10s\n", "event", "count");
185 printf("%-40s %10s\n", "----------------------------------------",
186 "-----------");
187
188 foreach my $event_name (keys %unhandled) {
189 printf("%-40s %10d\n", $event_name, $unhandled{$event_name});
190 }
191}
192
193sub trace_unhandled
194{
195 my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
196 $common_pid, $common_comm) = @_;
197
198 $unhandled{$event_name}++;
199}
diff --git a/tools/perf/scripts/perl/wakeup-latency.pl b/tools/perf/scripts/perl/wakeup-latency.pl
index ed58ef284e23..d9143dcec6c6 100644
--- a/tools/perf/scripts/perl/wakeup-latency.pl
+++ b/tools/perf/scripts/perl/wakeup-latency.pl
@@ -22,8 +22,8 @@ my %last_wakeup;
22 22
23my $max_wakeup_latency; 23my $max_wakeup_latency;
24my $min_wakeup_latency; 24my $min_wakeup_latency;
25my $total_wakeup_latency; 25my $total_wakeup_latency = 0;
26my $total_wakeups; 26my $total_wakeups = 0;
27 27
28sub sched::sched_switch 28sub sched::sched_switch
29{ 29{
@@ -67,8 +67,12 @@ sub trace_end
67{ 67{
68 printf("wakeup_latency stats:\n\n"); 68 printf("wakeup_latency stats:\n\n");
69 print "total_wakeups: $total_wakeups\n"; 69 print "total_wakeups: $total_wakeups\n";
70 printf("avg_wakeup_latency (ns): %u\n", 70 if ($total_wakeups) {
71 avg($total_wakeup_latency, $total_wakeups)); 71 printf("avg_wakeup_latency (ns): %u\n",
72 avg($total_wakeup_latency, $total_wakeups));
73 } else {
74 printf("avg_wakeup_latency (ns): N/A\n");
75 }
72 printf("min_wakeup_latency (ns): %u\n", $min_wakeup_latency); 76 printf("min_wakeup_latency (ns): %u\n", $min_wakeup_latency);
73 printf("max_wakeup_latency (ns): %u\n", $max_wakeup_latency); 77 printf("max_wakeup_latency (ns): %u\n", $max_wakeup_latency);
74 78
diff --git a/tools/perf/scripts/perl/workqueue-stats.pl b/tools/perf/scripts/perl/workqueue-stats.pl
index 511302c8a494..a8eaff5119e0 100644
--- a/tools/perf/scripts/perl/workqueue-stats.pl
+++ b/tools/perf/scripts/perl/workqueue-stats.pl
@@ -10,7 +10,7 @@
10# workqueue:workqueue_destruction -e workqueue:workqueue_execution 10# workqueue:workqueue_destruction -e workqueue:workqueue_execution
11# -e workqueue:workqueue_insertion 11# -e workqueue:workqueue_insertion
12# 12#
13# perf trace -p -s tools/perf/scripts/perl/workqueue-stats.pl 13# perf script -p -s tools/perf/scripts/perl/workqueue-stats.pl
14 14
15use 5.010000; 15use 5.010000;
16use strict; 16use strict;
@@ -71,9 +71,9 @@ sub trace_end
71 printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----"); 71 printf("%3s %6s %6s\t%-20s\n", "---", "---", "----", "----");
72 foreach my $pidhash (@cpus) { 72 foreach my $pidhash (@cpus) {
73 while ((my $pid, my $wqhash) = each %$pidhash) { 73 while ((my $pid, my $wqhash) = each %$pidhash) {
74 my $ins = $$wqhash{'inserted'}; 74 my $ins = $$wqhash{'inserted'} || 0;
75 my $exe = $$wqhash{'executed'}; 75 my $exe = $$wqhash{'executed'} || 0;
76 my $comm = $$wqhash{'comm'}; 76 my $comm = $$wqhash{'comm'} || "";
77 if ($ins || $exe) { 77 if ($ins || $exe) {
78 printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm); 78 printf("%3u %6u %6u\t%-20s\n", $cpu, $ins, $exe, $comm);
79 } 79 }
@@ -87,9 +87,9 @@ sub trace_end
87 printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----"); 87 printf("%3s %6s %6s\t%-20s\n", "---", "-------", "---------", "----");
88 foreach my $pidhash (@cpus) { 88 foreach my $pidhash (@cpus) {
89 while ((my $pid, my $wqhash) = each %$pidhash) { 89 while ((my $pid, my $wqhash) = each %$pidhash) {
90 my $created = $$wqhash{'created'}; 90 my $created = $$wqhash{'created'} || 0;
91 my $destroyed = $$wqhash{'destroyed'}; 91 my $destroyed = $$wqhash{'destroyed'} || 0;
92 my $comm = $$wqhash{'comm'}; 92 my $comm = $$wqhash{'comm'} || "";
93 if ($created || $destroyed) { 93 if ($created || $destroyed) {
94 printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed, 94 printf("%3u %6u %6u\t%-20s\n", $cpu, $created, $destroyed,
95 $comm); 95 $comm);
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/Context.c b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
new file mode 100644
index 000000000000..315067b8f552
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
@@ -0,0 +1,88 @@
1/*
2 * Context.c. Python interfaces for perf script.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
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 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <Python.h>
23#include "../../../perf.h"
24#include "../../../util/trace-event.h"
25
26PyMODINIT_FUNC initperf_trace_context(void);
27
28static PyObject *perf_trace_context_common_pc(PyObject *self, PyObject *args)
29{
30 static struct scripting_context *scripting_context;
31 PyObject *context;
32 int retval;
33
34 if (!PyArg_ParseTuple(args, "O", &context))
35 return NULL;
36
37 scripting_context = PyCObject_AsVoidPtr(context);
38 retval = common_pc(scripting_context);
39
40 return Py_BuildValue("i", retval);
41}
42
43static PyObject *perf_trace_context_common_flags(PyObject *self,
44 PyObject *args)
45{
46 static struct scripting_context *scripting_context;
47 PyObject *context;
48 int retval;
49
50 if (!PyArg_ParseTuple(args, "O", &context))
51 return NULL;
52
53 scripting_context = PyCObject_AsVoidPtr(context);
54 retval = common_flags(scripting_context);
55
56 return Py_BuildValue("i", retval);
57}
58
59static PyObject *perf_trace_context_common_lock_depth(PyObject *self,
60 PyObject *args)
61{
62 static struct scripting_context *scripting_context;
63 PyObject *context;
64 int retval;
65
66 if (!PyArg_ParseTuple(args, "O", &context))
67 return NULL;
68
69 scripting_context = PyCObject_AsVoidPtr(context);
70 retval = common_lock_depth(scripting_context);
71
72 return Py_BuildValue("i", retval);
73}
74
75static PyMethodDef ContextMethods[] = {
76 { "common_pc", perf_trace_context_common_pc, METH_VARARGS,
77 "Get the common preempt count event field value."},
78 { "common_flags", perf_trace_context_common_flags, METH_VARARGS,
79 "Get the common flags event field value."},
80 { "common_lock_depth", perf_trace_context_common_lock_depth,
81 METH_VARARGS, "Get the common lock depth event field value."},
82 { NULL, NULL, 0, NULL}
83};
84
85PyMODINIT_FUNC initperf_trace_context(void)
86{
87 (void) Py_InitModule("perf_trace_context", ContextMethods);
88}
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
new file mode 100644
index 000000000000..de7211e4fa47
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
@@ -0,0 +1,121 @@
1# Core.py - Python extension for perf script, core functions
2#
3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com>
4#
5# This software may be distributed under the terms of the GNU General
6# Public License ("GPL") version 2 as published by the Free Software
7# Foundation.
8
9from collections import defaultdict
10
11def autodict():
12 return defaultdict(autodict)
13
14flag_fields = autodict()
15symbolic_fields = autodict()
16
17def define_flag_field(event_name, field_name, delim):
18 flag_fields[event_name][field_name]['delim'] = delim
19
20def define_flag_value(event_name, field_name, value, field_str):
21 flag_fields[event_name][field_name]['values'][value] = field_str
22
23def define_symbolic_field(event_name, field_name):
24 # nothing to do, really
25 pass
26
27def define_symbolic_value(event_name, field_name, value, field_str):
28 symbolic_fields[event_name][field_name]['values'][value] = field_str
29
30def flag_str(event_name, field_name, value):
31 string = ""
32
33 if flag_fields[event_name][field_name]:
34 print_delim = 0
35 keys = flag_fields[event_name][field_name]['values'].keys()
36 keys.sort()
37 for idx in keys:
38 if not value and not idx:
39 string += flag_fields[event_name][field_name]['values'][idx]
40 break
41 if idx and (value & idx) == idx:
42 if print_delim and flag_fields[event_name][field_name]['delim']:
43 string += " " + flag_fields[event_name][field_name]['delim'] + " "
44 string += flag_fields[event_name][field_name]['values'][idx]
45 print_delim = 1
46 value &= ~idx
47
48 return string
49
50def symbol_str(event_name, field_name, value):
51 string = ""
52
53 if symbolic_fields[event_name][field_name]:
54 keys = symbolic_fields[event_name][field_name]['values'].keys()
55 keys.sort()
56 for idx in keys:
57 if not value and not idx:
58 string = symbolic_fields[event_name][field_name]['values'][idx]
59 break
60 if (value == idx):
61 string = symbolic_fields[event_name][field_name]['values'][idx]
62 break
63
64 return string
65
66trace_flags = { 0x00: "NONE", \
67 0x01: "IRQS_OFF", \
68 0x02: "IRQS_NOSUPPORT", \
69 0x04: "NEED_RESCHED", \
70 0x08: "HARDIRQ", \
71 0x10: "SOFTIRQ" }
72
73def trace_flag_str(value):
74 string = ""
75 print_delim = 0
76
77 keys = trace_flags.keys()
78
79 for idx in keys:
80 if not value and not idx:
81 string += "NONE"
82 break
83
84 if idx and (value & idx) == idx:
85 if print_delim:
86 string += " | ";
87 string += trace_flags[idx]
88 print_delim = 1
89 value &= ~idx
90
91 return string
92
93
94def taskState(state):
95 states = {
96 0 : "R",
97 1 : "S",
98 2 : "D",
99 64: "DEAD"
100 }
101
102 if state not in states:
103 return "Unknown"
104
105 return states[state]
106
107
108class EventHeaders:
109 def __init__(self, common_cpu, common_secs, common_nsecs,
110 common_pid, common_comm):
111 self.cpu = common_cpu
112 self.secs = common_secs
113 self.nsecs = common_nsecs
114 self.pid = common_pid
115 self.comm = common_comm
116
117 def ts(self):
118 return (self.secs * (10 ** 9)) + self.nsecs
119
120 def ts_format(self):
121 return "%d.%d" % (self.secs, int(self.nsecs / 1000))
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py
new file mode 100644
index 000000000000..fdd92f699055
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/SchedGui.py
@@ -0,0 +1,184 @@
1# SchedGui.py - Python extension for perf script, basic GUI code for
2# traces drawing and overview.
3#
4# Copyright (C) 2010 by Frederic Weisbecker <fweisbec@gmail.com>
5#
6# This software is distributed under the terms of the GNU General
7# Public License ("GPL") version 2 as published by the Free Software
8# Foundation.
9
10
11try:
12 import wx
13except ImportError:
14 raise ImportError, "You need to install the wxpython lib for this script"
15
16
17class RootFrame(wx.Frame):
18 Y_OFFSET = 100
19 RECT_HEIGHT = 100
20 RECT_SPACE = 50
21 EVENT_MARKING_WIDTH = 5
22
23 def __init__(self, sched_tracer, title, parent = None, id = -1):
24 wx.Frame.__init__(self, parent, id, title)
25
26 (self.screen_width, self.screen_height) = wx.GetDisplaySize()
27 self.screen_width -= 10
28 self.screen_height -= 10
29 self.zoom = 0.5
30 self.scroll_scale = 20
31 self.sched_tracer = sched_tracer
32 self.sched_tracer.set_root_win(self)
33 (self.ts_start, self.ts_end) = sched_tracer.interval()
34 self.update_width_virtual()
35 self.nr_rects = sched_tracer.nr_rectangles() + 1
36 self.height_virtual = RootFrame.Y_OFFSET + (self.nr_rects * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
37
38 # whole window panel
39 self.panel = wx.Panel(self, size=(self.screen_width, self.screen_height))
40
41 # scrollable container
42 self.scroll = wx.ScrolledWindow(self.panel)
43 self.scroll.SetScrollbars(self.scroll_scale, self.scroll_scale, self.width_virtual / self.scroll_scale, self.height_virtual / self.scroll_scale)
44 self.scroll.EnableScrolling(True, True)
45 self.scroll.SetFocus()
46
47 # scrollable drawing area
48 self.scroll_panel = wx.Panel(self.scroll, size=(self.screen_width - 15, self.screen_height / 2))
49 self.scroll_panel.Bind(wx.EVT_PAINT, self.on_paint)
50 self.scroll_panel.Bind(wx.EVT_KEY_DOWN, self.on_key_press)
51 self.scroll_panel.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
52 self.scroll.Bind(wx.EVT_PAINT, self.on_paint)
53 self.scroll.Bind(wx.EVT_KEY_DOWN, self.on_key_press)
54 self.scroll.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_down)
55
56 self.scroll.Fit()
57 self.Fit()
58
59 self.scroll_panel.SetDimensions(-1, -1, self.width_virtual, self.height_virtual, wx.SIZE_USE_EXISTING)
60
61 self.txt = None
62
63 self.Show(True)
64
65 def us_to_px(self, val):
66 return val / (10 ** 3) * self.zoom
67
68 def px_to_us(self, val):
69 return (val / self.zoom) * (10 ** 3)
70
71 def scroll_start(self):
72 (x, y) = self.scroll.GetViewStart()
73 return (x * self.scroll_scale, y * self.scroll_scale)
74
75 def scroll_start_us(self):
76 (x, y) = self.scroll_start()
77 return self.px_to_us(x)
78
79 def paint_rectangle_zone(self, nr, color, top_color, start, end):
80 offset_px = self.us_to_px(start - self.ts_start)
81 width_px = self.us_to_px(end - self.ts_start)
82
83 offset_py = RootFrame.Y_OFFSET + (nr * (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE))
84 width_py = RootFrame.RECT_HEIGHT
85
86 dc = self.dc
87
88 if top_color is not None:
89 (r, g, b) = top_color
90 top_color = wx.Colour(r, g, b)
91 brush = wx.Brush(top_color, wx.SOLID)
92 dc.SetBrush(brush)
93 dc.DrawRectangle(offset_px, offset_py, width_px, RootFrame.EVENT_MARKING_WIDTH)
94 width_py -= RootFrame.EVENT_MARKING_WIDTH
95 offset_py += RootFrame.EVENT_MARKING_WIDTH
96
97 (r ,g, b) = color
98 color = wx.Colour(r, g, b)
99 brush = wx.Brush(color, wx.SOLID)
100 dc.SetBrush(brush)
101 dc.DrawRectangle(offset_px, offset_py, width_px, width_py)
102
103 def update_rectangles(self, dc, start, end):
104 start += self.ts_start
105 end += self.ts_start
106 self.sched_tracer.fill_zone(start, end)
107
108 def on_paint(self, event):
109 dc = wx.PaintDC(self.scroll_panel)
110 self.dc = dc
111
112 width = min(self.width_virtual, self.screen_width)
113 (x, y) = self.scroll_start()
114 start = self.px_to_us(x)
115 end = self.px_to_us(x + width)
116 self.update_rectangles(dc, start, end)
117
118 def rect_from_ypixel(self, y):
119 y -= RootFrame.Y_OFFSET
120 rect = y / (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)
121 height = y % (RootFrame.RECT_HEIGHT + RootFrame.RECT_SPACE)
122
123 if rect < 0 or rect > self.nr_rects - 1 or height > RootFrame.RECT_HEIGHT:
124 return -1
125
126 return rect
127
128 def update_summary(self, txt):
129 if self.txt:
130 self.txt.Destroy()
131 self.txt = wx.StaticText(self.panel, -1, txt, (0, (self.screen_height / 2) + 50))
132
133
134 def on_mouse_down(self, event):
135 (x, y) = event.GetPositionTuple()
136 rect = self.rect_from_ypixel(y)
137 if rect == -1:
138 return
139
140 t = self.px_to_us(x) + self.ts_start
141
142 self.sched_tracer.mouse_down(rect, t)
143
144
145 def update_width_virtual(self):
146 self.width_virtual = self.us_to_px(self.ts_end - self.ts_start)
147
148 def __zoom(self, x):
149 self.update_width_virtual()
150 (xpos, ypos) = self.scroll.GetViewStart()
151 xpos = self.us_to_px(x) / self.scroll_scale
152 self.scroll.SetScrollbars(self.scroll_scale, self.scroll_scale, self.width_virtual / self.scroll_scale, self.height_virtual / self.scroll_scale, xpos, ypos)
153 self.Refresh()
154
155 def zoom_in(self):
156 x = self.scroll_start_us()
157 self.zoom *= 2
158 self.__zoom(x)
159
160 def zoom_out(self):
161 x = self.scroll_start_us()
162 self.zoom /= 2
163 self.__zoom(x)
164
165
166 def on_key_press(self, event):
167 key = event.GetRawKeyCode()
168 if key == ord("+"):
169 self.zoom_in()
170 return
171 if key == ord("-"):
172 self.zoom_out()
173 return
174
175 key = event.GetKeyCode()
176 (x, y) = self.scroll.GetViewStart()
177 if key == wx.WXK_RIGHT:
178 self.scroll.Scroll(x + 1, y)
179 elif key == wx.WXK_LEFT:
180 self.scroll.Scroll(x - 1, y)
181 elif key == wx.WXK_DOWN:
182 self.scroll.Scroll(x, y + 1)
183 elif key == wx.WXK_UP:
184 self.scroll.Scroll(x, y - 1)
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
new file mode 100644
index 000000000000..15c8400240fd
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -0,0 +1,86 @@
1# Util.py - Python extension for perf script, miscellaneous utility code
2#
3# Copyright (C) 2010 by Tom Zanussi <tzanussi@gmail.com>
4#
5# This software may be distributed under the terms of the GNU General
6# Public License ("GPL") version 2 as published by the Free Software
7# Foundation.
8
9import errno, os
10
11FUTEX_WAIT = 0
12FUTEX_WAKE = 1
13FUTEX_PRIVATE_FLAG = 128
14FUTEX_CLOCK_REALTIME = 256
15FUTEX_CMD_MASK = ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
16
17NSECS_PER_SEC = 1000000000
18
19def avg(total, n):
20 return total / n
21
22def nsecs(secs, nsecs):
23 return secs * NSECS_PER_SEC + nsecs
24
25def nsecs_secs(nsecs):
26 return nsecs / NSECS_PER_SEC
27
28def nsecs_nsecs(nsecs):
29 return nsecs % NSECS_PER_SEC
30
31def nsecs_str(nsecs):
32 str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)),
33 return str
34
35def add_stats(dict, key, value):
36 if not dict.has_key(key):
37 dict[key] = (value, value, value, 1)
38 else:
39 min, max, avg, count = dict[key]
40 if value < min:
41 min = value
42 if value > max:
43 max = value
44 avg = (avg + value) / 2
45 dict[key] = (min, max, avg, count + 1)
46
47def clear_term():
48 print("\x1b[H\x1b[2J")
49
50audit_package_warned = False
51
52try:
53 import audit
54 machine_to_id = {
55 'x86_64': audit.MACH_86_64,
56 'alpha' : audit.MACH_ALPHA,
57 'ia64' : audit.MACH_IA64,
58 'ppc' : audit.MACH_PPC,
59 'ppc64' : audit.MACH_PPC64,
60 's390' : audit.MACH_S390,
61 's390x' : audit.MACH_S390X,
62 'i386' : audit.MACH_X86,
63 'i586' : audit.MACH_X86,
64 'i686' : audit.MACH_X86,
65 }
66 try:
67 machine_to_id['armeb'] = audit.MACH_ARMEB
68 except:
69 pass
70 machine_id = machine_to_id[os.uname()[4]]
71except:
72 if not audit_package_warned:
73 audit_package_warned = True
74 print "Install the audit-libs-python package to get syscall names"
75
76def syscall_name(id):
77 try:
78 return audit.audit_syscall_to_name(id, machine_id)
79 except:
80 return str(id)
81
82def strerror(nr):
83 try:
84 return errno.errorcode[abs(nr)]
85 except:
86 return "Unknown %d errno" % nr
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
new file mode 100644
index 000000000000..8104895a7b67
--- /dev/null
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e raw_syscalls:sys_exit $@
diff --git a/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
new file mode 100644
index 000000000000..fda5096d0cbf
--- /dev/null
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
@@ -0,0 +1,10 @@
1#!/bin/bash
2# description: system-wide failed syscalls, by pid
3# args: [comm]
4if [ $# -gt 0 ] ; then
5 if ! expr match "$1" "-" > /dev/null ; then
6 comm=$1
7 shift
8 fi
9fi
10perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/failed-syscalls-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/futex-contention-record b/tools/perf/scripts/python/bin/futex-contention-record
new file mode 100644
index 000000000000..b1495c9a9b20
--- /dev/null
+++ b/tools/perf/scripts/python/bin/futex-contention-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e syscalls:sys_enter_futex -e syscalls:sys_exit_futex $@
diff --git a/tools/perf/scripts/python/bin/futex-contention-report b/tools/perf/scripts/python/bin/futex-contention-report
new file mode 100644
index 000000000000..6c44271091ab
--- /dev/null
+++ b/tools/perf/scripts/python/bin/futex-contention-report
@@ -0,0 +1,4 @@
1#!/bin/bash
2# description: futext contention measurement
3
4perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/futex-contention.py
diff --git a/tools/perf/scripts/python/bin/netdev-times-record b/tools/perf/scripts/python/bin/netdev-times-record
new file mode 100644
index 000000000000..558754b840a9
--- /dev/null
+++ b/tools/perf/scripts/python/bin/netdev-times-record
@@ -0,0 +1,8 @@
1#!/bin/bash
2perf record -e net:net_dev_xmit -e net:net_dev_queue \
3 -e net:netif_receive_skb -e net:netif_rx \
4 -e skb:consume_skb -e skb:kfree_skb \
5 -e skb:skb_copy_datagram_iovec -e napi:napi_poll \
6 -e irq:irq_handler_entry -e irq:irq_handler_exit \
7 -e irq:softirq_entry -e irq:softirq_exit \
8 -e irq:softirq_raise $@
diff --git a/tools/perf/scripts/python/bin/netdev-times-report b/tools/perf/scripts/python/bin/netdev-times-report
new file mode 100644
index 000000000000..8f759291da86
--- /dev/null
+++ b/tools/perf/scripts/python/bin/netdev-times-report
@@ -0,0 +1,5 @@
1#!/bin/bash
2# description: display a process of packet and processing time
3# args: [tx] [rx] [dev=] [debug]
4
5perf script -s "$PERF_EXEC_PATH"/scripts/python/netdev-times.py $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-record b/tools/perf/scripts/python/bin/sched-migration-record
new file mode 100644
index 000000000000..7493fddbe995
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sched-migration-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -m 16384 -e sched:sched_wakeup -e sched:sched_wakeup_new -e sched:sched_switch -e sched:sched_migrate_task $@
diff --git a/tools/perf/scripts/python/bin/sched-migration-report b/tools/perf/scripts/python/bin/sched-migration-report
new file mode 100644
index 000000000000..68b037a1849b
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sched-migration-report
@@ -0,0 +1,3 @@
1#!/bin/bash
2# description: sched migration overview
3perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/sched-migration.py
diff --git a/tools/perf/scripts/python/bin/sctop-record b/tools/perf/scripts/python/bin/sctop-record
new file mode 100644
index 000000000000..4efbfaa7f6a5
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sctop-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/sctop-report b/tools/perf/scripts/python/bin/sctop-report
new file mode 100644
index 000000000000..c32db294124d
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sctop-report
@@ -0,0 +1,24 @@
1#!/bin/bash
2# description: syscall top
3# args: [comm] [interval]
4n_args=0
5for i in "$@"
6do
7 if expr match "$i" "-" > /dev/null ; then
8 break
9 fi
10 n_args=$(( $n_args + 1 ))
11done
12if [ "$n_args" -gt 2 ] ; then
13 echo "usage: sctop-report [comm] [interval]"
14 exit
15fi
16if [ "$n_args" -gt 1 ] ; then
17 comm=$1
18 interval=$2
19 shift 2
20elif [ "$n_args" -gt 0 ] ; then
21 interval=$1
22 shift
23fi
24perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/sctop.py $comm $interval
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-record b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
new file mode 100644
index 000000000000..4efbfaa7f6a5
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/syscall-counts-by-pid-report b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
new file mode 100644
index 000000000000..16eb8d65c543
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-report
@@ -0,0 +1,10 @@
1#!/bin/bash
2# description: system-wide syscall counts, by pid
3# args: [comm]
4if [ $# -gt 0 ] ; then
5 if ! expr match "$1" "-" > /dev/null ; then
6 comm=$1
7 shift
8 fi
9fi
10perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/syscall-counts-record b/tools/perf/scripts/python/bin/syscall-counts-record
new file mode 100644
index 000000000000..4efbfaa7f6a5
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -e raw_syscalls:sys_enter $@
diff --git a/tools/perf/scripts/python/bin/syscall-counts-report b/tools/perf/scripts/python/bin/syscall-counts-report
new file mode 100644
index 000000000000..0f0e9d453bb4
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-report
@@ -0,0 +1,10 @@
1#!/bin/bash
2# description: system-wide syscall counts
3# args: [comm]
4if [ $# -gt 0 ] ; then
5 if ! expr match "$1" "-" > /dev/null ; then
6 comm=$1
7 shift
8 fi
9fi
10perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts.py $comm
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py
new file mode 100644
index 000000000000..4647a7694cf6
--- /dev/null
+++ b/tools/perf/scripts/python/check-perf-trace.py
@@ -0,0 +1,82 @@
1# perf script event handlers, generated by perf script -g python
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# This script tests basic functionality such as flag and symbol
6# strings, common_xxx() calls back into perf, begin, end, unhandled
7# events, etc. Basically, if this script runs successfully and
8# displays expected results, Python scripting support should be ok.
9
10import os
11import sys
12
13sys.path.append(os.environ['PERF_EXEC_PATH'] + \
14 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15
16from Core import *
17from perf_trace_context import *
18
19unhandled = autodict()
20
21def trace_begin():
22 print "trace_begin"
23 pass
24
25def trace_end():
26 print_unhandled()
27
28def irq__softirq_entry(event_name, context, common_cpu,
29 common_secs, common_nsecs, common_pid, common_comm,
30 vec):
31 print_header(event_name, common_cpu, common_secs, common_nsecs,
32 common_pid, common_comm)
33
34 print_uncommon(context)
35
36 print "vec=%s\n" % \
37 (symbol_str("irq__softirq_entry", "vec", vec)),
38
39def kmem__kmalloc(event_name, context, common_cpu,
40 common_secs, common_nsecs, common_pid, common_comm,
41 call_site, ptr, bytes_req, bytes_alloc,
42 gfp_flags):
43 print_header(event_name, common_cpu, common_secs, common_nsecs,
44 common_pid, common_comm)
45
46 print_uncommon(context)
47
48 print "call_site=%u, ptr=%u, bytes_req=%u, " \
49 "bytes_alloc=%u, gfp_flags=%s\n" % \
50 (call_site, ptr, bytes_req, bytes_alloc,
51
52 flag_str("kmem__kmalloc", "gfp_flags", gfp_flags)),
53
54def trace_unhandled(event_name, context, event_fields_dict):
55 try:
56 unhandled[event_name] += 1
57 except TypeError:
58 unhandled[event_name] = 1
59
60def print_header(event_name, cpu, secs, nsecs, pid, comm):
61 print "%-20s %5u %05u.%09u %8u %-20s " % \
62 (event_name, cpu, secs, nsecs, pid, comm),
63
64# print trace fields not included in handler args
65def print_uncommon(context):
66 print "common_preempt_count=%d, common_flags=%s, common_lock_depth=%d, " \
67 % (common_pc(context), trace_flag_str(common_flags(context)), \
68 common_lock_depth(context))
69
70def print_unhandled():
71 keys = unhandled.keys()
72 if not keys:
73 return
74
75 print "\nunhandled events:\n\n",
76
77 print "%-40s %10s\n" % ("event", "count"),
78 print "%-40s %10s\n" % ("----------------------------------------", \
79 "-----------"),
80
81 for event_name in keys:
82 print "%-40s %10d\n" % (event_name, unhandled[event_name])
diff --git a/tools/perf/scripts/python/failed-syscalls-by-pid.py b/tools/perf/scripts/python/failed-syscalls-by-pid.py
new file mode 100644
index 000000000000..85805fac4116
--- /dev/null
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -0,0 +1,73 @@
1# failed system call counts, by pid
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide failed system call totals, broken down by pid.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8import os
9import sys
10
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13
14from perf_trace_context import *
15from Core import *
16from Util import *
17
18usage = "perf script -s syscall-counts-by-pid.py [comm|pid]\n";
19
20for_comm = None
21for_pid = None
22
23if len(sys.argv) > 2:
24 sys.exit(usage)
25
26if len(sys.argv) > 1:
27 try:
28 for_pid = int(sys.argv[1])
29 except:
30 for_comm = sys.argv[1]
31
32syscalls = autodict()
33
34def trace_begin():
35 print "Press control+C to stop and show the summary"
36
37def trace_end():
38 print_error_totals()
39
40def raw_syscalls__sys_exit(event_name, context, common_cpu,
41 common_secs, common_nsecs, common_pid, common_comm,
42 id, ret):
43 if (for_comm and common_comm != for_comm) or \
44 (for_pid and common_pid != for_pid ):
45 return
46
47 if ret < 0:
48 try:
49 syscalls[common_comm][common_pid][id][ret] += 1
50 except TypeError:
51 syscalls[common_comm][common_pid][id][ret] = 1
52
53def print_error_totals():
54 if for_comm is not None:
55 print "\nsyscall errors for %s:\n\n" % (for_comm),
56 else:
57 print "\nsyscall errors:\n\n",
58
59 print "%-30s %10s\n" % ("comm [pid]", "count"),
60 print "%-30s %10s\n" % ("------------------------------", \
61 "----------"),
62
63 comm_keys = syscalls.keys()
64 for comm in comm_keys:
65 pid_keys = syscalls[comm].keys()
66 for pid in pid_keys:
67 print "\n%s [%d]\n" % (comm, pid),
68 id_keys = syscalls[comm][pid].keys()
69 for id in id_keys:
70 print " syscall: %-16s\n" % syscall_name(id),
71 ret_keys = syscalls[comm][pid][id].keys()
72 for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True):
73 print " err = %-20s %10d\n" % (strerror(ret), val),
diff --git a/tools/perf/scripts/python/futex-contention.py b/tools/perf/scripts/python/futex-contention.py
new file mode 100644
index 000000000000..11e70a388d41
--- /dev/null
+++ b/tools/perf/scripts/python/futex-contention.py
@@ -0,0 +1,50 @@
1# futex contention
2# (c) 2010, Arnaldo Carvalho de Melo <acme@redhat.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Translation of:
6#
7# http://sourceware.org/systemtap/wiki/WSFutexContention
8#
9# to perf python scripting.
10#
11# Measures futex contention
12
13import os, sys
14sys.path.append(os.environ['PERF_EXEC_PATH'] + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15from Util import *
16
17process_names = {}
18thread_thislock = {}
19thread_blocktime = {}
20
21lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time
22process_names = {} # long-lived pid-to-execname mapping
23
24def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm,
25 nr, uaddr, op, val, utime, uaddr2, val3):
26 cmd = op & FUTEX_CMD_MASK
27 if cmd != FUTEX_WAIT:
28 return # we don't care about originators of WAKE events
29
30 process_names[tid] = comm
31 thread_thislock[tid] = uaddr
32 thread_blocktime[tid] = nsecs(s, ns)
33
34def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm,
35 nr, ret):
36 if thread_blocktime.has_key(tid):
37 elapsed = nsecs(s, ns) - thread_blocktime[tid]
38 add_stats(lock_waits, (tid, thread_thislock[tid]), elapsed)
39 del thread_blocktime[tid]
40 del thread_thislock[tid]
41
42def trace_begin():
43 print "Press control+C to stop and show the summary"
44
45def trace_end():
46 for (tid, lock) in lock_waits:
47 min, max, avg, count = lock_waits[tid, lock]
48 print "%s[%d] lock %x contended %d times, %d avg ns" % \
49 (process_names[tid], tid, lock, count, avg)
50
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py
new file mode 100644
index 000000000000..9aa0a32972e8
--- /dev/null
+++ b/tools/perf/scripts/python/netdev-times.py
@@ -0,0 +1,464 @@
1# Display a process of packets and processed time.
2# It helps us to investigate networking or network device.
3#
4# options
5# tx: show only tx chart
6# rx: show only rx chart
7# dev=: show only thing related to specified device
8# debug: work with debug mode. It shows buffer status.
9
10import os
11import sys
12
13sys.path.append(os.environ['PERF_EXEC_PATH'] + \
14 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15
16from perf_trace_context import *
17from Core import *
18from Util import *
19
20all_event_list = []; # insert all tracepoint event related with this script
21irq_dic = {}; # key is cpu and value is a list which stacks irqs
22 # which raise NET_RX softirq
23net_rx_dic = {}; # key is cpu and value include time of NET_RX softirq-entry
24 # and a list which stacks receive
25receive_hunk_list = []; # a list which include a sequence of receive events
26rx_skb_list = []; # received packet list for matching
27 # skb_copy_datagram_iovec
28
29buffer_budget = 65536; # the budget of rx_skb_list, tx_queue_list and
30 # tx_xmit_list
31of_count_rx_skb_list = 0; # overflow count
32
33tx_queue_list = []; # list of packets which pass through dev_queue_xmit
34of_count_tx_queue_list = 0; # overflow count
35
36tx_xmit_list = []; # list of packets which pass through dev_hard_start_xmit
37of_count_tx_xmit_list = 0; # overflow count
38
39tx_free_list = []; # list of packets which is freed
40
41# options
42show_tx = 0;
43show_rx = 0;
44dev = 0; # store a name of device specified by option "dev="
45debug = 0;
46
47# indices of event_info tuple
48EINFO_IDX_NAME= 0
49EINFO_IDX_CONTEXT=1
50EINFO_IDX_CPU= 2
51EINFO_IDX_TIME= 3
52EINFO_IDX_PID= 4
53EINFO_IDX_COMM= 5
54
55# Calculate a time interval(msec) from src(nsec) to dst(nsec)
56def diff_msec(src, dst):
57 return (dst - src) / 1000000.0
58
59# Display a process of transmitting a packet
60def print_transmit(hunk):
61 if dev != 0 and hunk['dev'].find(dev) < 0:
62 return
63 print "%7s %5d %6d.%06dsec %12.3fmsec %12.3fmsec" % \
64 (hunk['dev'], hunk['len'],
65 nsecs_secs(hunk['queue_t']),
66 nsecs_nsecs(hunk['queue_t'])/1000,
67 diff_msec(hunk['queue_t'], hunk['xmit_t']),
68 diff_msec(hunk['xmit_t'], hunk['free_t']))
69
70# Format for displaying rx packet processing
71PF_IRQ_ENTRY= " irq_entry(+%.3fmsec irq=%d:%s)"
72PF_SOFT_ENTRY=" softirq_entry(+%.3fmsec)"
73PF_NAPI_POLL= " napi_poll_exit(+%.3fmsec %s)"
74PF_JOINT= " |"
75PF_WJOINT= " | |"
76PF_NET_RECV= " |---netif_receive_skb(+%.3fmsec skb=%x len=%d)"
77PF_NET_RX= " |---netif_rx(+%.3fmsec skb=%x)"
78PF_CPY_DGRAM= " | skb_copy_datagram_iovec(+%.3fmsec %d:%s)"
79PF_KFREE_SKB= " | kfree_skb(+%.3fmsec location=%x)"
80PF_CONS_SKB= " | consume_skb(+%.3fmsec)"
81
82# Display a process of received packets and interrputs associated with
83# a NET_RX softirq
84def print_receive(hunk):
85 show_hunk = 0
86 irq_list = hunk['irq_list']
87 cpu = irq_list[0]['cpu']
88 base_t = irq_list[0]['irq_ent_t']
89 # check if this hunk should be showed
90 if dev != 0:
91 for i in range(len(irq_list)):
92 if irq_list[i]['name'].find(dev) >= 0:
93 show_hunk = 1
94 break
95 else:
96 show_hunk = 1
97 if show_hunk == 0:
98 return
99
100 print "%d.%06dsec cpu=%d" % \
101 (nsecs_secs(base_t), nsecs_nsecs(base_t)/1000, cpu)
102 for i in range(len(irq_list)):
103 print PF_IRQ_ENTRY % \
104 (diff_msec(base_t, irq_list[i]['irq_ent_t']),
105 irq_list[i]['irq'], irq_list[i]['name'])
106 print PF_JOINT
107 irq_event_list = irq_list[i]['event_list']
108 for j in range(len(irq_event_list)):
109 irq_event = irq_event_list[j]
110 if irq_event['event'] == 'netif_rx':
111 print PF_NET_RX % \
112 (diff_msec(base_t, irq_event['time']),
113 irq_event['skbaddr'])
114 print PF_JOINT
115 print PF_SOFT_ENTRY % \
116 diff_msec(base_t, hunk['sirq_ent_t'])
117 print PF_JOINT
118 event_list = hunk['event_list']
119 for i in range(len(event_list)):
120 event = event_list[i]
121 if event['event_name'] == 'napi_poll':
122 print PF_NAPI_POLL % \
123 (diff_msec(base_t, event['event_t']), event['dev'])
124 if i == len(event_list) - 1:
125 print ""
126 else:
127 print PF_JOINT
128 else:
129 print PF_NET_RECV % \
130 (diff_msec(base_t, event['event_t']), event['skbaddr'],
131 event['len'])
132 if 'comm' in event.keys():
133 print PF_WJOINT
134 print PF_CPY_DGRAM % \
135 (diff_msec(base_t, event['comm_t']),
136 event['pid'], event['comm'])
137 elif 'handle' in event.keys():
138 print PF_WJOINT
139 if event['handle'] == "kfree_skb":
140 print PF_KFREE_SKB % \
141 (diff_msec(base_t,
142 event['comm_t']),
143 event['location'])
144 elif event['handle'] == "consume_skb":
145 print PF_CONS_SKB % \
146 diff_msec(base_t,
147 event['comm_t'])
148 print PF_JOINT
149
150def trace_begin():
151 global show_tx
152 global show_rx
153 global dev
154 global debug
155
156 for i in range(len(sys.argv)):
157 if i == 0:
158 continue
159 arg = sys.argv[i]
160 if arg == 'tx':
161 show_tx = 1
162 elif arg =='rx':
163 show_rx = 1
164 elif arg.find('dev=',0, 4) >= 0:
165 dev = arg[4:]
166 elif arg == 'debug':
167 debug = 1
168 if show_tx == 0 and show_rx == 0:
169 show_tx = 1
170 show_rx = 1
171
172def trace_end():
173 # order all events in time
174 all_event_list.sort(lambda a,b :cmp(a[EINFO_IDX_TIME],
175 b[EINFO_IDX_TIME]))
176 # process all events
177 for i in range(len(all_event_list)):
178 event_info = all_event_list[i]
179 name = event_info[EINFO_IDX_NAME]
180 if name == 'irq__softirq_exit':
181 handle_irq_softirq_exit(event_info)
182 elif name == 'irq__softirq_entry':
183 handle_irq_softirq_entry(event_info)
184 elif name == 'irq__softirq_raise':
185 handle_irq_softirq_raise(event_info)
186 elif name == 'irq__irq_handler_entry':
187 handle_irq_handler_entry(event_info)
188 elif name == 'irq__irq_handler_exit':
189 handle_irq_handler_exit(event_info)
190 elif name == 'napi__napi_poll':
191 handle_napi_poll(event_info)
192 elif name == 'net__netif_receive_skb':
193 handle_netif_receive_skb(event_info)
194 elif name == 'net__netif_rx':
195 handle_netif_rx(event_info)
196 elif name == 'skb__skb_copy_datagram_iovec':
197 handle_skb_copy_datagram_iovec(event_info)
198 elif name == 'net__net_dev_queue':
199 handle_net_dev_queue(event_info)
200 elif name == 'net__net_dev_xmit':
201 handle_net_dev_xmit(event_info)
202 elif name == 'skb__kfree_skb':
203 handle_kfree_skb(event_info)
204 elif name == 'skb__consume_skb':
205 handle_consume_skb(event_info)
206 # display receive hunks
207 if show_rx:
208 for i in range(len(receive_hunk_list)):
209 print_receive(receive_hunk_list[i])
210 # display transmit hunks
211 if show_tx:
212 print " dev len Qdisc " \
213 " netdevice free"
214 for i in range(len(tx_free_list)):
215 print_transmit(tx_free_list[i])
216 if debug:
217 print "debug buffer status"
218 print "----------------------------"
219 print "xmit Qdisc:remain:%d overflow:%d" % \
220 (len(tx_queue_list), of_count_tx_queue_list)
221 print "xmit netdevice:remain:%d overflow:%d" % \
222 (len(tx_xmit_list), of_count_tx_xmit_list)
223 print "receive:remain:%d overflow:%d" % \
224 (len(rx_skb_list), of_count_rx_skb_list)
225
226# called from perf, when it finds a correspoinding event
227def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec):
228 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
229 return
230 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
231 all_event_list.append(event_info)
232
233def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec):
234 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
235 return
236 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
237 all_event_list.append(event_info)
238
239def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec):
240 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
241 return
242 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
243 all_event_list.append(event_info)
244
245def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm,
246 irq, irq_name):
247 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
248 irq, irq_name)
249 all_event_list.append(event_info)
250
251def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret):
252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret)
253 all_event_list.append(event_info)
254
255def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name):
256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
257 napi, dev_name)
258 all_event_list.append(event_info)
259
260def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr,
261 skblen, dev_name):
262 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
263 skbaddr, skblen, dev_name)
264 all_event_list.append(event_info)
265
266def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr,
267 skblen, dev_name):
268 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
269 skbaddr, skblen, dev_name)
270 all_event_list.append(event_info)
271
272def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm,
273 skbaddr, skblen, dev_name):
274 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
275 skbaddr, skblen, dev_name)
276 all_event_list.append(event_info)
277
278def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm,
279 skbaddr, skblen, rc, dev_name):
280 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
281 skbaddr, skblen, rc ,dev_name)
282 all_event_list.append(event_info)
283
284def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm,
285 skbaddr, protocol, location):
286 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
287 skbaddr, protocol, location)
288 all_event_list.append(event_info)
289
290def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr):
291 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
292 skbaddr)
293 all_event_list.append(event_info)
294
295def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm,
296 skbaddr, skblen):
297 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
298 skbaddr, skblen)
299 all_event_list.append(event_info)
300
301def handle_irq_handler_entry(event_info):
302 (name, context, cpu, time, pid, comm, irq, irq_name) = event_info
303 if cpu not in irq_dic.keys():
304 irq_dic[cpu] = []
305 irq_record = {'irq':irq, 'name':irq_name, 'cpu':cpu, 'irq_ent_t':time}
306 irq_dic[cpu].append(irq_record)
307
308def handle_irq_handler_exit(event_info):
309 (name, context, cpu, time, pid, comm, irq, ret) = event_info
310 if cpu not in irq_dic.keys():
311 return
312 irq_record = irq_dic[cpu].pop()
313 if irq != irq_record['irq']:
314 return
315 irq_record.update({'irq_ext_t':time})
316 # if an irq doesn't include NET_RX softirq, drop.
317 if 'event_list' in irq_record.keys():
318 irq_dic[cpu].append(irq_record)
319
320def handle_irq_softirq_raise(event_info):
321 (name, context, cpu, time, pid, comm, vec) = event_info
322 if cpu not in irq_dic.keys() \
323 or len(irq_dic[cpu]) == 0:
324 return
325 irq_record = irq_dic[cpu].pop()
326 if 'event_list' in irq_record.keys():
327 irq_event_list = irq_record['event_list']
328 else:
329 irq_event_list = []
330 irq_event_list.append({'time':time, 'event':'sirq_raise'})
331 irq_record.update({'event_list':irq_event_list})
332 irq_dic[cpu].append(irq_record)
333
334def handle_irq_softirq_entry(event_info):
335 (name, context, cpu, time, pid, comm, vec) = event_info
336 net_rx_dic[cpu] = {'sirq_ent_t':time, 'event_list':[]}
337
338def handle_irq_softirq_exit(event_info):
339 (name, context, cpu, time, pid, comm, vec) = event_info
340 irq_list = []
341 event_list = 0
342 if cpu in irq_dic.keys():
343 irq_list = irq_dic[cpu]
344 del irq_dic[cpu]
345 if cpu in net_rx_dic.keys():
346 sirq_ent_t = net_rx_dic[cpu]['sirq_ent_t']
347 event_list = net_rx_dic[cpu]['event_list']
348 del net_rx_dic[cpu]
349 if irq_list == [] or event_list == 0:
350 return
351 rec_data = {'sirq_ent_t':sirq_ent_t, 'sirq_ext_t':time,
352 'irq_list':irq_list, 'event_list':event_list}
353 # merge information realted to a NET_RX softirq
354 receive_hunk_list.append(rec_data)
355
356def handle_napi_poll(event_info):
357 (name, context, cpu, time, pid, comm, napi, dev_name) = event_info
358 if cpu in net_rx_dic.keys():
359 event_list = net_rx_dic[cpu]['event_list']
360 rec_data = {'event_name':'napi_poll',
361 'dev':dev_name, 'event_t':time}
362 event_list.append(rec_data)
363
364def handle_netif_rx(event_info):
365 (name, context, cpu, time, pid, comm,
366 skbaddr, skblen, dev_name) = event_info
367 if cpu not in irq_dic.keys() \
368 or len(irq_dic[cpu]) == 0:
369 return
370 irq_record = irq_dic[cpu].pop()
371 if 'event_list' in irq_record.keys():
372 irq_event_list = irq_record['event_list']
373 else:
374 irq_event_list = []
375 irq_event_list.append({'time':time, 'event':'netif_rx',
376 'skbaddr':skbaddr, 'skblen':skblen, 'dev_name':dev_name})
377 irq_record.update({'event_list':irq_event_list})
378 irq_dic[cpu].append(irq_record)
379
380def handle_netif_receive_skb(event_info):
381 global of_count_rx_skb_list
382
383 (name, context, cpu, time, pid, comm,
384 skbaddr, skblen, dev_name) = event_info
385 if cpu in net_rx_dic.keys():
386 rec_data = {'event_name':'netif_receive_skb',
387 'event_t':time, 'skbaddr':skbaddr, 'len':skblen}
388 event_list = net_rx_dic[cpu]['event_list']
389 event_list.append(rec_data)
390 rx_skb_list.insert(0, rec_data)
391 if len(rx_skb_list) > buffer_budget:
392 rx_skb_list.pop()
393 of_count_rx_skb_list += 1
394
395def handle_net_dev_queue(event_info):
396 global of_count_tx_queue_list
397
398 (name, context, cpu, time, pid, comm,
399 skbaddr, skblen, dev_name) = event_info
400 skb = {'dev':dev_name, 'skbaddr':skbaddr, 'len':skblen, 'queue_t':time}
401 tx_queue_list.insert(0, skb)
402 if len(tx_queue_list) > buffer_budget:
403 tx_queue_list.pop()
404 of_count_tx_queue_list += 1
405
406def handle_net_dev_xmit(event_info):
407 global of_count_tx_xmit_list
408
409 (name, context, cpu, time, pid, comm,
410 skbaddr, skblen, rc, dev_name) = event_info
411 if rc == 0: # NETDEV_TX_OK
412 for i in range(len(tx_queue_list)):
413 skb = tx_queue_list[i]
414 if skb['skbaddr'] == skbaddr:
415 skb['xmit_t'] = time
416 tx_xmit_list.insert(0, skb)
417 del tx_queue_list[i]
418 if len(tx_xmit_list) > buffer_budget:
419 tx_xmit_list.pop()
420 of_count_tx_xmit_list += 1
421 return
422
423def handle_kfree_skb(event_info):
424 (name, context, cpu, time, pid, comm,
425 skbaddr, protocol, location) = event_info
426 for i in range(len(tx_queue_list)):
427 skb = tx_queue_list[i]
428 if skb['skbaddr'] == skbaddr:
429 del tx_queue_list[i]
430 return
431 for i in range(len(tx_xmit_list)):
432 skb = tx_xmit_list[i]
433 if skb['skbaddr'] == skbaddr:
434 skb['free_t'] = time
435 tx_free_list.append(skb)
436 del tx_xmit_list[i]
437 return
438 for i in range(len(rx_skb_list)):
439 rec_data = rx_skb_list[i]
440 if rec_data['skbaddr'] == skbaddr:
441 rec_data.update({'handle':"kfree_skb",
442 'comm':comm, 'pid':pid, 'comm_t':time})
443 del rx_skb_list[i]
444 return
445
446def handle_consume_skb(event_info):
447 (name, context, cpu, time, pid, comm, skbaddr) = event_info
448 for i in range(len(tx_xmit_list)):
449 skb = tx_xmit_list[i]
450 if skb['skbaddr'] == skbaddr:
451 skb['free_t'] = time
452 tx_free_list.append(skb)
453 del tx_xmit_list[i]
454 return
455
456def handle_skb_copy_datagram_iovec(event_info):
457 (name, context, cpu, time, pid, comm, skbaddr, skblen) = event_info
458 for i in range(len(rx_skb_list)):
459 rec_data = rx_skb_list[i]
460 if skbaddr == rec_data['skbaddr']:
461 rec_data.update({'handle':"skb_copy_datagram_iovec",
462 'comm':comm, 'pid':pid, 'comm_t':time})
463 del rx_skb_list[i]
464 return
diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py
new file mode 100644
index 000000000000..74d55ec08aed
--- /dev/null
+++ b/tools/perf/scripts/python/sched-migration.py
@@ -0,0 +1,461 @@
1#!/usr/bin/python
2#
3# Cpu task migration overview toy
4#
5# Copyright (C) 2010 Frederic Weisbecker <fweisbec@gmail.com>
6#
7# perf script event handlers have been generated by perf script -g python
8#
9# This software is distributed under the terms of the GNU General
10# Public License ("GPL") version 2 as published by the Free Software
11# Foundation.
12
13
14import os
15import sys
16
17from collections import defaultdict
18from UserList import UserList
19
20sys.path.append(os.environ['PERF_EXEC_PATH'] + \
21 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
22sys.path.append('scripts/python/Perf-Trace-Util/lib/Perf/Trace')
23
24from perf_trace_context import *
25from Core import *
26from SchedGui import *
27
28
29threads = { 0 : "idle"}
30
31def thread_name(pid):
32 return "%s:%d" % (threads[pid], pid)
33
34class RunqueueEventUnknown:
35 @staticmethod
36 def color():
37 return None
38
39 def __repr__(self):
40 return "unknown"
41
42class RunqueueEventSleep:
43 @staticmethod
44 def color():
45 return (0, 0, 0xff)
46
47 def __init__(self, sleeper):
48 self.sleeper = sleeper
49
50 def __repr__(self):
51 return "%s gone to sleep" % thread_name(self.sleeper)
52
53class RunqueueEventWakeup:
54 @staticmethod
55 def color():
56 return (0xff, 0xff, 0)
57
58 def __init__(self, wakee):
59 self.wakee = wakee
60
61 def __repr__(self):
62 return "%s woke up" % thread_name(self.wakee)
63
64class RunqueueEventFork:
65 @staticmethod
66 def color():
67 return (0, 0xff, 0)
68
69 def __init__(self, child):
70 self.child = child
71
72 def __repr__(self):
73 return "new forked task %s" % thread_name(self.child)
74
75class RunqueueMigrateIn:
76 @staticmethod
77 def color():
78 return (0, 0xf0, 0xff)
79
80 def __init__(self, new):
81 self.new = new
82
83 def __repr__(self):
84 return "task migrated in %s" % thread_name(self.new)
85
86class RunqueueMigrateOut:
87 @staticmethod
88 def color():
89 return (0xff, 0, 0xff)
90
91 def __init__(self, old):
92 self.old = old
93
94 def __repr__(self):
95 return "task migrated out %s" % thread_name(self.old)
96
97class RunqueueSnapshot:
98 def __init__(self, tasks = [0], event = RunqueueEventUnknown()):
99 self.tasks = tuple(tasks)
100 self.event = event
101
102 def sched_switch(self, prev, prev_state, next):
103 event = RunqueueEventUnknown()
104
105 if taskState(prev_state) == "R" and next in self.tasks \
106 and prev in self.tasks:
107 return self
108
109 if taskState(prev_state) != "R":
110 event = RunqueueEventSleep(prev)
111
112 next_tasks = list(self.tasks[:])
113 if prev in self.tasks:
114 if taskState(prev_state) != "R":
115 next_tasks.remove(prev)
116 elif taskState(prev_state) == "R":
117 next_tasks.append(prev)
118
119 if next not in next_tasks:
120 next_tasks.append(next)
121
122 return RunqueueSnapshot(next_tasks, event)
123
124 def migrate_out(self, old):
125 if old not in self.tasks:
126 return self
127 next_tasks = [task for task in self.tasks if task != old]
128
129 return RunqueueSnapshot(next_tasks, RunqueueMigrateOut(old))
130
131 def __migrate_in(self, new, event):
132 if new in self.tasks:
133 self.event = event
134 return self
135 next_tasks = self.tasks[:] + tuple([new])
136
137 return RunqueueSnapshot(next_tasks, event)
138
139 def migrate_in(self, new):
140 return self.__migrate_in(new, RunqueueMigrateIn(new))
141
142 def wake_up(self, new):
143 return self.__migrate_in(new, RunqueueEventWakeup(new))
144
145 def wake_up_new(self, new):
146 return self.__migrate_in(new, RunqueueEventFork(new))
147
148 def load(self):
149 """ Provide the number of tasks on the runqueue.
150 Don't count idle"""
151 return len(self.tasks) - 1
152
153 def __repr__(self):
154 ret = self.tasks.__repr__()
155 ret += self.origin_tostring()
156
157 return ret
158
159class TimeSlice:
160 def __init__(self, start, prev):
161 self.start = start
162 self.prev = prev
163 self.end = start
164 # cpus that triggered the event
165 self.event_cpus = []
166 if prev is not None:
167 self.total_load = prev.total_load
168 self.rqs = prev.rqs.copy()
169 else:
170 self.rqs = defaultdict(RunqueueSnapshot)
171 self.total_load = 0
172
173 def __update_total_load(self, old_rq, new_rq):
174 diff = new_rq.load() - old_rq.load()
175 self.total_load += diff
176
177 def sched_switch(self, ts_list, prev, prev_state, next, cpu):
178 old_rq = self.prev.rqs[cpu]
179 new_rq = old_rq.sched_switch(prev, prev_state, next)
180
181 if old_rq is new_rq:
182 return
183
184 self.rqs[cpu] = new_rq
185 self.__update_total_load(old_rq, new_rq)
186 ts_list.append(self)
187 self.event_cpus = [cpu]
188
189 def migrate(self, ts_list, new, old_cpu, new_cpu):
190 if old_cpu == new_cpu:
191 return
192 old_rq = self.prev.rqs[old_cpu]
193 out_rq = old_rq.migrate_out(new)
194 self.rqs[old_cpu] = out_rq
195 self.__update_total_load(old_rq, out_rq)
196
197 new_rq = self.prev.rqs[new_cpu]
198 in_rq = new_rq.migrate_in(new)
199 self.rqs[new_cpu] = in_rq
200 self.__update_total_load(new_rq, in_rq)
201
202 ts_list.append(self)
203
204 if old_rq is not out_rq:
205 self.event_cpus.append(old_cpu)
206 self.event_cpus.append(new_cpu)
207
208 def wake_up(self, ts_list, pid, cpu, fork):
209 old_rq = self.prev.rqs[cpu]
210 if fork:
211 new_rq = old_rq.wake_up_new(pid)
212 else:
213 new_rq = old_rq.wake_up(pid)
214
215 if new_rq is old_rq:
216 return
217 self.rqs[cpu] = new_rq
218 self.__update_total_load(old_rq, new_rq)
219 ts_list.append(self)
220 self.event_cpus = [cpu]
221
222 def next(self, t):
223 self.end = t
224 return TimeSlice(t, self)
225
226class TimeSliceList(UserList):
227 def __init__(self, arg = []):
228 self.data = arg
229
230 def get_time_slice(self, ts):
231 if len(self.data) == 0:
232 slice = TimeSlice(ts, TimeSlice(-1, None))
233 else:
234 slice = self.data[-1].next(ts)
235 return slice
236
237 def find_time_slice(self, ts):
238 start = 0
239 end = len(self.data)
240 found = -1
241 searching = True
242 while searching:
243 if start == end or start == end - 1:
244 searching = False
245
246 i = (end + start) / 2
247 if self.data[i].start <= ts and self.data[i].end >= ts:
248 found = i
249 end = i
250 continue
251
252 if self.data[i].end < ts:
253 start = i
254
255 elif self.data[i].start > ts:
256 end = i
257
258 return found
259
260 def set_root_win(self, win):
261 self.root_win = win
262
263 def mouse_down(self, cpu, t):
264 idx = self.find_time_slice(t)
265 if idx == -1:
266 return
267
268 ts = self[idx]
269 rq = ts.rqs[cpu]
270 raw = "CPU: %d\n" % cpu
271 raw += "Last event : %s\n" % rq.event.__repr__()
272 raw += "Timestamp : %d.%06d\n" % (ts.start / (10 ** 9), (ts.start % (10 ** 9)) / 1000)
273 raw += "Duration : %6d us\n" % ((ts.end - ts.start) / (10 ** 6))
274 raw += "Load = %d\n" % rq.load()
275 for t in rq.tasks:
276 raw += "%s \n" % thread_name(t)
277
278 self.root_win.update_summary(raw)
279
280 def update_rectangle_cpu(self, slice, cpu):
281 rq = slice.rqs[cpu]
282
283 if slice.total_load != 0:
284 load_rate = rq.load() / float(slice.total_load)
285 else:
286 load_rate = 0
287
288 red_power = int(0xff - (0xff * load_rate))
289 color = (0xff, red_power, red_power)
290
291 top_color = None
292
293 if cpu in slice.event_cpus:
294 top_color = rq.event.color()
295
296 self.root_win.paint_rectangle_zone(cpu, color, top_color, slice.start, slice.end)
297
298 def fill_zone(self, start, end):
299 i = self.find_time_slice(start)
300 if i == -1:
301 return
302
303 for i in xrange(i, len(self.data)):
304 timeslice = self.data[i]
305 if timeslice.start > end:
306 return
307
308 for cpu in timeslice.rqs:
309 self.update_rectangle_cpu(timeslice, cpu)
310
311 def interval(self):
312 if len(self.data) == 0:
313 return (0, 0)
314
315 return (self.data[0].start, self.data[-1].end)
316
317 def nr_rectangles(self):
318 last_ts = self.data[-1]
319 max_cpu = 0
320 for cpu in last_ts.rqs:
321 if cpu > max_cpu:
322 max_cpu = cpu
323 return max_cpu
324
325
326class SchedEventProxy:
327 def __init__(self):
328 self.current_tsk = defaultdict(lambda : -1)
329 self.timeslices = TimeSliceList()
330
331 def sched_switch(self, headers, prev_comm, prev_pid, prev_prio, prev_state,
332 next_comm, next_pid, next_prio):
333 """ Ensure the task we sched out this cpu is really the one
334 we logged. Otherwise we may have missed traces """
335
336 on_cpu_task = self.current_tsk[headers.cpu]
337
338 if on_cpu_task != -1 and on_cpu_task != prev_pid:
339 print "Sched switch event rejected ts: %s cpu: %d prev: %s(%d) next: %s(%d)" % \
340 (headers.ts_format(), headers.cpu, prev_comm, prev_pid, next_comm, next_pid)
341
342 threads[prev_pid] = prev_comm
343 threads[next_pid] = next_comm
344 self.current_tsk[headers.cpu] = next_pid
345
346 ts = self.timeslices.get_time_slice(headers.ts())
347 ts.sched_switch(self.timeslices, prev_pid, prev_state, next_pid, headers.cpu)
348
349 def migrate(self, headers, pid, prio, orig_cpu, dest_cpu):
350 ts = self.timeslices.get_time_slice(headers.ts())
351 ts.migrate(self.timeslices, pid, orig_cpu, dest_cpu)
352
353 def wake_up(self, headers, comm, pid, success, target_cpu, fork):
354 if success == 0:
355 return
356 ts = self.timeslices.get_time_slice(headers.ts())
357 ts.wake_up(self.timeslices, pid, target_cpu, fork)
358
359
360def trace_begin():
361 global parser
362 parser = SchedEventProxy()
363
364def trace_end():
365 app = wx.App(False)
366 timeslices = parser.timeslices
367 frame = RootFrame(timeslices, "Migration")
368 app.MainLoop()
369
370def sched__sched_stat_runtime(event_name, context, common_cpu,
371 common_secs, common_nsecs, common_pid, common_comm,
372 comm, pid, runtime, vruntime):
373 pass
374
375def sched__sched_stat_iowait(event_name, context, common_cpu,
376 common_secs, common_nsecs, common_pid, common_comm,
377 comm, pid, delay):
378 pass
379
380def sched__sched_stat_sleep(event_name, context, common_cpu,
381 common_secs, common_nsecs, common_pid, common_comm,
382 comm, pid, delay):
383 pass
384
385def sched__sched_stat_wait(event_name, context, common_cpu,
386 common_secs, common_nsecs, common_pid, common_comm,
387 comm, pid, delay):
388 pass
389
390def sched__sched_process_fork(event_name, context, common_cpu,
391 common_secs, common_nsecs, common_pid, common_comm,
392 parent_comm, parent_pid, child_comm, child_pid):
393 pass
394
395def sched__sched_process_wait(event_name, context, common_cpu,
396 common_secs, common_nsecs, common_pid, common_comm,
397 comm, pid, prio):
398 pass
399
400def sched__sched_process_exit(event_name, context, common_cpu,
401 common_secs, common_nsecs, common_pid, common_comm,
402 comm, pid, prio):
403 pass
404
405def sched__sched_process_free(event_name, context, common_cpu,
406 common_secs, common_nsecs, common_pid, common_comm,
407 comm, pid, prio):
408 pass
409
410def sched__sched_migrate_task(event_name, context, common_cpu,
411 common_secs, common_nsecs, common_pid, common_comm,
412 comm, pid, prio, orig_cpu,
413 dest_cpu):
414 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
415 common_pid, common_comm)
416 parser.migrate(headers, pid, prio, orig_cpu, dest_cpu)
417
418def sched__sched_switch(event_name, context, common_cpu,
419 common_secs, common_nsecs, common_pid, common_comm,
420 prev_comm, prev_pid, prev_prio, prev_state,
421 next_comm, next_pid, next_prio):
422
423 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
424 common_pid, common_comm)
425 parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state,
426 next_comm, next_pid, next_prio)
427
428def sched__sched_wakeup_new(event_name, context, common_cpu,
429 common_secs, common_nsecs, common_pid, common_comm,
430 comm, pid, prio, success,
431 target_cpu):
432 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
433 common_pid, common_comm)
434 parser.wake_up(headers, comm, pid, success, target_cpu, 1)
435
436def sched__sched_wakeup(event_name, context, common_cpu,
437 common_secs, common_nsecs, common_pid, common_comm,
438 comm, pid, prio, success,
439 target_cpu):
440 headers = EventHeaders(common_cpu, common_secs, common_nsecs,
441 common_pid, common_comm)
442 parser.wake_up(headers, comm, pid, success, target_cpu, 0)
443
444def sched__sched_wait_task(event_name, context, common_cpu,
445 common_secs, common_nsecs, common_pid, common_comm,
446 comm, pid, prio):
447 pass
448
449def sched__sched_kthread_stop_ret(event_name, context, common_cpu,
450 common_secs, common_nsecs, common_pid, common_comm,
451 ret):
452 pass
453
454def sched__sched_kthread_stop(event_name, context, common_cpu,
455 common_secs, common_nsecs, common_pid, common_comm,
456 comm, pid):
457 pass
458
459def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
460 common_pid, common_comm):
461 pass
diff --git a/tools/perf/scripts/python/sctop.py b/tools/perf/scripts/python/sctop.py
new file mode 100644
index 000000000000..42c267e292fa
--- /dev/null
+++ b/tools/perf/scripts/python/sctop.py
@@ -0,0 +1,75 @@
1# system call top
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Periodically displays system-wide system call totals, broken down by
6# syscall. If a [comm] arg is specified, only syscalls called by
7# [comm] are displayed. If an [interval] arg is specified, the display
8# will be refreshed every [interval] seconds. The default interval is
9# 3 seconds.
10
11import os, sys, thread, time
12
13sys.path.append(os.environ['PERF_EXEC_PATH'] + \
14 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
15
16from perf_trace_context import *
17from Core import *
18from Util import *
19
20usage = "perf script -s sctop.py [comm] [interval]\n";
21
22for_comm = None
23default_interval = 3
24interval = default_interval
25
26if len(sys.argv) > 3:
27 sys.exit(usage)
28
29if len(sys.argv) > 2:
30 for_comm = sys.argv[1]
31 interval = int(sys.argv[2])
32elif len(sys.argv) > 1:
33 try:
34 interval = int(sys.argv[1])
35 except ValueError:
36 for_comm = sys.argv[1]
37 interval = default_interval
38
39syscalls = autodict()
40
41def trace_begin():
42 thread.start_new_thread(print_syscall_totals, (interval,))
43 pass
44
45def raw_syscalls__sys_enter(event_name, context, common_cpu,
46 common_secs, common_nsecs, common_pid, common_comm,
47 id, args):
48 if for_comm is not None:
49 if common_comm != for_comm:
50 return
51 try:
52 syscalls[id] += 1
53 except TypeError:
54 syscalls[id] = 1
55
56def print_syscall_totals(interval):
57 while 1:
58 clear_term()
59 if for_comm is not None:
60 print "\nsyscall events for %s:\n\n" % (for_comm),
61 else:
62 print "\nsyscall events:\n\n",
63
64 print "%-40s %10s\n" % ("event", "count"),
65 print "%-40s %10s\n" % ("----------------------------------------", \
66 "----------"),
67
68 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
69 reverse = True):
70 try:
71 print "%-40s %10d\n" % (syscall_name(id), val),
72 except TypeError:
73 pass
74 syscalls.clear()
75 time.sleep(interval)
diff --git a/tools/perf/scripts/python/syscall-counts-by-pid.py b/tools/perf/scripts/python/syscall-counts-by-pid.py
new file mode 100644
index 000000000000..c64d1c55d745
--- /dev/null
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -0,0 +1,69 @@
1# system call counts, by pid
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide system call totals, broken down by syscall.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8import os, sys
9
10sys.path.append(os.environ['PERF_EXEC_PATH'] + \
11 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
12
13from perf_trace_context import *
14from Core import *
15from Util import syscall_name
16
17usage = "perf script -s syscall-counts-by-pid.py [comm]\n";
18
19for_comm = None
20for_pid = None
21
22if len(sys.argv) > 2:
23 sys.exit(usage)
24
25if len(sys.argv) > 1:
26 try:
27 for_pid = int(sys.argv[1])
28 except:
29 for_comm = sys.argv[1]
30
31syscalls = autodict()
32
33def trace_begin():
34 print "Press control+C to stop and show the summary"
35
36def trace_end():
37 print_syscall_totals()
38
39def raw_syscalls__sys_enter(event_name, context, common_cpu,
40 common_secs, common_nsecs, common_pid, common_comm,
41 id, args):
42
43 if (for_comm and common_comm != for_comm) or \
44 (for_pid and common_pid != for_pid ):
45 return
46 try:
47 syscalls[common_comm][common_pid][id] += 1
48 except TypeError:
49 syscalls[common_comm][common_pid][id] = 1
50
51def print_syscall_totals():
52 if for_comm is not None:
53 print "\nsyscall events for %s:\n\n" % (for_comm),
54 else:
55 print "\nsyscall events by comm/pid:\n\n",
56
57 print "%-40s %10s\n" % ("comm [pid]/syscalls", "count"),
58 print "%-40s %10s\n" % ("----------------------------------------", \
59 "----------"),
60
61 comm_keys = syscalls.keys()
62 for comm in comm_keys:
63 pid_keys = syscalls[comm].keys()
64 for pid in pid_keys:
65 print "\n%s [%d]\n" % (comm, pid),
66 id_keys = syscalls[comm][pid].keys()
67 for id, val in sorted(syscalls[comm][pid].iteritems(), \
68 key = lambda(k, v): (v, k), reverse = True):
69 print " %-38s %10d\n" % (syscall_name(id), val),
diff --git a/tools/perf/scripts/python/syscall-counts.py b/tools/perf/scripts/python/syscall-counts.py
new file mode 100644
index 000000000000..b435d3f188e8
--- /dev/null
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -0,0 +1,59 @@
1# system call counts
2# (c) 2010, Tom Zanussi <tzanussi@gmail.com>
3# Licensed under the terms of the GNU GPL License version 2
4#
5# Displays system-wide system call totals, broken down by syscall.
6# If a [comm] arg is specified, only syscalls called by [comm] are displayed.
7
8import os
9import sys
10
11sys.path.append(os.environ['PERF_EXEC_PATH'] + \
12 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
13
14from perf_trace_context import *
15from Core import *
16from Util import syscall_name
17
18usage = "perf script -s syscall-counts.py [comm]\n";
19
20for_comm = None
21
22if len(sys.argv) > 2:
23 sys.exit(usage)
24
25if len(sys.argv) > 1:
26 for_comm = sys.argv[1]
27
28syscalls = autodict()
29
30def trace_begin():
31 print "Press control+C to stop and show the summary"
32
33def trace_end():
34 print_syscall_totals()
35
36def raw_syscalls__sys_enter(event_name, context, common_cpu,
37 common_secs, common_nsecs, common_pid, common_comm,
38 id, args):
39 if for_comm is not None:
40 if common_comm != for_comm:
41 return
42 try:
43 syscalls[id] += 1
44 except TypeError:
45 syscalls[id] = 1
46
47def print_syscall_totals():
48 if for_comm is not None:
49 print "\nsyscall events for %s:\n\n" % (for_comm),
50 else:
51 print "\nsyscall events:\n\n",
52
53 print "%-40s %10s\n" % ("event", "count"),
54 print "%-40s %10s\n" % ("----------------------------------------", \
55 "-----------"),
56
57 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
58 reverse = True):
59 print "%-40s %10d\n" % (syscall_name(id), val),
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 54552a00a117..97d76562a1a0 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -1,17 +1,17 @@
1#!/bin/sh 1#!/bin/sh
2 2
3GVF=PERF-VERSION-FILE 3if [ $# -eq 1 ] ; then
4DEF_VER=v0.0.2.PERF 4 OUTPUT=$1
5fi
6
7GVF=${OUTPUT}PERF-VERSION-FILE
5 8
6LF=' 9LF='
7' 10'
8 11
9# First see if there is a version file (included in release tarballs), 12# First check if there is a .git to get the version from git describe
10# then try git-describe, then default. 13# otherwise try to get the version from the kernel makefile
11if test -f version 14if test -d ../../.git -o -f ../../.git &&
12then
13 VN=$(cat version) || VN="$DEF_VER"
14elif test -d .git -o -f .git &&
15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && 15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
16 case "$VN" in 16 case "$VN" in
17 *$LF*) (exit 1) ;; 17 *$LF*) (exit 1) ;;
@@ -23,7 +23,12 @@ elif test -d .git -o -f .git &&
23then 23then
24 VN=$(echo "$VN" | sed -e 's/-/./g'); 24 VN=$(echo "$VN" | sed -e 's/-/./g');
25else 25else
26 VN="$DEF_VER" 26 eval `grep '^VERSION\s*=' ../../Makefile|tr -d ' '`
27 eval `grep '^PATCHLEVEL\s*=' ../../Makefile|tr -d ' '`
28 eval `grep '^SUBLEVEL\s*=' ../../Makefile|tr -d ' '`
29 eval `grep '^EXTRAVERSION\s*=' ../../Makefile|tr -d ' '`
30
31 VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
27fi 32fi
28 33
29VN=$(expr "$VN" : v*'\(.*\)') 34VN=$(expr "$VN" : v*'\(.*\)')
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
index a791dd467261..0e76affe9c36 100644
--- a/tools/perf/util/abspath.c
+++ b/tools/perf/util/abspath.c
@@ -1,86 +1,5 @@
1#include "cache.h" 1#include "cache.h"
2 2
3/*
4 * Do not use this for inspecting *tracked* content. When path is a
5 * symlink to a directory, we do not want to say it is a directory when
6 * dealing with tracked content in the working tree.
7 */
8static int is_directory(const char *path)
9{
10 struct stat st;
11 return (!stat(path, &st) && S_ISDIR(st.st_mode));
12}
13
14/* We allow "recursive" symbolic links. Only within reason, though. */
15#define MAXDEPTH 5
16
17const char *make_absolute_path(const char *path)
18{
19 static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
20 char cwd[1024] = "";
21 int buf_index = 1, len;
22
23 int depth = MAXDEPTH;
24 char *last_elem = NULL;
25 struct stat st;
26
27 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
28 die ("Too long path: %.*s", 60, path);
29
30 while (depth--) {
31 if (!is_directory(buf)) {
32 char *last_slash = strrchr(buf, '/');
33 if (last_slash) {
34 *last_slash = '\0';
35 last_elem = xstrdup(last_slash + 1);
36 } else {
37 last_elem = xstrdup(buf);
38 *buf = '\0';
39 }
40 }
41
42 if (*buf) {
43 if (!*cwd && !getcwd(cwd, sizeof(cwd)))
44 die ("Could not get current working directory");
45
46 if (chdir(buf))
47 die ("Could not switch to '%s'", buf);
48 }
49 if (!getcwd(buf, PATH_MAX))
50 die ("Could not get current working directory");
51
52 if (last_elem) {
53 len = strlen(buf);
54
55 if (len + strlen(last_elem) + 2 > PATH_MAX)
56 die ("Too long path name: '%s/%s'",
57 buf, last_elem);
58 buf[len] = '/';
59 strcpy(buf + len + 1, last_elem);
60 free(last_elem);
61 last_elem = NULL;
62 }
63
64 if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
65 len = readlink(buf, next_buf, PATH_MAX);
66 if (len < 0)
67 die ("Invalid symlink: %s", buf);
68 if (PATH_MAX <= len)
69 die("symbolic link too long: %s", buf);
70 next_buf[len] = '\0';
71 buf = next_buf;
72 buf_index = 1 - buf_index;
73 next_buf = bufs[buf_index];
74 } else
75 break;
76 }
77
78 if (*cwd && chdir(cwd))
79 die ("Could not change back to '%s'", cwd);
80
81 return buf;
82}
83
84static const char *get_pwd_cwd(void) 3static const char *get_pwd_cwd(void)
85{ 4{
86 static char cwd[PATH_MAX + 1]; 5 static char cwd[PATH_MAX + 1];
diff --git a/tools/perf/util/bitmap.c b/tools/perf/util/bitmap.c
new file mode 100644
index 000000000000..5e230acae1e9
--- /dev/null
+++ b/tools/perf/util/bitmap.c
@@ -0,0 +1,21 @@
1/*
2 * From lib/bitmap.c
3 * Helper functions for bitmap.h.
4 *
5 * This source code is licensed under the GNU General Public License,
6 * Version 2. See the file COPYING for more details.
7 */
8#include <linux/bitmap.h>
9
10int __bitmap_weight(const unsigned long *bitmap, int bits)
11{
12 int k, w = 0, lim = bits/BITS_PER_LONG;
13
14 for (k = 0; k < lim; k++)
15 w += hweight_long(bitmap[k]);
16
17 if (bits % BITS_PER_LONG)
18 w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
19
20 return w;
21}
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
new file mode 100644
index 000000000000..deffb8c96071
--- /dev/null
+++ b/tools/perf/util/build-id.c
@@ -0,0 +1,80 @@
1/*
2 * build-id.c
3 *
4 * build-id support
5 *
6 * Copyright (C) 2009, 2010 Red Hat Inc.
7 * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
8 */
9#include "util.h"
10#include <stdio.h>
11#include "build-id.h"
12#include "event.h"
13#include "symbol.h"
14#include <linux/kernel.h>
15#include "debug.h"
16
17static int build_id__mark_dso_hit(event_t *event,
18 struct sample_data *sample __used,
19 struct perf_session *session)
20{
21 struct addr_location al;
22 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
23 struct thread *thread = perf_session__findnew(session, event->ip.pid);
24
25 if (thread == NULL) {
26 pr_err("problem processing %d event, skipping it.\n",
27 event->header.type);
28 return -1;
29 }
30
31 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
32 event->ip.pid, event->ip.ip, &al);
33
34 if (al.map != NULL)
35 al.map->dso->hit = 1;
36
37 return 0;
38}
39
40static int event__exit_del_thread(event_t *self, struct sample_data *sample __used,
41 struct perf_session *session)
42{
43 struct thread *thread = perf_session__findnew(session, self->fork.tid);
44
45 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
46 self->fork.ppid, self->fork.ptid);
47
48 if (thread) {
49 rb_erase(&thread->rb_node, &session->threads);
50 session->last_match = NULL;
51 thread__delete(thread);
52 }
53
54 return 0;
55}
56
57struct perf_event_ops build_id__mark_dso_hit_ops = {
58 .sample = build_id__mark_dso_hit,
59 .mmap = event__process_mmap,
60 .fork = event__process_task,
61 .exit = event__exit_del_thread,
62};
63
64char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
65{
66 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
67
68 if (!self->has_build_id)
69 return NULL;
70
71 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
72 if (bf == NULL) {
73 if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
74 build_id_hex, build_id_hex + 2) < 0)
75 return NULL;
76 } else
77 snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
78 build_id_hex, build_id_hex + 2);
79 return bf;
80}
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
new file mode 100644
index 000000000000..5dafb00eaa06
--- /dev/null
+++ b/tools/perf/util/build-id.h
@@ -0,0 +1,10 @@
1#ifndef PERF_BUILD_ID_H_
2#define PERF_BUILD_ID_H_ 1
3
4#include "session.h"
5
6extern struct perf_event_ops build_id__mark_dso_hit_ops;
7
8char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
9
10#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 918eb376abe3..a7729797fd96 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_CACHE_H 1#ifndef __PERF_CACHE_H
2#define __PERF_CACHE_H 2#define __PERF_CACHE_H
3 3
4#include <stdbool.h>
4#include "util.h" 5#include "util.h"
5#include "strbuf.h" 6#include "strbuf.h"
6#include "../perf.h" 7#include "../perf.h"
@@ -12,56 +13,17 @@
12 13
13#define PERF_DIR_ENVIRONMENT "PERF_DIR" 14#define PERF_DIR_ENVIRONMENT "PERF_DIR"
14#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE" 15#define PERF_WORK_TREE_ENVIRONMENT "PERF_WORK_TREE"
15#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
16#define DB_ENVIRONMENT "PERF_OBJECT_DIRECTORY"
17#define INDEX_ENVIRONMENT "PERF_INDEX_FILE"
18#define GRAFT_ENVIRONMENT "PERF_GRAFT_FILE"
19#define TEMPLATE_DIR_ENVIRONMENT "PERF_TEMPLATE_DIR"
20#define CONFIG_ENVIRONMENT "PERF_CONFIG"
21#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH" 16#define EXEC_PATH_ENVIRONMENT "PERF_EXEC_PATH"
22#define CEILING_DIRECTORIES_ENVIRONMENT "PERF_CEILING_DIRECTORIES" 17#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
23#define PERFATTRIBUTES_FILE ".perfattributes"
24#define INFOATTRIBUTES_FILE "info/attributes"
25#define ATTRIBUTE_MACRO_PREFIX "[attr]"
26#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" 18#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
27 19
28typedef int (*config_fn_t)(const char *, const char *, void *); 20typedef int (*config_fn_t)(const char *, const char *, void *);
29extern int perf_default_config(const char *, const char *, void *); 21extern int perf_default_config(const char *, const char *, void *);
30extern int perf_config_from_file(config_fn_t fn, const char *, void *);
31extern int perf_config(config_fn_t fn, void *); 22extern int perf_config(config_fn_t fn, void *);
32extern int perf_parse_ulong(const char *, unsigned long *);
33extern int perf_config_int(const char *, const char *); 23extern int perf_config_int(const char *, const char *);
34extern unsigned long perf_config_ulong(const char *, const char *);
35extern int perf_config_bool_or_int(const char *, const char *, int *);
36extern int perf_config_bool(const char *, const char *); 24extern int perf_config_bool(const char *, const char *);
37extern int perf_config_string(const char **, const char *, const char *);
38extern int perf_config_set(const char *, const char *);
39extern int perf_config_set_multivar(const char *, const char *, const char *, int);
40extern int perf_config_rename_section(const char *, const char *);
41extern const char *perf_etc_perfconfig(void);
42extern int check_repository_format_version(const char *var, const char *value, void *cb);
43extern int perf_config_system(void);
44extern int perf_config_global(void);
45extern int config_error_nonbool(const char *); 25extern int config_error_nonbool(const char *);
46extern const char *config_exclusive_filename; 26extern const char *perf_config_dirname(const char *, const char *);
47
48#define MAX_PERFNAME (1000)
49extern char perf_default_email[MAX_PERFNAME];
50extern char perf_default_name[MAX_PERFNAME];
51extern int user_ident_explicitly_given;
52
53extern const char *perf_log_output_encoding;
54extern const char *perf_mailmap_file;
55
56/* IO helper functions */
57extern void maybe_flush_or_die(FILE *, const char *);
58extern int copy_fd(int ifd, int ofd);
59extern int copy_file(const char *dst, const char *src, int mode);
60extern ssize_t write_in_full(int fd, const void *buf, size_t count);
61extern void write_or_die(int fd, const void *buf, size_t count);
62extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
63extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
64extern void fsync_or_die(int fd, const char *);
65 27
66/* pager.c */ 28/* pager.c */
67extern void setup_pager(void); 29extern void setup_pager(void);
@@ -69,8 +31,18 @@ extern const char *pager_program;
69extern int pager_in_use(void); 31extern int pager_in_use(void);
70extern int pager_use_color; 32extern int pager_use_color;
71 33
72extern const char *editor_program; 34extern int use_browser;
73extern const char *excludes_file; 35
36#ifdef NO_NEWT_SUPPORT
37static inline void setup_browser(void)
38{
39 setup_pager();
40}
41static inline void exit_browser(bool wait_for_ok __used) {}
42#else
43void setup_browser(void);
44void exit_browser(bool wait_for_ok);
45#endif
74 46
75char *alias_lookup(const char *alias); 47char *alias_lookup(const char *alias);
76int split_cmdline(char *cmdline, const char ***argv); 48int split_cmdline(char *cmdline, const char ***argv);
@@ -101,25 +73,17 @@ static inline int is_absolute_path(const char *path)
101 return path[0] == '/'; 73 return path[0] == '/';
102} 74}
103 75
104const char *make_absolute_path(const char *path);
105const char *make_nonrelative_path(const char *path); 76const char *make_nonrelative_path(const char *path);
106const char *make_relative_path(const char *abs, const char *base);
107int normalize_path_copy(char *dst, const char *src);
108int longest_ancestor_length(const char *path, const char *prefix_list);
109char *strip_path_suffix(const char *path, const char *suffix); 77char *strip_path_suffix(const char *path, const char *suffix);
110 78
111extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 79extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
112extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 80extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
113/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
114extern int perf_mkstemp(char *path, size_t len, const char *template);
115 81
116extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
117 __attribute__((format (printf, 3, 4)));
118extern char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
119 __attribute__((format (printf, 3, 4)));
120extern char *perf_pathdup(const char *fmt, ...) 82extern char *perf_pathdup(const char *fmt, ...)
121 __attribute__((format (printf, 1, 2))); 83 __attribute__((format (printf, 1, 2)));
122 84
85#ifdef NO_STRLCPY
123extern size_t strlcpy(char *dest, const char *src, size_t size); 86extern size_t strlcpy(char *dest, const char *src, size_t size);
87#endif
124 88
125#endif /* __PERF_CACHE_H */ 89#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index b3b71258272a..e12d539417b2 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2009, Frederic Weisbecker <fweisbec@gmail.com> 2 * Copyright (C) 2009-2010, Frederic Weisbecker <fweisbec@gmail.com>
3 * 3 *
4 * Handle the callchains from the stream in an ad-hoc radix tree and then 4 * Handle the callchains from the stream in an ad-hoc radix tree and then
5 * sort them in an rbtree. 5 * sort them in an rbtree.
@@ -15,11 +15,22 @@
15#include <errno.h> 15#include <errno.h>
16#include <math.h> 16#include <math.h>
17 17
18#include "util.h"
18#include "callchain.h" 19#include "callchain.h"
19 20
21bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
22{
23 unsigned int chain_size = event->header.size;
24 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
25 return chain->nr * sizeof(u64) <= chain_size;
26}
27
20#define chain_for_each_child(child, parent) \ 28#define chain_for_each_child(child, parent) \
21 list_for_each_entry(child, &parent->children, brothers) 29 list_for_each_entry(child, &parent->children, brothers)
22 30
31#define chain_for_each_child_safe(child, next, parent) \
32 list_for_each_entry_safe(child, next, &parent->children, brothers)
33
23static void 34static void
24rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 35rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
25 enum chain_mode mode) 36 enum chain_mode mode)
@@ -78,10 +89,10 @@ __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
78 * sort them by hit 89 * sort them by hit
79 */ 90 */
80static void 91static void
81sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node, 92sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
82 u64 min_hit, struct callchain_param *param __used) 93 u64 min_hit, struct callchain_param *param __used)
83{ 94{
84 __sort_chain_flat(rb_root, node, min_hit); 95 __sort_chain_flat(rb_root, &root->node, min_hit);
85} 96}
86 97
87static void __sort_chain_graph_abs(struct callchain_node *node, 98static void __sort_chain_graph_abs(struct callchain_node *node,
@@ -100,11 +111,11 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
100} 111}
101 112
102static void 113static void
103sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root, 114sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
104 u64 min_hit, struct callchain_param *param __used) 115 u64 min_hit, struct callchain_param *param __used)
105{ 116{
106 __sort_chain_graph_abs(chain_root, min_hit); 117 __sort_chain_graph_abs(&chain_root->node, min_hit);
107 rb_root->rb_node = chain_root->rb_root.rb_node; 118 rb_root->rb_node = chain_root->node.rb_root.rb_node;
108} 119}
109 120
110static void __sort_chain_graph_rel(struct callchain_node *node, 121static void __sort_chain_graph_rel(struct callchain_node *node,
@@ -125,11 +136,11 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
125} 136}
126 137
127static void 138static void
128sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root, 139sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
129 u64 min_hit __used, struct callchain_param *param) 140 u64 min_hit __used, struct callchain_param *param)
130{ 141{
131 __sort_chain_graph_rel(chain_root, param->min_percent / 100.0); 142 __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
132 rb_root->rb_node = chain_root->rb_root.rb_node; 143 rb_root->rb_node = chain_root->node.rb_root.rb_node;
133} 144}
134 145
135int register_callchain_param(struct callchain_param *param) 146int register_callchain_param(struct callchain_param *param)
@@ -160,7 +171,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
160{ 171{
161 struct callchain_node *new; 172 struct callchain_node *new;
162 173
163 new = malloc(sizeof(*new)); 174 new = zalloc(sizeof(*new));
164 if (!new) { 175 if (!new) {
165 perror("not enough memory to create child for code path tree"); 176 perror("not enough memory to create child for code path tree");
166 return NULL; 177 return NULL;
@@ -183,25 +194,36 @@ create_child(struct callchain_node *parent, bool inherit_children)
183 return new; 194 return new;
184} 195}
185 196
197
198struct resolved_ip {
199 u64 ip;
200 struct map_symbol ms;
201};
202
203struct resolved_chain {
204 u64 nr;
205 struct resolved_ip ips[0];
206};
207
208
186/* 209/*
187 * Fill the node with callchain values 210 * Fill the node with callchain values
188 */ 211 */
189static void 212static void
190fill_node(struct callchain_node *node, struct ip_callchain *chain, 213fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
191 int start, struct symbol **syms)
192{ 214{
193 unsigned int i; 215 unsigned int i;
194 216
195 for (i = start; i < chain->nr; i++) { 217 for (i = start; i < chain->nr; i++) {
196 struct callchain_list *call; 218 struct callchain_list *call;
197 219
198 call = malloc(sizeof(*call)); 220 call = zalloc(sizeof(*call));
199 if (!call) { 221 if (!call) {
200 perror("not enough memory for the code path tree"); 222 perror("not enough memory for the code path tree");
201 return; 223 return;
202 } 224 }
203 call->ip = chain->ips[i]; 225 call->ip = chain->ips[i].ip;
204 call->sym = syms[i]; 226 call->ms = chain->ips[i].ms;
205 list_add_tail(&call->list, &node->val); 227 list_add_tail(&call->list, &node->val);
206 } 228 }
207 node->val_nr = chain->nr - start; 229 node->val_nr = chain->nr - start;
@@ -210,16 +232,16 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
210} 232}
211 233
212static void 234static void
213add_child(struct callchain_node *parent, struct ip_callchain *chain, 235add_child(struct callchain_node *parent, struct resolved_chain *chain,
214 int start, struct symbol **syms) 236 int start, u64 period)
215{ 237{
216 struct callchain_node *new; 238 struct callchain_node *new;
217 239
218 new = create_child(parent, false); 240 new = create_child(parent, false);
219 fill_node(new, chain, start, syms); 241 fill_node(new, chain, start);
220 242
221 new->children_hit = 0; 243 new->children_hit = 0;
222 new->hit = 1; 244 new->hit = period;
223} 245}
224 246
225/* 247/*
@@ -228,9 +250,9 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
228 * Then create another child to host the given callchain of new branch 250 * Then create another child to host the given callchain of new branch
229 */ 251 */
230static void 252static void
231split_add_child(struct callchain_node *parent, struct ip_callchain *chain, 253split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
232 struct callchain_list *to_split, int idx_parents, int idx_local, 254 struct callchain_list *to_split, int idx_parents, int idx_local,
233 struct symbol **syms) 255 u64 period)
234{ 256{
235 struct callchain_node *new; 257 struct callchain_node *new;
236 struct list_head *old_tail; 258 struct list_head *old_tail;
@@ -257,40 +279,40 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
257 /* create a new child for the new branch if any */ 279 /* create a new child for the new branch if any */
258 if (idx_total < chain->nr) { 280 if (idx_total < chain->nr) {
259 parent->hit = 0; 281 parent->hit = 0;
260 add_child(parent, chain, idx_total, syms); 282 add_child(parent, chain, idx_total, period);
261 parent->children_hit++; 283 parent->children_hit += period;
262 } else { 284 } else {
263 parent->hit = 1; 285 parent->hit = period;
264 } 286 }
265} 287}
266 288
267static int 289static int
268__append_chain(struct callchain_node *root, struct ip_callchain *chain, 290append_chain(struct callchain_node *root, struct resolved_chain *chain,
269 unsigned int start, struct symbol **syms); 291 unsigned int start, u64 period);
270 292
271static void 293static void
272__append_chain_children(struct callchain_node *root, struct ip_callchain *chain, 294append_chain_children(struct callchain_node *root, struct resolved_chain *chain,
273 struct symbol **syms, unsigned int start) 295 unsigned int start, u64 period)
274{ 296{
275 struct callchain_node *rnode; 297 struct callchain_node *rnode;
276 298
277 /* lookup in childrens */ 299 /* lookup in childrens */
278 chain_for_each_child(rnode, root) { 300 chain_for_each_child(rnode, root) {
279 unsigned int ret = __append_chain(rnode, chain, start, syms); 301 unsigned int ret = append_chain(rnode, chain, start, period);
280 302
281 if (!ret) 303 if (!ret)
282 goto inc_children_hit; 304 goto inc_children_hit;
283 } 305 }
284 /* nothing in children, add to the current node */ 306 /* nothing in children, add to the current node */
285 add_child(root, chain, start, syms); 307 add_child(root, chain, start, period);
286 308
287inc_children_hit: 309inc_children_hit:
288 root->children_hit++; 310 root->children_hit += period;
289} 311}
290 312
291static int 313static int
292__append_chain(struct callchain_node *root, struct ip_callchain *chain, 314append_chain(struct callchain_node *root, struct resolved_chain *chain,
293 unsigned int start, struct symbol **syms) 315 unsigned int start, u64 period)
294{ 316{
295 struct callchain_list *cnode; 317 struct callchain_list *cnode;
296 unsigned int i = start; 318 unsigned int i = start;
@@ -302,13 +324,19 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
302 * anywhere inside a function. 324 * anywhere inside a function.
303 */ 325 */
304 list_for_each_entry(cnode, &root->val, list) { 326 list_for_each_entry(cnode, &root->val, list) {
327 struct symbol *sym;
328
305 if (i == chain->nr) 329 if (i == chain->nr)
306 break; 330 break;
307 if (cnode->sym && syms[i]) { 331
308 if (cnode->sym->start != syms[i]->start) 332 sym = chain->ips[i].ms.sym;
333
334 if (cnode->ms.sym && sym) {
335 if (cnode->ms.sym->start != sym->start)
309 break; 336 break;
310 } else if (cnode->ip != chain->ips[i]) 337 } else if (cnode->ip != chain->ips[i].ip)
311 break; 338 break;
339
312 if (!found) 340 if (!found)
313 found = true; 341 found = true;
314 i++; 342 i++;
@@ -320,26 +348,117 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
320 348
321 /* we match only a part of the node. Split it and add the new chain */ 349 /* we match only a part of the node. Split it and add the new chain */
322 if (i - start < root->val_nr) { 350 if (i - start < root->val_nr) {
323 split_add_child(root, chain, cnode, start, i - start, syms); 351 split_add_child(root, chain, cnode, start, i - start, period);
324 return 0; 352 return 0;
325 } 353 }
326 354
327 /* we match 100% of the path, increment the hit */ 355 /* we match 100% of the path, increment the hit */
328 if (i - start == root->val_nr && i == chain->nr) { 356 if (i - start == root->val_nr && i == chain->nr) {
329 root->hit++; 357 root->hit += period;
330 return 0; 358 return 0;
331 } 359 }
332 360
333 /* We match the node and still have a part remaining */ 361 /* We match the node and still have a part remaining */
334 __append_chain_children(root, chain, syms, i); 362 append_chain_children(root, chain, i, period);
335 363
336 return 0; 364 return 0;
337} 365}
338 366
339void append_chain(struct callchain_node *root, struct ip_callchain *chain, 367static void filter_context(struct ip_callchain *old, struct resolved_chain *new,
340 struct symbol **syms) 368 struct map_symbol *syms)
341{ 369{
370 int i, j = 0;
371
372 for (i = 0; i < (int)old->nr; i++) {
373 if (old->ips[i] >= PERF_CONTEXT_MAX)
374 continue;
375
376 new->ips[j].ip = old->ips[i];
377 new->ips[j].ms = syms[i];
378 j++;
379 }
380
381 new->nr = j;
382}
383
384
385int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
386 struct map_symbol *syms, u64 period)
387{
388 struct resolved_chain *filtered;
389
342 if (!chain->nr) 390 if (!chain->nr)
343 return; 391 return 0;
344 __append_chain_children(root, chain, syms, 0); 392
393 filtered = zalloc(sizeof(*filtered) +
394 chain->nr * sizeof(struct resolved_ip));
395 if (!filtered)
396 return -ENOMEM;
397
398 filter_context(chain, filtered, syms);
399
400 if (!filtered->nr)
401 goto end;
402
403 append_chain_children(&root->node, filtered, 0, period);
404
405 if (filtered->nr > root->max_depth)
406 root->max_depth = filtered->nr;
407end:
408 free(filtered);
409
410 return 0;
411}
412
413static int
414merge_chain_branch(struct callchain_node *dst, struct callchain_node *src,
415 struct resolved_chain *chain)
416{
417 struct callchain_node *child, *next_child;
418 struct callchain_list *list, *next_list;
419 int old_pos = chain->nr;
420 int err = 0;
421
422 list_for_each_entry_safe(list, next_list, &src->val, list) {
423 chain->ips[chain->nr].ip = list->ip;
424 chain->ips[chain->nr].ms = list->ms;
425 chain->nr++;
426 list_del(&list->list);
427 free(list);
428 }
429
430 if (src->hit)
431 append_chain_children(dst, chain, 0, src->hit);
432
433 chain_for_each_child_safe(child, next_child, src) {
434 err = merge_chain_branch(dst, child, chain);
435 if (err)
436 break;
437
438 list_del(&child->brothers);
439 free(child);
440 }
441
442 chain->nr = old_pos;
443
444 return err;
445}
446
447int callchain_merge(struct callchain_root *dst, struct callchain_root *src)
448{
449 struct resolved_chain *chain;
450 int err;
451
452 chain = malloc(sizeof(*chain) +
453 src->max_depth * sizeof(struct resolved_ip));
454 if (!chain)
455 return -ENOMEM;
456
457 chain->nr = 0;
458
459 err = merge_chain_branch(&dst->node, &src->node, chain);
460
461 free(chain);
462
463 return err;
345} 464}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index ad4626de4c2b..c15fb8c24ad2 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -4,7 +4,7 @@
4#include "../perf.h" 4#include "../perf.h"
5#include <linux/list.h> 5#include <linux/list.h>
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include "util.h" 7#include "event.h"
8#include "symbol.h" 8#include "symbol.h"
9 9
10enum chain_mode { 10enum chain_mode {
@@ -26,28 +26,39 @@ struct callchain_node {
26 u64 children_hit; 26 u64 children_hit;
27}; 27};
28 28
29struct callchain_root {
30 u64 max_depth;
31 struct callchain_node node;
32};
33
29struct callchain_param; 34struct callchain_param;
30 35
31typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *, 36typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
32 u64, struct callchain_param *); 37 u64, struct callchain_param *);
33 38
34struct callchain_param { 39struct callchain_param {
35 enum chain_mode mode; 40 enum chain_mode mode;
41 u32 print_limit;
36 double min_percent; 42 double min_percent;
37 sort_chain_func_t sort; 43 sort_chain_func_t sort;
38}; 44};
39 45
40struct callchain_list { 46struct callchain_list {
41 u64 ip; 47 u64 ip;
42 struct symbol *sym; 48 struct map_symbol ms;
43 struct list_head list; 49 struct list_head list;
44}; 50};
45 51
46static inline void callchain_init(struct callchain_node *node) 52static inline void callchain_init(struct callchain_root *root)
47{ 53{
48 INIT_LIST_HEAD(&node->brothers); 54 INIT_LIST_HEAD(&root->node.brothers);
49 INIT_LIST_HEAD(&node->children); 55 INIT_LIST_HEAD(&root->node.children);
50 INIT_LIST_HEAD(&node->val); 56 INIT_LIST_HEAD(&root->node.val);
57
58 root->node.parent = NULL;
59 root->node.hit = 0;
60 root->node.children_hit = 0;
61 root->max_depth = 0;
51} 62}
52 63
53static inline u64 cumul_hits(struct callchain_node *node) 64static inline u64 cumul_hits(struct callchain_node *node)
@@ -56,6 +67,9 @@ static inline u64 cumul_hits(struct callchain_node *node)
56} 67}
57 68
58int register_callchain_param(struct callchain_param *param); 69int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 70int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
60 struct symbol **syms); 71 struct map_symbol *syms, u64 period);
72int callchain_merge(struct callchain_root *dst, struct callchain_root *src);
73
74bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
61#endif /* __PERF_CALLCHAIN_H */ 75#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e88bca55a599..e191eb9a667f 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -166,6 +166,31 @@ int perf_color_default_config(const char *var, const char *value, void *cb)
166 return perf_default_config(var, value, cb); 166 return perf_default_config(var, value, cb);
167} 167}
168 168
169static int __color_vsnprintf(char *bf, size_t size, const char *color,
170 const char *fmt, va_list args, const char *trail)
171{
172 int r = 0;
173
174 /*
175 * Auto-detect:
176 */
177 if (perf_use_color_default < 0) {
178 if (isatty(1) || pager_in_use())
179 perf_use_color_default = 1;
180 else
181 perf_use_color_default = 0;
182 }
183
184 if (perf_use_color_default && *color)
185 r += snprintf(bf, size, "%s", color);
186 r += vsnprintf(bf + r, size - r, fmt, args);
187 if (perf_use_color_default && *color)
188 r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
189 if (trail)
190 r += snprintf(bf + r, size - r, "%s", trail);
191 return r;
192}
193
169static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, 194static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
170 va_list args, const char *trail) 195 va_list args, const char *trail)
171{ 196{
@@ -191,11 +216,28 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
191 return r; 216 return r;
192} 217}
193 218
219int color_vsnprintf(char *bf, size_t size, const char *color,
220 const char *fmt, va_list args)
221{
222 return __color_vsnprintf(bf, size, color, fmt, args, NULL);
223}
224
194int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) 225int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
195{ 226{
196 return __color_vfprintf(fp, color, fmt, args, NULL); 227 return __color_vfprintf(fp, color, fmt, args, NULL);
197} 228}
198 229
230int color_snprintf(char *bf, size_t size, const char *color,
231 const char *fmt, ...)
232{
233 va_list args;
234 int r;
235
236 va_start(args, fmt);
237 r = color_vsnprintf(bf, size, color, fmt, args);
238 va_end(args);
239 return r;
240}
199 241
200int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) 242int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
201{ 243{
@@ -274,3 +316,9 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
274 316
275 return r; 317 return r;
276} 318}
319
320int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent)
321{
322 const char *color = get_percent_color(percent);
323 return color_snprintf(bf, size, color, fmt, percent);
324}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 24e8809210bb..dea082b79602 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -32,10 +32,14 @@ int perf_color_default_config(const char *var, const char *value, void *cb);
32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); 32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
33void color_parse(const char *value, const char *var, char *dst); 33void color_parse(const char *value, const char *var, char *dst);
34void color_parse_mem(const char *value, int len, const char *var, char *dst); 34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_vsnprintf(char *bf, size_t size, const char *color,
36 const char *fmt, va_list args);
35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); 37int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
36int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 38int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
37int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
38int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
42int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent);
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 43int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent); 44const char *get_percent_color(double percent);
41 45
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 8784649109ce..e02d78cae70f 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -11,12 +11,17 @@
11 11
12#define MAXNAME (256) 12#define MAXNAME (256)
13 13
14#define DEBUG_CACHE_DIR ".debug"
15
16
17char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
18
14static FILE *config_file; 19static FILE *config_file;
15static const char *config_file_name; 20static const char *config_file_name;
16static int config_linenr; 21static int config_linenr;
17static int config_file_eof; 22static int config_file_eof;
18 23
19const char *config_exclusive_filename = NULL; 24static const char *config_exclusive_filename;
20 25
21static int get_next_char(void) 26static int get_next_char(void)
22{ 27{
@@ -127,7 +132,7 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
127 break; 132 break;
128 if (!iskeychar(c)) 133 if (!iskeychar(c))
129 break; 134 break;
130 name[len++] = tolower(c); 135 name[len++] = c;
131 if (len >= MAXNAME) 136 if (len >= MAXNAME)
132 return -1; 137 return -1;
133 } 138 }
@@ -291,19 +296,6 @@ static int perf_parse_long(const char *value, long *ret)
291 return 0; 296 return 0;
292} 297}
293 298
294int perf_parse_ulong(const char *value, unsigned long *ret)
295{
296 if (value && *value) {
297 char *end;
298 unsigned long val = strtoul(value, &end, 0);
299 if (!parse_unit_factor(end, &val))
300 return 0;
301 *ret = val;
302 return 1;
303 }
304 return 0;
305}
306
307static void die_bad_config(const char *name) 299static void die_bad_config(const char *name)
308{ 300{
309 if (config_file_name) 301 if (config_file_name)
@@ -319,15 +311,7 @@ int perf_config_int(const char *name, const char *value)
319 return ret; 311 return ret;
320} 312}
321 313
322unsigned long perf_config_ulong(const char *name, const char *value) 314static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
323{
324 unsigned long ret;
325 if (!perf_parse_ulong(value, &ret))
326 die_bad_config(name);
327 return ret;
328}
329
330int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
331{ 315{
332 *is_bool = 1; 316 *is_bool = 1;
333 if (!value) 317 if (!value)
@@ -348,12 +332,11 @@ int perf_config_bool(const char *name, const char *value)
348 return !!perf_config_bool_or_int(name, value, &discard); 332 return !!perf_config_bool_or_int(name, value, &discard);
349} 333}
350 334
351int perf_config_string(const char **dest, const char *var, const char *value) 335const char *perf_config_dirname(const char *name, const char *value)
352{ 336{
353 if (!value) 337 if (!name)
354 return config_error_nonbool(var); 338 return NULL;
355 *dest = strdup(value); 339 return value;
356 return 0;
357} 340}
358 341
359static int perf_default_core_config(const char *var __used, const char *value __used) 342static int perf_default_core_config(const char *var __used, const char *value __used)
@@ -371,7 +354,7 @@ int perf_default_config(const char *var, const char *value, void *dummy __used)
371 return 0; 354 return 0;
372} 355}
373 356
374int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 357static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
375{ 358{
376 int ret; 359 int ret;
377 FILE *f = fopen(filename, "r"); 360 FILE *f = fopen(filename, "r");
@@ -389,7 +372,7 @@ int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
389 return ret; 372 return ret;
390} 373}
391 374
392const char *perf_etc_perfconfig(void) 375static const char *perf_etc_perfconfig(void)
393{ 376{
394 static const char *system_wide; 377 static const char *system_wide;
395 if (!system_wide) 378 if (!system_wide)
@@ -403,12 +386,12 @@ static int perf_env_bool(const char *k, int def)
403 return v ? perf_config_bool(k, v) : def; 386 return v ? perf_config_bool(k, v) : def;
404} 387}
405 388
406int perf_config_system(void) 389static int perf_config_system(void)
407{ 390{
408 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 391 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
409} 392}
410 393
411int perf_config_global(void) 394static int perf_config_global(void)
412{ 395{
413 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 396 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
414} 397}
@@ -450,430 +433,60 @@ int perf_config(config_fn_t fn, void *data)
450} 433}
451 434
452/* 435/*
453 * Find all the stuff for perf_config_set() below. 436 * Call this to report error for your variable that should not
437 * get a boolean value (i.e. "[my] var" means "true").
454 */ 438 */
455 439int config_error_nonbool(const char *var)
456#define MAX_MATCHES 512
457
458static struct {
459 int baselen;
460 char* key;
461 int do_not_match;
462 regex_t* value_regex;
463 int multi_replace;
464 size_t offset[MAX_MATCHES];
465 enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
466 int seen;
467} store;
468
469static int matches(const char* key, const char* value)
470{
471 return !strcmp(key, store.key) &&
472 (store.value_regex == NULL ||
473 (store.do_not_match ^
474 !regexec(store.value_regex, value, 0, NULL, 0)));
475}
476
477static int store_aux(const char* key, const char* value, void *cb __used)
478{ 440{
479 int section_len; 441 return error("Missing value for '%s'", var);
480 const char *ep;
481
482 switch (store.state) {
483 case KEY_SEEN:
484 if (matches(key, value)) {
485 if (store.seen == 1 && store.multi_replace == 0) {
486 warning("%s has multiple values", key);
487 } else if (store.seen >= MAX_MATCHES) {
488 error("too many matches for %s", key);
489 return 1;
490 }
491
492 store.offset[store.seen] = ftell(config_file);
493 store.seen++;
494 }
495 break;
496 case SECTION_SEEN:
497 /*
498 * What we are looking for is in store.key (both
499 * section and var), and its section part is baselen
500 * long. We found key (again, both section and var).
501 * We would want to know if this key is in the same
502 * section as what we are looking for. We already
503 * know we are in the same section as what should
504 * hold store.key.
505 */
506 ep = strrchr(key, '.');
507 section_len = ep - key;
508
509 if ((section_len != store.baselen) ||
510 memcmp(key, store.key, section_len+1)) {
511 store.state = SECTION_END_SEEN;
512 break;
513 }
514
515 /*
516 * Do not increment matches: this is no match, but we
517 * just made sure we are in the desired section.
518 */
519 store.offset[store.seen] = ftell(config_file);
520 /* fallthru */
521 case SECTION_END_SEEN:
522 case START:
523 if (matches(key, value)) {
524 store.offset[store.seen] = ftell(config_file);
525 store.state = KEY_SEEN;
526 store.seen++;
527 } else {
528 if (strrchr(key, '.') - key == store.baselen &&
529 !strncmp(key, store.key, store.baselen)) {
530 store.state = SECTION_SEEN;
531 store.offset[store.seen] = ftell(config_file);
532 }
533 }
534 default:
535 break;
536 }
537 return 0;
538} 442}
539 443
540static int store_write_section(int fd, const char* key) 444struct buildid_dir_config {
541{ 445 char *dir;
542 const char *dot; 446};
543 int i, success;
544 struct strbuf sb = STRBUF_INIT;
545
546 dot = memchr(key, '.', store.baselen);
547 if (dot) {
548 strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
549 for (i = dot - key + 1; i < store.baselen; i++) {
550 if (key[i] == '"' || key[i] == '\\')
551 strbuf_addch(&sb, '\\');
552 strbuf_addch(&sb, key[i]);
553 }
554 strbuf_addstr(&sb, "\"]\n");
555 } else {
556 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
557 }
558
559 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
560 strbuf_release(&sb);
561 447
562 return success; 448static int buildid_dir_command_config(const char *var, const char *value,
563} 449 void *data)
564
565static int store_write_pair(int fd, const char* key, const char* value)
566{ 450{
567 int i, success; 451 struct buildid_dir_config *c = data;
568 int length = strlen(key + store.baselen + 1); 452 const char *v;
569 const char *quote = "";
570 struct strbuf sb = STRBUF_INIT;
571
572 /*
573 * Check to see if the value needs to be surrounded with a dq pair.
574 * Note that problematic characters are always backslash-quoted; this
575 * check is about not losing leading or trailing SP and strings that
576 * follow beginning-of-comment characters (i.e. ';' and '#') by the
577 * configuration parser.
578 */
579 if (value[0] == ' ')
580 quote = "\"";
581 for (i = 0; value[i]; i++)
582 if (value[i] == ';' || value[i] == '#')
583 quote = "\"";
584 if (i && value[i - 1] == ' ')
585 quote = "\"";
586
587 strbuf_addf(&sb, "\t%.*s = %s",
588 length, key + store.baselen + 1, quote);
589
590 for (i = 0; value[i]; i++)
591 switch (value[i]) {
592 case '\n':
593 strbuf_addstr(&sb, "\\n");
594 break;
595 case '\t':
596 strbuf_addstr(&sb, "\\t");
597 break;
598 case '"':
599 case '\\':
600 strbuf_addch(&sb, '\\');
601 default:
602 strbuf_addch(&sb, value[i]);
603 break;
604 }
605 strbuf_addf(&sb, "%s\n", quote);
606
607 success = (write_in_full(fd, sb.buf, sb.len) == (ssize_t)sb.len);
608 strbuf_release(&sb);
609
610 return success;
611}
612 453
613static ssize_t find_beginning_of_line(const char* contents, size_t size, 454 /* same dir for all commands */
614 size_t offset_, int* found_bracket) 455 if (!prefixcmp(var, "buildid.") && !strcmp(var + 8, "dir")) {
615{ 456 v = perf_config_dirname(var, value);
616 size_t equal_offset = size, bracket_offset = size; 457 if (!v)
617 ssize_t offset; 458 return -1;
618 459 strncpy(c->dir, v, MAXPATHLEN-1);
619contline: 460 c->dir[MAXPATHLEN-1] = '\0';
620 for (offset = offset_-2; offset > 0
621 && contents[offset] != '\n'; offset--)
622 switch (contents[offset]) {
623 case '=': equal_offset = offset; break;
624 case ']': bracket_offset = offset; break;
625 default: break;
626 }
627 if (offset > 0 && contents[offset-1] == '\\') {
628 offset_ = offset;
629 goto contline;
630 } 461 }
631 if (bracket_offset < equal_offset) { 462 return 0;
632 *found_bracket = 1;
633 offset = bracket_offset+1;
634 } else
635 offset++;
636
637 return offset;
638} 463}
639 464
640int perf_config_set(const char* key, const char* value) 465static void check_buildid_dir_config(void)
641{ 466{
642 return perf_config_set_multivar(key, value, NULL, 0); 467 struct buildid_dir_config c;
468 c.dir = buildid_dir;
469 perf_config(buildid_dir_command_config, &c);
643} 470}
644 471
645/* 472void set_buildid_dir(void)
646 * If value==NULL, unset in (remove from) config,
647 * if value_regex!=NULL, disregard key/value pairs where value does not match.
648 * if multi_replace==0, nothing, or only one matching key/value is replaced,
649 * else all matching key/values (regardless how many) are removed,
650 * before the new pair is written.
651 *
652 * Returns 0 on success.
653 *
654 * This function does this:
655 *
656 * - it locks the config file by creating ".perf/config.lock"
657 *
658 * - it then parses the config using store_aux() as validator to find
659 * the position on the key/value pair to replace. If it is to be unset,
660 * it must be found exactly once.
661 *
662 * - the config file is mmap()ed and the part before the match (if any) is
663 * written to the lock file, then the changed part and the rest.
664 *
665 * - the config file is removed and the lock file rename()d to it.
666 *
667 */
668int perf_config_set_multivar(const char* key, const char* value,
669 const char* value_regex, int multi_replace)
670{ 473{
671 int i, dot; 474 buildid_dir[0] = '\0';
672 int fd = -1, in_fd;
673 int ret = 0;
674 char* config_filename;
675 const char* last_dot = strrchr(key, '.');
676
677 if (config_exclusive_filename)
678 config_filename = strdup(config_exclusive_filename);
679 else
680 config_filename = perf_pathdup("config");
681
682 /*
683 * Since "key" actually contains the section name and the real
684 * key name separated by a dot, we have to know where the dot is.
685 */
686
687 if (last_dot == NULL) {
688 error("key does not contain a section: %s", key);
689 ret = 2;
690 goto out_free;
691 }
692 store.baselen = last_dot - key;
693
694 store.multi_replace = multi_replace;
695
696 /*
697 * Validate the key and while at it, lower case it for matching.
698 */
699 store.key = malloc(strlen(key) + 1);
700 dot = 0;
701 for (i = 0; key[i]; i++) {
702 unsigned char c = key[i];
703 if (c == '.')
704 dot = 1;
705 /* Leave the extended basename untouched.. */
706 if (!dot || i > store.baselen) {
707 if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
708 error("invalid key: %s", key);
709 free(store.key);
710 ret = 1;
711 goto out_free;
712 }
713 c = tolower(c);
714 } else if (c == '\n') {
715 error("invalid key (newline): %s", key);
716 free(store.key);
717 ret = 1;
718 goto out_free;
719 }
720 store.key[i] = c;
721 }
722 store.key[i] = 0;
723
724 /*
725 * If .perf/config does not exist yet, write a minimal version.
726 */
727 in_fd = open(config_filename, O_RDONLY);
728 if ( in_fd < 0 ) {
729 free(store.key);
730
731 if ( ENOENT != errno ) {
732 error("opening %s: %s", config_filename,
733 strerror(errno));
734 ret = 3; /* same as "invalid config file" */
735 goto out_free;
736 }
737 /* if nothing to unset, error out */
738 if (value == NULL) {
739 ret = 5;
740 goto out_free;
741 }
742
743 store.key = (char*)key;
744 if (!store_write_section(fd, key) ||
745 !store_write_pair(fd, key, value))
746 goto write_err_out;
747 } else {
748 struct stat st;
749 char *contents;
750 ssize_t contents_sz, copy_begin, copy_end;
751 int new_line = 0;
752
753 if (value_regex == NULL)
754 store.value_regex = NULL;
755 else {
756 if (value_regex[0] == '!') {
757 store.do_not_match = 1;
758 value_regex++;
759 } else
760 store.do_not_match = 0;
761
762 store.value_regex = (regex_t*)malloc(sizeof(regex_t));
763 if (regcomp(store.value_regex, value_regex,
764 REG_EXTENDED)) {
765 error("invalid pattern: %s", value_regex);
766 free(store.value_regex);
767 ret = 6;
768 goto out_free;
769 }
770 }
771
772 store.offset[0] = 0;
773 store.state = START;
774 store.seen = 0;
775
776 /*
777 * After this, store.offset will contain the *end* offset
778 * of the last match, or remain at 0 if no match was found.
779 * As a side effect, we make sure to transform only a valid
780 * existing config file.
781 */
782 if (perf_config_from_file(store_aux, config_filename, NULL)) {
783 error("invalid config file %s", config_filename);
784 free(store.key);
785 if (store.value_regex != NULL) {
786 regfree(store.value_regex);
787 free(store.value_regex);
788 }
789 ret = 3;
790 goto out_free;
791 }
792 475
793 free(store.key); 476 /* try config file */
794 if (store.value_regex != NULL) { 477 check_buildid_dir_config();
795 regfree(store.value_regex);
796 free(store.value_regex);
797 }
798 478
799 /* if nothing to unset, or too many matches, error out */ 479 /* default to $HOME/.debug */
800 if ((store.seen == 0 && value == NULL) || 480 if (buildid_dir[0] == '\0') {
801 (store.seen > 1 && multi_replace == 0)) { 481 char *v = getenv("HOME");
802 ret = 5; 482 if (v) {
803 goto out_free; 483 snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
804 } 484 v, DEBUG_CACHE_DIR);
805 485 } else {
806 fstat(in_fd, &st); 486 strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
807 contents_sz = xsize_t(st.st_size);
808 contents = mmap(NULL, contents_sz, PROT_READ,
809 MAP_PRIVATE, in_fd, 0);
810 close(in_fd);
811
812 if (store.seen == 0)
813 store.seen = 1;
814
815 for (i = 0, copy_begin = 0; i < store.seen; i++) {
816 if (store.offset[i] == 0) {
817 store.offset[i] = copy_end = contents_sz;
818 } else if (store.state != KEY_SEEN) {
819 copy_end = store.offset[i];
820 } else
821 copy_end = find_beginning_of_line(
822 contents, contents_sz,
823 store.offset[i]-2, &new_line);
824
825 if (copy_end > 0 && contents[copy_end-1] != '\n')
826 new_line = 1;
827
828 /* write the first part of the config */
829 if (copy_end > copy_begin) {
830 if (write_in_full(fd, contents + copy_begin,
831 copy_end - copy_begin) <
832 copy_end - copy_begin)
833 goto write_err_out;
834 if (new_line &&
835 write_in_full(fd, "\n", 1) != 1)
836 goto write_err_out;
837 }
838 copy_begin = store.offset[i];
839 }
840
841 /* write the pair (value == NULL means unset) */
842 if (value != NULL) {
843 if (store.state == START) {
844 if (!store_write_section(fd, key))
845 goto write_err_out;
846 }
847 if (!store_write_pair(fd, key, value))
848 goto write_err_out;
849 } 487 }
850 488 buildid_dir[MAXPATHLEN-1] = '\0';
851 /* write the rest of the config */
852 if (copy_begin < contents_sz)
853 if (write_in_full(fd, contents + copy_begin,
854 contents_sz - copy_begin) <
855 contents_sz - copy_begin)
856 goto write_err_out;
857
858 munmap(contents, contents_sz);
859 } 489 }
860 490 /* for communicating with external commands */
861 ret = 0; 491 setenv("PERF_BUILDID_DIR", buildid_dir, 1);
862
863out_free:
864 free(config_filename);
865 return ret;
866
867write_err_out:
868 goto out_free;
869
870}
871
872/*
873 * Call this to report error for your variable that should not
874 * get a boolean value (i.e. "[my] var" means "true").
875 */
876int config_error_nonbool(const char *var)
877{
878 return error("Missing value for '%s'", var);
879} 492}
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
new file mode 100644
index 000000000000..3ccaa1043383
--- /dev/null
+++ b/tools/perf/util/cpumap.c
@@ -0,0 +1,179 @@
1#include "util.h"
2#include "../perf.h"
3#include "cpumap.h"
4#include <assert.h>
5#include <stdio.h>
6
7static struct cpu_map *cpu_map__default_new(void)
8{
9 struct cpu_map *cpus;
10 int nr_cpus;
11
12 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
13 if (nr_cpus < 0)
14 return NULL;
15
16 cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int));
17 if (cpus != NULL) {
18 int i;
19 for (i = 0; i < nr_cpus; ++i)
20 cpus->map[i] = i;
21
22 cpus->nr = nr_cpus;
23 }
24
25 return cpus;
26}
27
28static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
29{
30 size_t payload_size = nr_cpus * sizeof(int);
31 struct cpu_map *cpus = malloc(sizeof(*cpus) + payload_size);
32
33 if (cpus != NULL) {
34 cpus->nr = nr_cpus;
35 memcpy(cpus->map, tmp_cpus, payload_size);
36 }
37
38 return cpus;
39}
40
41static struct cpu_map *cpu_map__read_all_cpu_map(void)
42{
43 struct cpu_map *cpus = NULL;
44 FILE *onlnf;
45 int nr_cpus = 0;
46 int *tmp_cpus = NULL, *tmp;
47 int max_entries = 0;
48 int n, cpu, prev;
49 char sep;
50
51 onlnf = fopen("/sys/devices/system/cpu/online", "r");
52 if (!onlnf)
53 return cpu_map__default_new();
54
55 sep = 0;
56 prev = -1;
57 for (;;) {
58 n = fscanf(onlnf, "%u%c", &cpu, &sep);
59 if (n <= 0)
60 break;
61 if (prev >= 0) {
62 int new_max = nr_cpus + cpu - prev - 1;
63
64 if (new_max >= max_entries) {
65 max_entries = new_max + MAX_NR_CPUS / 2;
66 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
67 if (tmp == NULL)
68 goto out_free_tmp;
69 tmp_cpus = tmp;
70 }
71
72 while (++prev < cpu)
73 tmp_cpus[nr_cpus++] = prev;
74 }
75 if (nr_cpus == max_entries) {
76 max_entries += MAX_NR_CPUS;
77 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
78 if (tmp == NULL)
79 goto out_free_tmp;
80 tmp_cpus = tmp;
81 }
82
83 tmp_cpus[nr_cpus++] = cpu;
84 if (n == 2 && sep == '-')
85 prev = cpu;
86 else
87 prev = -1;
88 if (n == 1 || sep == '\n')
89 break;
90 }
91
92 if (nr_cpus > 0)
93 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
94 else
95 cpus = cpu_map__default_new();
96out_free_tmp:
97 free(tmp_cpus);
98 fclose(onlnf);
99 return cpus;
100}
101
102struct cpu_map *cpu_map__new(const char *cpu_list)
103{
104 struct cpu_map *cpus = NULL;
105 unsigned long start_cpu, end_cpu = 0;
106 char *p = NULL;
107 int i, nr_cpus = 0;
108 int *tmp_cpus = NULL, *tmp;
109 int max_entries = 0;
110
111 if (!cpu_list)
112 return cpu_map__read_all_cpu_map();
113
114 if (!isdigit(*cpu_list))
115 goto out;
116
117 while (isdigit(*cpu_list)) {
118 p = NULL;
119 start_cpu = strtoul(cpu_list, &p, 0);
120 if (start_cpu >= INT_MAX
121 || (*p != '\0' && *p != ',' && *p != '-'))
122 goto invalid;
123
124 if (*p == '-') {
125 cpu_list = ++p;
126 p = NULL;
127 end_cpu = strtoul(cpu_list, &p, 0);
128
129 if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
130 goto invalid;
131
132 if (end_cpu < start_cpu)
133 goto invalid;
134 } else {
135 end_cpu = start_cpu;
136 }
137
138 for (; start_cpu <= end_cpu; start_cpu++) {
139 /* check for duplicates */
140 for (i = 0; i < nr_cpus; i++)
141 if (tmp_cpus[i] == (int)start_cpu)
142 goto invalid;
143
144 if (nr_cpus == max_entries) {
145 max_entries += MAX_NR_CPUS;
146 tmp = realloc(tmp_cpus, max_entries * sizeof(int));
147 if (tmp == NULL)
148 goto invalid;
149 tmp_cpus = tmp;
150 }
151 tmp_cpus[nr_cpus++] = (int)start_cpu;
152 }
153 if (*p)
154 ++p;
155
156 cpu_list = p;
157 }
158
159 if (nr_cpus > 0)
160 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
161 else
162 cpus = cpu_map__default_new();
163invalid:
164 free(tmp_cpus);
165out:
166 return cpus;
167}
168
169struct cpu_map *cpu_map__dummy_new(void)
170{
171 struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
172
173 if (cpus != NULL) {
174 cpus->nr = 1;
175 cpus->map[0] = -1;
176 }
177
178 return cpus;
179}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
new file mode 100644
index 000000000000..f7a4f42f6307
--- /dev/null
+++ b/tools/perf/util/cpumap.h
@@ -0,0 +1,13 @@
1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H
3
4struct cpu_map {
5 int nr;
6 int map[];
7};
8
9struct cpu_map *cpu_map__new(const char *cpu_list);
10struct cpu_map *cpu_map__dummy_new(void);
11void *cpu_map__delete(struct cpu_map *map);
12
13#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
deleted file mode 100644
index b557b836de3d..000000000000
--- a/tools/perf/util/data_map.c
+++ /dev/null
@@ -1,252 +0,0 @@
1#include "symbol.h"
2#include "util.h"
3#include "debug.h"
4#include "thread.h"
5#include "session.h"
6
7static int process_event_stub(event_t *event __used,
8 struct perf_session *session __used)
9{
10 dump_printf(": unhandled!\n");
11 return 0;
12}
13
14static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
15{
16 if (!handler->process_sample_event)
17 handler->process_sample_event = process_event_stub;
18 if (!handler->process_mmap_event)
19 handler->process_mmap_event = process_event_stub;
20 if (!handler->process_comm_event)
21 handler->process_comm_event = process_event_stub;
22 if (!handler->process_fork_event)
23 handler->process_fork_event = process_event_stub;
24 if (!handler->process_exit_event)
25 handler->process_exit_event = process_event_stub;
26 if (!handler->process_lost_event)
27 handler->process_lost_event = process_event_stub;
28 if (!handler->process_read_event)
29 handler->process_read_event = process_event_stub;
30 if (!handler->process_throttle_event)
31 handler->process_throttle_event = process_event_stub;
32 if (!handler->process_unthrottle_event)
33 handler->process_unthrottle_event = process_event_stub;
34}
35
36static const char *event__name[] = {
37 [0] = "TOTAL",
38 [PERF_RECORD_MMAP] = "MMAP",
39 [PERF_RECORD_LOST] = "LOST",
40 [PERF_RECORD_COMM] = "COMM",
41 [PERF_RECORD_EXIT] = "EXIT",
42 [PERF_RECORD_THROTTLE] = "THROTTLE",
43 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
44 [PERF_RECORD_FORK] = "FORK",
45 [PERF_RECORD_READ] = "READ",
46 [PERF_RECORD_SAMPLE] = "SAMPLE",
47};
48
49unsigned long event__total[PERF_RECORD_MAX];
50
51void event__print_totals(void)
52{
53 int i;
54 for (i = 0; i < PERF_RECORD_MAX; ++i)
55 pr_info("%10s events: %10ld\n",
56 event__name[i], event__total[i]);
57}
58
59static int process_event(event_t *event, struct perf_session *session,
60 struct perf_event_ops *ops,
61 unsigned long offset, unsigned long head)
62{
63 trace_event(event);
64
65 if (event->header.type < PERF_RECORD_MAX) {
66 dump_printf("%p [%p]: PERF_RECORD_%s",
67 (void *)(offset + head),
68 (void *)(long)(event->header.size),
69 event__name[event->header.type]);
70 ++event__total[0];
71 ++event__total[event->header.type];
72 }
73
74 switch (event->header.type) {
75 case PERF_RECORD_SAMPLE:
76 return ops->process_sample_event(event, session);
77 case PERF_RECORD_MMAP:
78 return ops->process_mmap_event(event, session);
79 case PERF_RECORD_COMM:
80 return ops->process_comm_event(event, session);
81 case PERF_RECORD_FORK:
82 return ops->process_fork_event(event, session);
83 case PERF_RECORD_EXIT:
84 return ops->process_exit_event(event, session);
85 case PERF_RECORD_LOST:
86 return ops->process_lost_event(event, session);
87 case PERF_RECORD_READ:
88 return ops->process_read_event(event, session);
89 case PERF_RECORD_THROTTLE:
90 return ops->process_throttle_event(event, session);
91 case PERF_RECORD_UNTHROTTLE:
92 return ops->process_unthrottle_event(event, session);
93 default:
94 ops->total_unknown++;
95 return -1;
96 }
97}
98
99int perf_header__read_build_ids(int input, u64 offset, u64 size)
100{
101 struct build_id_event bev;
102 char filename[PATH_MAX];
103 u64 limit = offset + size;
104 int err = -1;
105
106 while (offset < limit) {
107 struct dso *dso;
108 ssize_t len;
109
110 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
111 goto out;
112
113 len = bev.header.size - sizeof(bev);
114 if (read(input, filename, len) != len)
115 goto out;
116
117 dso = dsos__findnew(filename);
118 if (dso != NULL)
119 dso__set_build_id(dso, &bev.build_id);
120
121 offset += bev.header.size;
122 }
123 err = 0;
124out:
125 return err;
126}
127
128static struct thread *perf_session__register_idle_thread(struct perf_session *self)
129{
130 struct thread *thread = perf_session__findnew(self, 0);
131
132 if (!thread || thread__set_comm(thread, "swapper")) {
133 pr_err("problem inserting idle task.\n");
134 thread = NULL;
135 }
136
137 return thread;
138}
139
140int perf_session__process_events(struct perf_session *self,
141 struct perf_event_ops *ops)
142{
143 int err;
144 unsigned long head, shift;
145 unsigned long offset = 0;
146 size_t page_size;
147 event_t *event;
148 uint32_t size;
149 char *buf;
150
151 if (perf_session__register_idle_thread(self) == NULL)
152 return -ENOMEM;
153
154 perf_event_ops__fill_defaults(ops);
155
156 page_size = getpagesize();
157
158 head = self->header.data_offset;
159 self->sample_type = perf_header__sample_type(&self->header);
160
161 err = -EINVAL;
162 if (ops->sample_type_check && ops->sample_type_check(self) < 0)
163 goto out_err;
164
165 if (!ops->full_paths) {
166 char bf[PATH_MAX];
167
168 if (getcwd(bf, sizeof(bf)) == NULL) {
169 err = -errno;
170out_getcwd_err:
171 pr_err("failed to get the current directory\n");
172 goto out_err;
173 }
174 self->cwd = strdup(bf);
175 if (self->cwd == NULL) {
176 err = -ENOMEM;
177 goto out_getcwd_err;
178 }
179 self->cwdlen = strlen(self->cwd);
180 }
181
182 shift = page_size * (head / page_size);
183 offset += shift;
184 head -= shift;
185
186remap:
187 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ,
188 MAP_SHARED, self->fd, offset);
189 if (buf == MAP_FAILED) {
190 pr_err("failed to mmap file\n");
191 err = -errno;
192 goto out_err;
193 }
194
195more:
196 event = (event_t *)(buf + head);
197
198 size = event->header.size;
199 if (!size)
200 size = 8;
201
202 if (head + event->header.size >= page_size * self->mmap_window) {
203 int munmap_ret;
204
205 shift = page_size * (head / page_size);
206
207 munmap_ret = munmap(buf, page_size * self->mmap_window);
208 assert(munmap_ret == 0);
209
210 offset += shift;
211 head -= shift;
212 goto remap;
213 }
214
215 size = event->header.size;
216
217 dump_printf("\n%p [%p]: event: %d\n",
218 (void *)(offset + head),
219 (void *)(long)event->header.size,
220 event->header.type);
221
222 if (!size || process_event(event, self, ops, offset, head) < 0) {
223
224 dump_printf("%p [%p]: skipping unknown header type: %d\n",
225 (void *)(offset + head),
226 (void *)(long)(event->header.size),
227 event->header.type);
228
229 /*
230 * assume we lost track of the stream, check alignment, and
231 * increment a single u64 in the hope to catch on again 'soon'.
232 */
233
234 if (unlikely(head & 7))
235 head &= ~7ULL;
236
237 size = 8;
238 }
239
240 head += size;
241
242 if (offset + head >= self->header.data_offset + self->header.data_size)
243 goto done;
244
245 if (offset + head < self->size)
246 goto more;
247
248done:
249 err = 0;
250out_err:
251 return err;
252}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 28d520d5a1fb..01bbe8ecec3f 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -6,12 +6,14 @@
6#include <stdarg.h> 6#include <stdarg.h>
7#include <stdio.h> 7#include <stdio.h>
8 8
9#include "cache.h"
9#include "color.h" 10#include "color.h"
10#include "event.h" 11#include "event.h"
11#include "debug.h" 12#include "debug.h"
13#include "util.h"
12 14
13int verbose = 0; 15int verbose;
14int dump_trace = 0; 16bool dump_trace = false, quiet = false;
15 17
16int eprintf(int level, const char *fmt, ...) 18int eprintf(int level, const char *fmt, ...)
17{ 19{
@@ -20,7 +22,10 @@ int eprintf(int level, const char *fmt, ...)
20 22
21 if (verbose >= level) { 23 if (verbose >= level) {
22 va_start(args, fmt); 24 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args); 25 if (use_browser > 0)
26 ret = ui_helpline__show_help(fmt, args);
27 else
28 ret = vfprintf(stderr, fmt, args);
24 va_end(args); 29 va_end(args);
25 } 30 }
26 31
@@ -41,20 +46,16 @@ int dump_printf(const char *fmt, ...)
41 return ret; 46 return ret;
42} 47}
43 48
44static int dump_printf_color(const char *fmt, const char *color, ...) 49#ifdef NO_NEWT_SUPPORT
50void ui__warning(const char *format, ...)
45{ 51{
46 va_list args; 52 va_list args;
47 int ret = 0;
48 53
49 if (dump_trace) { 54 va_start(args, format);
50 va_start(args, color); 55 vfprintf(stderr, format, args);
51 ret = color_vfprintf(stdout, color, fmt, args); 56 va_end(args);
52 va_end(args);
53 }
54
55 return ret;
56} 57}
57 58#endif
58 59
59void trace_event(event_t *event) 60void trace_event(event_t *event)
60{ 61{
@@ -65,31 +66,29 @@ void trace_event(event_t *event)
65 if (!dump_trace) 66 if (!dump_trace)
66 return; 67 return;
67 68
68 dump_printf("."); 69 printf(".");
69 dump_printf_color("\n. ... raw event: size %d bytes\n", color, 70 color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n",
70 event->header.size); 71 event->header.size);
71 72
72 for (i = 0; i < event->header.size; i++) { 73 for (i = 0; i < event->header.size; i++) {
73 if ((i & 15) == 0) { 74 if ((i & 15) == 0) {
74 dump_printf("."); 75 printf(".");
75 dump_printf_color(" %04x: ", color, i); 76 color_fprintf(stdout, color, " %04x: ", i);
76 } 77 }
77 78
78 dump_printf_color(" %02x", color, raw_event[i]); 79 color_fprintf(stdout, color, " %02x", raw_event[i]);
79 80
80 if (((i & 15) == 15) || i == event->header.size-1) { 81 if (((i & 15) == 15) || i == event->header.size-1) {
81 dump_printf_color(" ", color); 82 color_fprintf(stdout, color, " ");
82 for (j = 0; j < 15-(i & 15); j++) 83 for (j = 0; j < 15-(i & 15); j++)
83 dump_printf_color(" ", color); 84 color_fprintf(stdout, color, " ");
84 for (j = 0; j < (i & 15); j++) { 85 for (j = i & ~15; j <= i; j++) {
85 if (isprint(raw_event[i-15+j])) 86 color_fprintf(stdout, color, "%c",
86 dump_printf_color("%c", color, 87 isprint(raw_event[j]) ?
87 raw_event[i-15+j]); 88 raw_event[j] : '.');
88 else
89 dump_printf_color(".", color);
90 } 89 }
91 dump_printf_color("\n", color); 90 color_fprintf(stdout, color, "\n");
92 } 91 }
93 } 92 }
94 dump_printf(".\n"); 93 printf(".\n");
95} 94}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index c6c24c522dea..ca35fd66b5df 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -2,14 +2,39 @@
2#ifndef __PERF_DEBUG_H 2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H 3#define __PERF_DEBUG_H
4 4
5#include <stdbool.h>
5#include "event.h" 6#include "event.h"
6 7
7extern int verbose; 8extern int verbose;
8extern int dump_trace; 9extern bool quiet, dump_trace;
9 10
10int eprintf(int level,
11 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 11int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(event_t *event); 12void trace_event(event_t *event);
14 13
14struct ui_progress;
15
16#ifdef NO_NEWT_SUPPORT
17static inline int ui_helpline__show_help(const char *format __used, va_list ap __used)
18{
19 return 0;
20}
21
22static inline struct ui_progress *ui_progress__new(const char *title __used,
23 u64 total __used)
24{
25 return (struct ui_progress *)1;
26}
27
28static inline void ui_progress__update(struct ui_progress *self __used,
29 u64 curr __used) {}
30
31static inline void ui_progress__delete(struct ui_progress *self __used) {}
32#else
33extern char ui_helpline__last_msg[];
34int ui_helpline__show_help(const char *format, va_list ap);
35#include "ui/progress.h"
36#endif
37
38void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
39
15#endif /* __PERF_DEBUG_H */ 40#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
index 06b73ee02c49..a88fefc0cc0a 100644
--- a/tools/perf/util/debugfs.c
+++ b/tools/perf/util/debugfs.c
@@ -106,16 +106,14 @@ int debugfs_valid_entry(const char *path)
106 return 0; 106 return 0;
107} 107}
108 108
109/* mount the debugfs somewhere */ 109/* mount the debugfs somewhere if it's not mounted */
110 110
111int debugfs_mount(const char *mountpoint) 111char *debugfs_mount(const char *mountpoint)
112{ 112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */ 113 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) { 114 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1; 115 debugfs_premounted = 1;
118 return 0; 116 return debugfs_mountpoint;
119 } 117 }
120 118
121 /* if not mounted and no argument */ 119 /* if not mounted and no argument */
@@ -127,13 +125,14 @@ int debugfs_mount(const char *mountpoint)
127 mountpoint = "/sys/kernel/debug"; 125 mountpoint = "/sys/kernel/debug";
128 } 126 }
129 127
128 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
129 return NULL;
130
130 /* save the mountpoint */ 131 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); 132 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
133 debugfs_found = 1;
132 134
133 /* mount it */ 135 return debugfs_mountpoint;
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137} 136}
138 137
139/* umount the debugfs */ 138/* umount the debugfs */
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
index 3cd14f9ae784..83a02879745f 100644
--- a/tools/perf/util/debugfs.h
+++ b/tools/perf/util/debugfs.h
@@ -15,7 +15,7 @@
15extern const char *debugfs_find_mountpoint(void); 15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs); 16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path); 17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint); 18extern char *debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void); 19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value); 20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size); 21extern int debugfs_read(const char *entry, char *buffer, size_t size);
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bb0fd6da2d56..2302ec051bb4 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -7,12 +7,46 @@
7#include "strlist.h" 7#include "strlist.h"
8#include "thread.h" 8#include "thread.h"
9 9
10static pid_t event__synthesize_comm(pid_t pid, int full, 10static const char *event__name[] = {
11 int (*process)(event_t *event, 11 [0] = "TOTAL",
12 struct perf_session *session), 12 [PERF_RECORD_MMAP] = "MMAP",
13 [PERF_RECORD_LOST] = "LOST",
14 [PERF_RECORD_COMM] = "COMM",
15 [PERF_RECORD_EXIT] = "EXIT",
16 [PERF_RECORD_THROTTLE] = "THROTTLE",
17 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
18 [PERF_RECORD_FORK] = "FORK",
19 [PERF_RECORD_READ] = "READ",
20 [PERF_RECORD_SAMPLE] = "SAMPLE",
21 [PERF_RECORD_HEADER_ATTR] = "ATTR",
22 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
23 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
24 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
25 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
26};
27
28const char *event__get_event_name(unsigned int id)
29{
30 if (id >= ARRAY_SIZE(event__name))
31 return "INVALID";
32 if (!event__name[id])
33 return "UNKNOWN";
34 return event__name[id];
35}
36
37static struct sample_data synth_sample = {
38 .pid = -1,
39 .tid = -1,
40 .time = -1,
41 .stream_id = -1,
42 .cpu = -1,
43 .period = 1,
44};
45
46static pid_t event__synthesize_comm(event_t *event, pid_t pid, int full,
47 event__handler_t process,
13 struct perf_session *session) 48 struct perf_session *session)
14{ 49{
15 event_t ev;
16 char filename[PATH_MAX]; 50 char filename[PATH_MAX];
17 char bf[BUFSIZ]; 51 char bf[BUFSIZ];
18 FILE *fp; 52 FILE *fp;
@@ -33,34 +67,39 @@ out_race:
33 return 0; 67 return 0;
34 } 68 }
35 69
36 memset(&ev.comm, 0, sizeof(ev.comm)); 70 memset(&event->comm, 0, sizeof(event->comm));
37 while (!ev.comm.comm[0] || !ev.comm.pid) { 71
38 if (fgets(bf, sizeof(bf), fp) == NULL) 72 while (!event->comm.comm[0] || !event->comm.pid) {
39 goto out_failure; 73 if (fgets(bf, sizeof(bf), fp) == NULL) {
74 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
75 goto out;
76 }
40 77
41 if (memcmp(bf, "Name:", 5) == 0) { 78 if (memcmp(bf, "Name:", 5) == 0) {
42 char *name = bf + 5; 79 char *name = bf + 5;
43 while (*name && isspace(*name)) 80 while (*name && isspace(*name))
44 ++name; 81 ++name;
45 size = strlen(name) - 1; 82 size = strlen(name) - 1;
46 memcpy(ev.comm.comm, name, size++); 83 memcpy(event->comm.comm, name, size++);
47 } else if (memcmp(bf, "Tgid:", 5) == 0) { 84 } else if (memcmp(bf, "Tgid:", 5) == 0) {
48 char *tgids = bf + 5; 85 char *tgids = bf + 5;
49 while (*tgids && isspace(*tgids)) 86 while (*tgids && isspace(*tgids))
50 ++tgids; 87 ++tgids;
51 tgid = ev.comm.pid = atoi(tgids); 88 tgid = event->comm.pid = atoi(tgids);
52 } 89 }
53 } 90 }
54 91
55 ev.comm.header.type = PERF_RECORD_COMM; 92 event->comm.header.type = PERF_RECORD_COMM;
56 size = ALIGN(size, sizeof(u64)); 93 size = ALIGN(size, sizeof(u64));
57 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); 94 memset(event->comm.comm + size, 0, session->id_hdr_size);
58 95 event->comm.header.size = (sizeof(event->comm) -
96 (sizeof(event->comm.comm) - size) +
97 session->id_hdr_size);
59 if (!full) { 98 if (!full) {
60 ev.comm.tid = pid; 99 event->comm.tid = pid;
61 100
62 process(&ev, session); 101 process(event, &synth_sample, session);
63 goto out_fclose; 102 goto out;
64 } 103 }
65 104
66 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 105 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
@@ -75,24 +114,20 @@ out_race:
75 if (*end) 114 if (*end)
76 continue; 115 continue;
77 116
78 ev.comm.tid = pid; 117 event->comm.tid = pid;
79 118
80 process(&ev, session); 119 process(event, &synth_sample, session);
81 } 120 }
82 closedir(tasks);
83 121
84out_fclose: 122 closedir(tasks);
123out:
85 fclose(fp); 124 fclose(fp);
86 return tgid;
87 125
88out_failure: 126 return tgid;
89 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
90 return -1;
91} 127}
92 128
93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 129static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid,
94 int (*process)(event_t *event, 130 event__handler_t process,
95 struct perf_session *session),
96 struct perf_session *session) 131 struct perf_session *session)
97{ 132{
98 char filename[PATH_MAX]; 133 char filename[PATH_MAX];
@@ -109,22 +144,25 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
109 return -1; 144 return -1;
110 } 145 }
111 146
147 event->header.type = PERF_RECORD_MMAP;
148 /*
149 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
150 */
151 event->header.misc = PERF_RECORD_MISC_USER;
152
112 while (1) { 153 while (1) {
113 char bf[BUFSIZ], *pbf = bf; 154 char bf[BUFSIZ], *pbf = bf;
114 event_t ev = {
115 .header = { .type = PERF_RECORD_MMAP },
116 };
117 int n; 155 int n;
118 size_t size; 156 size_t size;
119 if (fgets(bf, sizeof(bf), fp) == NULL) 157 if (fgets(bf, sizeof(bf), fp) == NULL)
120 break; 158 break;
121 159
122 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 160 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
123 n = hex2u64(pbf, &ev.mmap.start); 161 n = hex2u64(pbf, &event->mmap.start);
124 if (n < 0) 162 if (n < 0)
125 continue; 163 continue;
126 pbf += n + 1; 164 pbf += n + 1;
127 n = hex2u64(pbf, &ev.mmap.len); 165 n = hex2u64(pbf, &event->mmap.len);
128 if (n < 0) 166 if (n < 0)
129 continue; 167 continue;
130 pbf += n + 3; 168 pbf += n + 3;
@@ -138,17 +176,22 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
138 if (execname == NULL) 176 if (execname == NULL)
139 continue; 177 continue;
140 178
179 pbf += 3;
180 n = hex2u64(pbf, &event->mmap.pgoff);
181
141 size = strlen(execname); 182 size = strlen(execname);
142 execname[size - 1] = '\0'; /* Remove \n */ 183 execname[size - 1] = '\0'; /* Remove \n */
143 memcpy(ev.mmap.filename, execname, size); 184 memcpy(event->mmap.filename, execname, size);
144 size = ALIGN(size, sizeof(u64)); 185 size = ALIGN(size, sizeof(u64));
145 ev.mmap.len -= ev.mmap.start; 186 event->mmap.len -= event->mmap.start;
146 ev.mmap.header.size = (sizeof(ev.mmap) - 187 event->mmap.header.size = (sizeof(event->mmap) -
147 (sizeof(ev.mmap.filename) - size)); 188 (sizeof(event->mmap.filename) - size));
148 ev.mmap.pid = tgid; 189 memset(event->mmap.filename + size, 0, session->id_hdr_size);
149 ev.mmap.tid = pid; 190 event->mmap.header.size += session->id_hdr_size;
150 191 event->mmap.pid = tgid;
151 process(&ev, session); 192 event->mmap.tid = pid;
193
194 process(event, &synth_sample, session);
152 } 195 }
153 } 196 }
154 197
@@ -156,25 +199,112 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
156 return 0; 199 return 0;
157} 200}
158 201
159int event__synthesize_thread(pid_t pid, 202int event__synthesize_modules(event__handler_t process,
160 int (*process)(event_t *event, 203 struct perf_session *session,
161 struct perf_session *session), 204 struct machine *machine)
162 struct perf_session *session)
163{ 205{
164 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 206 struct rb_node *nd;
207 struct map_groups *kmaps = &machine->kmaps;
208 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size);
209
210 if (event == NULL) {
211 pr_debug("Not enough memory synthesizing mmap event "
212 "for kernel modules\n");
213 return -1;
214 }
215
216 event->header.type = PERF_RECORD_MMAP;
217
218 /*
219 * kernel uses 0 for user space maps, see kernel/perf_event.c
220 * __perf_event_mmap
221 */
222 if (machine__is_host(machine))
223 event->header.misc = PERF_RECORD_MISC_KERNEL;
224 else
225 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
226
227 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
228 nd; nd = rb_next(nd)) {
229 size_t size;
230 struct map *pos = rb_entry(nd, struct map, rb_node);
231
232 if (pos->dso->kernel)
233 continue;
234
235 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
236 event->mmap.header.type = PERF_RECORD_MMAP;
237 event->mmap.header.size = (sizeof(event->mmap) -
238 (sizeof(event->mmap.filename) - size));
239 memset(event->mmap.filename + size, 0, session->id_hdr_size);
240 event->mmap.header.size += session->id_hdr_size;
241 event->mmap.start = pos->start;
242 event->mmap.len = pos->end - pos->start;
243 event->mmap.pid = machine->pid;
244
245 memcpy(event->mmap.filename, pos->dso->long_name,
246 pos->dso->long_name_len + 1);
247 process(event, &synth_sample, session);
248 }
249
250 free(event);
251 return 0;
252}
253
254static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event,
255 pid_t pid, event__handler_t process,
256 struct perf_session *session)
257{
258 pid_t tgid = event__synthesize_comm(comm_event, pid, 1, process,
259 session);
165 if (tgid == -1) 260 if (tgid == -1)
166 return -1; 261 return -1;
167 return event__synthesize_mmap_events(pid, tgid, process, session); 262 return event__synthesize_mmap_events(mmap_event, pid, tgid,
263 process, session);
264}
265
266int event__synthesize_thread(pid_t pid, event__handler_t process,
267 struct perf_session *session)
268{
269 event_t *comm_event, *mmap_event;
270 int err = -1;
271
272 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
273 if (comm_event == NULL)
274 goto out;
275
276 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
277 if (mmap_event == NULL)
278 goto out_free_comm;
279
280 err = __event__synthesize_thread(comm_event, mmap_event, pid,
281 process, session);
282 free(mmap_event);
283out_free_comm:
284 free(comm_event);
285out:
286 return err;
168} 287}
169 288
170void event__synthesize_threads(int (*process)(event_t *event, 289int event__synthesize_threads(event__handler_t process,
171 struct perf_session *session), 290 struct perf_session *session)
172 struct perf_session *session)
173{ 291{
174 DIR *proc; 292 DIR *proc;
175 struct dirent dirent, *next; 293 struct dirent dirent, *next;
294 event_t *comm_event, *mmap_event;
295 int err = -1;
296
297 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
298 if (comm_event == NULL)
299 goto out;
300
301 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
302 if (mmap_event == NULL)
303 goto out_free_comm;
176 304
177 proc = opendir("/proc"); 305 proc = opendir("/proc");
306 if (proc == NULL)
307 goto out_free_mmap;
178 308
179 while (!readdir_r(proc, &dirent, &next) && next) { 309 while (!readdir_r(proc, &dirent, &next) && next) {
180 char *end; 310 char *end;
@@ -183,47 +313,142 @@ void event__synthesize_threads(int (*process)(event_t *event,
183 if (*end) /* only interested in proper numerical dirents */ 313 if (*end) /* only interested in proper numerical dirents */
184 continue; 314 continue;
185 315
186 event__synthesize_thread(pid, process, session); 316 __event__synthesize_thread(comm_event, mmap_event, pid,
317 process, session);
187 } 318 }
188 319
189 closedir(proc); 320 closedir(proc);
321 err = 0;
322out_free_mmap:
323 free(mmap_event);
324out_free_comm:
325 free(comm_event);
326out:
327 return err;
190} 328}
191 329
192static void thread__comm_adjust(struct thread *self) 330struct process_symbol_args {
331 const char *name;
332 u64 start;
333};
334
335static int find_symbol_cb(void *arg, const char *name, char type,
336 u64 start, u64 end __used)
337{
338 struct process_symbol_args *args = arg;
339
340 /*
341 * Must be a function or at least an alias, as in PARISC64, where "_text" is
342 * an 'A' to the same address as "_stext".
343 */
344 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
345 type == 'A') || strcmp(name, args->name))
346 return 0;
347
348 args->start = start;
349 return 1;
350}
351
352int event__synthesize_kernel_mmap(event__handler_t process,
353 struct perf_session *session,
354 struct machine *machine,
355 const char *symbol_name)
356{
357 size_t size;
358 const char *filename, *mmap_name;
359 char path[PATH_MAX];
360 char name_buff[PATH_MAX];
361 struct map *map;
362 int err;
363 /*
364 * We should get this from /sys/kernel/sections/.text, but till that is
365 * available use this, and after it is use this as a fallback for older
366 * kernels.
367 */
368 struct process_symbol_args args = { .name = symbol_name, };
369 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size);
370
371 if (event == NULL) {
372 pr_debug("Not enough memory synthesizing mmap event "
373 "for kernel modules\n");
374 return -1;
375 }
376
377 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
378 if (machine__is_host(machine)) {
379 /*
380 * kernel uses PERF_RECORD_MISC_USER for user space maps,
381 * see kernel/perf_event.c __perf_event_mmap
382 */
383 event->header.misc = PERF_RECORD_MISC_KERNEL;
384 filename = "/proc/kallsyms";
385 } else {
386 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
387 if (machine__is_default_guest(machine))
388 filename = (char *) symbol_conf.default_guest_kallsyms;
389 else {
390 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
391 filename = path;
392 }
393 }
394
395 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
396 return -ENOENT;
397
398 map = machine->vmlinux_maps[MAP__FUNCTION];
399 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
400 "%s%s", mmap_name, symbol_name) + 1;
401 size = ALIGN(size, sizeof(u64));
402 event->mmap.header.type = PERF_RECORD_MMAP;
403 event->mmap.header.size = (sizeof(event->mmap) -
404 (sizeof(event->mmap.filename) - size) + session->id_hdr_size);
405 event->mmap.pgoff = args.start;
406 event->mmap.start = map->start;
407 event->mmap.len = map->end - event->mmap.start;
408 event->mmap.pid = machine->pid;
409
410 err = process(event, &synth_sample, session);
411 free(event);
412
413 return err;
414}
415
416static void thread__comm_adjust(struct thread *self, struct hists *hists)
193{ 417{
194 char *comm = self->comm; 418 char *comm = self->comm;
195 419
196 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 420 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
197 (!symbol_conf.comm_list || 421 (!symbol_conf.comm_list ||
198 strlist__has_entry(symbol_conf.comm_list, comm))) { 422 strlist__has_entry(symbol_conf.comm_list, comm))) {
199 unsigned int slen = strlen(comm); 423 u16 slen = strlen(comm);
200 424
201 if (slen > comms__col_width) { 425 if (hists__new_col_len(hists, HISTC_COMM, slen))
202 comms__col_width = slen; 426 hists__set_col_len(hists, HISTC_THREAD, slen + 6);
203 threads__col_width = slen + 6;
204 }
205 } 427 }
206} 428}
207 429
208static int thread__set_comm_adjust(struct thread *self, const char *comm) 430static int thread__set_comm_adjust(struct thread *self, const char *comm,
431 struct hists *hists)
209{ 432{
210 int ret = thread__set_comm(self, comm); 433 int ret = thread__set_comm(self, comm);
211 434
212 if (ret) 435 if (ret)
213 return ret; 436 return ret;
214 437
215 thread__comm_adjust(self); 438 thread__comm_adjust(self, hists);
216 439
217 return 0; 440 return 0;
218} 441}
219 442
220int event__process_comm(event_t *self, struct perf_session *session) 443int event__process_comm(event_t *self, struct sample_data *sample __used,
444 struct perf_session *session)
221{ 445{
222 struct thread *thread = perf_session__findnew(session, self->comm.pid); 446 struct thread *thread = perf_session__findnew(session, self->comm.tid);
223 447
224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 448 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
225 449
226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) { 450 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm,
451 &session->hists)) {
227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 452 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
228 return -1; 453 return -1;
229 } 454 }
@@ -231,49 +456,171 @@ int event__process_comm(event_t *self, struct perf_session *session)
231 return 0; 456 return 0;
232} 457}
233 458
234int event__process_lost(event_t *self, struct perf_session *session) 459int event__process_lost(event_t *self, struct sample_data *sample __used,
460 struct perf_session *session)
235{ 461{
236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 462 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
237 session->events_stats.lost += self->lost.lost; 463 session->hists.stats.total_lost += self->lost.lost;
238 return 0; 464 return 0;
239} 465}
240 466
241int event__process_mmap(event_t *self, struct perf_session *session) 467static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
468{
469 maps[MAP__FUNCTION]->start = self->mmap.start;
470 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
471 /*
472 * Be a bit paranoid here, some perf.data file came with
473 * a zero sized synthesized MMAP event for the kernel.
474 */
475 if (maps[MAP__FUNCTION]->end == 0)
476 maps[MAP__FUNCTION]->end = ~0ULL;
477}
478
479static int event__process_kernel_mmap(event_t *self,
480 struct perf_session *session)
242{ 481{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid); 482 struct map *map;
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 483 char kmmap_prefix[PATH_MAX];
245 session->cwd, session->cwdlen); 484 struct machine *machine;
246 485 enum dso_kernel_type kernel_type;
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 486 bool is_kernel_mmap;
248 self->mmap.pid, self->mmap.tid, 487
249 (void *)(long)self->mmap.start, 488 machine = perf_session__findnew_machine(session, self->mmap.pid);
250 (void *)(long)self->mmap.len, 489 if (!machine) {
251 (void *)(long)self->mmap.pgoff, 490 pr_err("Can't find id %d's machine\n", self->mmap.pid);
252 self->mmap.filename); 491 goto out_problem;
253 492 }
254 if (thread == NULL || map == NULL) 493
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 494 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
495 if (machine__is_host(machine))
496 kernel_type = DSO_TYPE_KERNEL;
256 else 497 else
257 thread__insert_map(thread, map); 498 kernel_type = DSO_TYPE_GUEST_KERNEL;
499
500 is_kernel_mmap = memcmp(self->mmap.filename,
501 kmmap_prefix,
502 strlen(kmmap_prefix)) == 0;
503 if (self->mmap.filename[0] == '/' ||
504 (!is_kernel_mmap && self->mmap.filename[0] == '[')) {
505
506 char short_module_name[1024];
507 char *name, *dot;
508
509 if (self->mmap.filename[0] == '/') {
510 name = strrchr(self->mmap.filename, '/');
511 if (name == NULL)
512 goto out_problem;
513
514 ++name; /* skip / */
515 dot = strrchr(name, '.');
516 if (dot == NULL)
517 goto out_problem;
518 snprintf(short_module_name, sizeof(short_module_name),
519 "[%.*s]", (int)(dot - name), name);
520 strxfrchar(short_module_name, '-', '_');
521 } else
522 strcpy(short_module_name, self->mmap.filename);
523
524 map = machine__new_module(machine, self->mmap.start,
525 self->mmap.filename);
526 if (map == NULL)
527 goto out_problem;
528
529 name = strdup(short_module_name);
530 if (name == NULL)
531 goto out_problem;
532
533 map->dso->short_name = name;
534 map->dso->sname_alloc = 1;
535 map->end = map->start + self->mmap.len;
536 } else if (is_kernel_mmap) {
537 const char *symbol_name = (self->mmap.filename +
538 strlen(kmmap_prefix));
539 /*
540 * Should be there already, from the build-id table in
541 * the header.
542 */
543 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
544 kmmap_prefix);
545 if (kernel == NULL)
546 goto out_problem;
547
548 kernel->kernel = kernel_type;
549 if (__machine__create_kernel_maps(machine, kernel) < 0)
550 goto out_problem;
551
552 event_set_kernel_mmap_len(machine->vmlinux_maps, self);
553 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
554 symbol_name,
555 self->mmap.pgoff);
556 if (machine__is_default_guest(machine)) {
557 /*
558 * preload dso of guest kernel and modules
559 */
560 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
561 NULL);
562 }
563 }
564 return 0;
565out_problem:
566 return -1;
567}
568
569int event__process_mmap(event_t *self, struct sample_data *sample __used,
570 struct perf_session *session)
571{
572 struct machine *machine;
573 struct thread *thread;
574 struct map *map;
575 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
576 int ret = 0;
577
578 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
579 self->mmap.pid, self->mmap.tid, self->mmap.start,
580 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
581
582 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
583 cpumode == PERF_RECORD_MISC_KERNEL) {
584 ret = event__process_kernel_mmap(self, session);
585 if (ret < 0)
586 goto out_problem;
587 return 0;
588 }
258 589
590 machine = perf_session__find_host_machine(session);
591 if (machine == NULL)
592 goto out_problem;
593 thread = perf_session__findnew(session, self->mmap.pid);
594 if (thread == NULL)
595 goto out_problem;
596 map = map__new(&machine->user_dsos, self->mmap.start,
597 self->mmap.len, self->mmap.pgoff,
598 self->mmap.pid, self->mmap.filename,
599 MAP__FUNCTION);
600 if (map == NULL)
601 goto out_problem;
602
603 thread__insert_map(thread, map);
604 return 0;
605
606out_problem:
607 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
259 return 0; 608 return 0;
260} 609}
261 610
262int event__process_task(event_t *self, struct perf_session *session) 611int event__process_task(event_t *self, struct sample_data *sample __used,
612 struct perf_session *session)
263{ 613{
264 struct thread *thread = perf_session__findnew(session, self->fork.pid); 614 struct thread *thread = perf_session__findnew(session, self->fork.tid);
265 struct thread *parent = perf_session__findnew(session, self->fork.ppid); 615 struct thread *parent = perf_session__findnew(session, self->fork.ptid);
266 616
267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 617 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
268 self->fork.ppid, self->fork.ptid); 618 self->fork.ppid, self->fork.ptid);
269 /*
270 * A thread clone will have the same PID for both parent and child.
271 */
272 if (thread == parent)
273 return 0;
274 619
275 if (self->header.type == PERF_RECORD_EXIT) 620 if (self->header.type == PERF_RECORD_EXIT) {
621 perf_session__remove_thread(session, thread);
276 return 0; 622 return 0;
623 }
277 624
278 if (thread == NULL || parent == NULL || 625 if (thread == NULL || parent == NULL ||
279 thread__fork(thread, parent) < 0) { 626 thread__fork(thread, parent) < 0) {
@@ -284,26 +631,79 @@ int event__process_task(event_t *self, struct perf_session *session)
284 return 0; 631 return 0;
285} 632}
286 633
287void thread__find_addr_location(struct thread *self, 634int event__process(event_t *event, struct sample_data *sample,
288 struct perf_session *session, u8 cpumode, 635 struct perf_session *session)
289 enum map_type type, u64 addr, 636{
290 struct addr_location *al, 637 switch (event->header.type) {
291 symbol_filter_t filter) 638 case PERF_RECORD_COMM:
639 event__process_comm(event, sample, session);
640 break;
641 case PERF_RECORD_MMAP:
642 event__process_mmap(event, sample, session);
643 break;
644 case PERF_RECORD_FORK:
645 case PERF_RECORD_EXIT:
646 event__process_task(event, sample, session);
647 break;
648 default:
649 break;
650 }
651
652 return 0;
653}
654
655void thread__find_addr_map(struct thread *self,
656 struct perf_session *session, u8 cpumode,
657 enum map_type type, pid_t pid, u64 addr,
658 struct addr_location *al)
292{ 659{
293 struct map_groups *mg = &self->mg; 660 struct map_groups *mg = &self->mg;
661 struct machine *machine = NULL;
294 662
295 al->thread = self; 663 al->thread = self;
296 al->addr = addr; 664 al->addr = addr;
665 al->cpumode = cpumode;
666 al->filtered = false;
297 667
298 if (cpumode & PERF_RECORD_MISC_KERNEL) { 668 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
299 al->level = 'k'; 669 al->level = 'k';
300 mg = &session->kmaps; 670 machine = perf_session__find_host_machine(session);
301 } else if (cpumode & PERF_RECORD_MISC_USER) 671 if (machine == NULL) {
672 al->map = NULL;
673 return;
674 }
675 mg = &machine->kmaps;
676 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
302 al->level = '.'; 677 al->level = '.';
303 else { 678 machine = perf_session__find_host_machine(session);
304 al->level = 'H'; 679 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
680 al->level = 'g';
681 machine = perf_session__find_machine(session, pid);
682 if (machine == NULL) {
683 al->map = NULL;
684 return;
685 }
686 mg = &machine->kmaps;
687 } else {
688 /*
689 * 'u' means guest os user space.
690 * TODO: We don't support guest user space. Might support late.
691 */
692 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
693 al->level = 'u';
694 else
695 al->level = 'H';
305 al->map = NULL; 696 al->map = NULL;
306 al->sym = NULL; 697
698 if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
699 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
700 !perf_guest)
701 al->filtered = true;
702 if ((cpumode == PERF_RECORD_MISC_USER ||
703 cpumode == PERF_RECORD_MISC_KERNEL) &&
704 !perf_host)
705 al->filtered = true;
706
307 return; 707 return;
308 } 708 }
309try_again: 709try_again:
@@ -318,32 +718,44 @@ try_again:
318 * "[vdso]" dso, but for now lets use the old trick of looking 718 * "[vdso]" dso, but for now lets use the old trick of looking
319 * in the whole kernel symbol list. 719 * in the whole kernel symbol list.
320 */ 720 */
321 if ((long long)al->addr < 0 && mg != &session->kmaps) { 721 if ((long long)al->addr < 0 &&
322 mg = &session->kmaps; 722 cpumode == PERF_RECORD_MISC_KERNEL &&
723 machine && mg != &machine->kmaps) {
724 mg = &machine->kmaps;
323 goto try_again; 725 goto try_again;
324 } 726 }
325 al->sym = NULL; 727 } else
326 } else {
327 al->addr = al->map->map_ip(al->map, al->addr); 728 al->addr = al->map->map_ip(al->map, al->addr);
328 al->sym = map__find_symbol(al->map, session, al->addr, filter);
329 }
330} 729}
331 730
332static void dso__calc_col_width(struct dso *self) 731void thread__find_addr_location(struct thread *self,
732 struct perf_session *session, u8 cpumode,
733 enum map_type type, pid_t pid, u64 addr,
734 struct addr_location *al,
735 symbol_filter_t filter)
736{
737 thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
738 if (al->map != NULL)
739 al->sym = map__find_symbol(al->map, al->addr, filter);
740 else
741 al->sym = NULL;
742}
743
744static void dso__calc_col_width(struct dso *self, struct hists *hists)
333{ 745{
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 746 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list || 747 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) { 748 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name); 749 u16 slen = dso__name_len(self);
338 if (slen > dsos__col_width) 750 hists__new_col_len(hists, HISTC_DSO, slen);
339 dsos__col_width = slen;
340 } 751 }
341 752
342 self->slen_calculated = 1; 753 self->slen_calculated = 1;
343} 754}
344 755
345int event__preprocess_sample(const event_t *self, struct perf_session *session, 756int event__preprocess_sample(const event_t *self, struct perf_session *session,
346 struct addr_location *al, symbol_filter_t filter) 757 struct addr_location *al, struct sample_data *data,
758 symbol_filter_t filter)
347{ 759{
348 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 760 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
349 struct thread *thread = perf_session__findnew(session, self->ip.pid); 761 struct thread *thread = perf_session__findnew(session, self->ip.pid);
@@ -356,31 +768,57 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
356 goto out_filtered; 768 goto out_filtered;
357 769
358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 770 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
771 /*
772 * Have we already created the kernel maps for the host machine?
773 *
774 * This should have happened earlier, when we processed the kernel MMAP
775 * events, but for older perf.data files there was no such thing, so do
776 * it now.
777 */
778 if (cpumode == PERF_RECORD_MISC_KERNEL &&
779 session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL)
780 machine__create_kernel_maps(&session->host_machine);
359 781
360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION, 782 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
361 self->ip.ip, al, filter); 783 self->ip.pid, self->ip.ip, al);
362 dump_printf(" ...... dso: %s\n", 784 dump_printf(" ...... dso: %s\n",
363 al->map ? al->map->dso->long_name : 785 al->map ? al->map->dso->long_name :
364 al->level == 'H' ? "[hypervisor]" : "<not found>"); 786 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /* 787 al->sym = NULL;
366 * We have to do this here as we may have a dso with no symbol hit that 788 al->cpu = data->cpu;
367 * has a name longer than the ones with symbols sampled. 789
368 */ 790 if (al->map) {
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated) 791 if (symbol_conf.dso_list &&
370 dso__calc_col_width(al->map->dso); 792 (!al->map || !al->map->dso ||
371 793 !(strlist__has_entry(symbol_conf.dso_list,
372 if (symbol_conf.dso_list && 794 al->map->dso->short_name) ||
373 (!al->map || !al->map->dso || 795 (al->map->dso->short_name != al->map->dso->long_name &&
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) || 796 strlist__has_entry(symbol_conf.dso_list,
375 (al->map->dso->short_name != al->map->dso->long_name && 797 al->map->dso->long_name)))))
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name))))) 798 goto out_filtered;
377 goto out_filtered; 799 /*
800 * We have to do this here as we may have a dso with no symbol
801 * hit that has a name longer than the ones with symbols
802 * sampled.
803 */
804 if (!sort_dso.elide && !al->map->dso->slen_calculated)
805 dso__calc_col_width(al->map->dso, &session->hists);
806
807 al->sym = map__find_symbol(al->map, al->addr, filter);
808 } else {
809 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
810
811 if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
812 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
813 !symbol_conf.dso_list)
814 hists__set_col_len(&session->hists, HISTC_DSO,
815 unresolved_col_width);
816 }
378 817
379 if (symbol_conf.sym_list && al->sym && 818 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) 819 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered; 820 goto out_filtered;
382 821
383 al->filtered = false;
384 return 0; 822 return 0;
385 823
386out_filtered: 824out_filtered:
@@ -388,9 +826,65 @@ out_filtered:
388 return 0; 826 return 0;
389} 827}
390 828
391int event__parse_sample(event_t *event, u64 type, struct sample_data *data) 829static int event__parse_id_sample(const event_t *event,
830 struct perf_session *session,
831 struct sample_data *sample)
832{
833 const u64 *array;
834 u64 type;
835
836 sample->cpu = sample->pid = sample->tid = -1;
837 sample->stream_id = sample->id = sample->time = -1ULL;
838
839 if (!session->sample_id_all)
840 return 0;
841
842 array = event->sample.array;
843 array += ((event->header.size -
844 sizeof(event->header)) / sizeof(u64)) - 1;
845 type = session->sample_type;
846
847 if (type & PERF_SAMPLE_CPU) {
848 u32 *p = (u32 *)array;
849 sample->cpu = *p;
850 array--;
851 }
852
853 if (type & PERF_SAMPLE_STREAM_ID) {
854 sample->stream_id = *array;
855 array--;
856 }
857
858 if (type & PERF_SAMPLE_ID) {
859 sample->id = *array;
860 array--;
861 }
862
863 if (type & PERF_SAMPLE_TIME) {
864 sample->time = *array;
865 array--;
866 }
867
868 if (type & PERF_SAMPLE_TID) {
869 u32 *p = (u32 *)array;
870 sample->pid = p[0];
871 sample->tid = p[1];
872 }
873
874 return 0;
875}
876
877int event__parse_sample(const event_t *event, struct perf_session *session,
878 struct sample_data *data)
392{ 879{
393 u64 *array = event->sample.array; 880 const u64 *array;
881 u64 type;
882
883 if (event->header.type != PERF_RECORD_SAMPLE)
884 return event__parse_id_sample(event, session, data);
885
886 array = event->sample.array;
887 type = session->sample_type;
394 888
395 if (type & PERF_SAMPLE_IP) { 889 if (type & PERF_SAMPLE_IP) {
396 data->ip = event->ip.ip; 890 data->ip = event->ip.ip;
@@ -414,6 +908,7 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
414 array++; 908 array++;
415 } 909 }
416 910
911 data->id = -1ULL;
417 if (type & PERF_SAMPLE_ID) { 912 if (type & PERF_SAMPLE_ID) {
418 data->id = *array; 913 data->id = *array;
419 array++; 914 array++;
@@ -428,7 +923,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
428 u32 *p = (u32 *)array; 923 u32 *p = (u32 *)array;
429 data->cpu = *p; 924 data->cpu = *p;
430 array++; 925 array++;
431 } 926 } else
927 data->cpu = -1;
432 928
433 if (type & PERF_SAMPLE_PERIOD) { 929 if (type & PERF_SAMPLE_PERIOD) {
434 data->period = *array; 930 data->period = *array;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 690a96d0467c..2b7e91902f10 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -1,10 +1,10 @@
1#ifndef __PERF_RECORD_H 1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H 2#define __PERF_RECORD_H
3 3
4#include <limits.h>
5
4#include "../perf.h" 6#include "../perf.h"
5#include "util.h" 7#include "map.h"
6#include <linux/list.h>
7#include <linux/rbtree.h>
8 8
9/* 9/*
10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * 10 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
@@ -68,21 +68,55 @@ struct sample_data {
68 u64 addr; 68 u64 addr;
69 u64 id; 69 u64 id;
70 u64 stream_id; 70 u64 stream_id;
71 u32 cpu;
72 u64 period; 71 u64 period;
73 struct ip_callchain *callchain; 72 u32 cpu;
74 u32 raw_size; 73 u32 raw_size;
75 void *raw_data; 74 void *raw_data;
75 struct ip_callchain *callchain;
76}; 76};
77 77
78#define BUILD_ID_SIZE 20 78#define BUILD_ID_SIZE 20
79 79
80struct build_id_event { 80struct build_id_event {
81 struct perf_event_header header; 81 struct perf_event_header header;
82 pid_t pid;
82 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; 83 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
83 char filename[]; 84 char filename[];
84}; 85};
85 86
87enum perf_user_event_type { /* above any possible kernel type */
88 PERF_RECORD_USER_TYPE_START = 64,
89 PERF_RECORD_HEADER_ATTR = 64,
90 PERF_RECORD_HEADER_EVENT_TYPE = 65,
91 PERF_RECORD_HEADER_TRACING_DATA = 66,
92 PERF_RECORD_HEADER_BUILD_ID = 67,
93 PERF_RECORD_FINISHED_ROUND = 68,
94 PERF_RECORD_HEADER_MAX
95};
96
97struct attr_event {
98 struct perf_event_header header;
99 struct perf_event_attr attr;
100 u64 id[];
101};
102
103#define MAX_EVENT_NAME 64
104
105struct perf_trace_event_type {
106 u64 event_id;
107 char name[MAX_EVENT_NAME];
108};
109
110struct event_type_event {
111 struct perf_event_header header;
112 struct perf_trace_event_type event_type;
113};
114
115struct tracing_data_event {
116 struct perf_event_header header;
117 u32 size;
118};
119
86typedef union event_union { 120typedef union event_union {
87 struct perf_event_header header; 121 struct perf_event_header header;
88 struct ip_event ip; 122 struct ip_event ip;
@@ -92,92 +126,52 @@ typedef union event_union {
92 struct lost_event lost; 126 struct lost_event lost;
93 struct read_event read; 127 struct read_event read;
94 struct sample_event sample; 128 struct sample_event sample;
129 struct attr_event attr;
130 struct event_type_event event_type;
131 struct tracing_data_event tracing_data;
132 struct build_id_event build_id;
95} event_t; 133} event_t;
96 134
97struct events_stats {
98 u64 total;
99 u64 lost;
100};
101
102void event__print_totals(void); 135void event__print_totals(void);
103 136
104enum map_type {
105 MAP__FUNCTION = 0,
106 MAP__VARIABLE,
107};
108
109#define MAP__NR_TYPES (MAP__VARIABLE + 1)
110
111struct map {
112 union {
113 struct rb_node rb_node;
114 struct list_head node;
115 };
116 u64 start;
117 u64 end;
118 enum map_type type;
119 u64 pgoff;
120 u64 (*map_ip)(struct map *, u64);
121 u64 (*unmap_ip)(struct map *, u64);
122 struct dso *dso;
123};
124
125static inline u64 map__map_ip(struct map *map, u64 ip)
126{
127 return ip - map->start + map->pgoff;
128}
129
130static inline u64 map__unmap_ip(struct map *map, u64 ip)
131{
132 return ip + map->start - map->pgoff;
133}
134
135static inline u64 identity__map_ip(struct map *map __used, u64 ip)
136{
137 return ip;
138}
139
140struct symbol;
141
142typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
143
144void map__init(struct map *self, enum map_type type,
145 u64 start, u64 end, u64 pgoff, struct dso *dso);
146struct map *map__new(struct mmap_event *event, enum map_type,
147 char *cwd, int cwdlen);
148void map__delete(struct map *self);
149struct map *map__clone(struct map *self);
150int map__overlap(struct map *l, struct map *r);
151size_t map__fprintf(struct map *self, FILE *fp);
152
153struct perf_session; 137struct perf_session;
154 138
155int map__load(struct map *self, struct perf_session *session, 139typedef int (*event__handler_synth_t)(event_t *event,
156 symbol_filter_t filter); 140 struct perf_session *session);
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 141typedef int (*event__handler_t)(event_t *event, struct sample_data *sample,
158 u64 addr, symbol_filter_t filter); 142 struct perf_session *session);
159struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
160 struct perf_session *session,
161 symbol_filter_t filter);
162void map__fixup_start(struct map *self);
163void map__fixup_end(struct map *self);
164
165int event__synthesize_thread(pid_t pid,
166 int (*process)(event_t *event,
167 struct perf_session *session),
168 struct perf_session *session);
169void event__synthesize_threads(int (*process)(event_t *event,
170 struct perf_session *session),
171 struct perf_session *session);
172 143
173int event__process_comm(event_t *self, struct perf_session *session); 144int event__synthesize_thread(pid_t pid, event__handler_t process,
174int event__process_lost(event_t *self, struct perf_session *session); 145 struct perf_session *session);
175int event__process_mmap(event_t *self, struct perf_session *session); 146int event__synthesize_threads(event__handler_t process,
176int event__process_task(event_t *self, struct perf_session *session); 147 struct perf_session *session);
148int event__synthesize_kernel_mmap(event__handler_t process,
149 struct perf_session *session,
150 struct machine *machine,
151 const char *symbol_name);
152
153int event__synthesize_modules(event__handler_t process,
154 struct perf_session *session,
155 struct machine *machine);
156
157int event__process_comm(event_t *self, struct sample_data *sample,
158 struct perf_session *session);
159int event__process_lost(event_t *self, struct sample_data *sample,
160 struct perf_session *session);
161int event__process_mmap(event_t *self, struct sample_data *sample,
162 struct perf_session *session);
163int event__process_task(event_t *self, struct sample_data *sample,
164 struct perf_session *session);
165int event__process(event_t *event, struct sample_data *sample,
166 struct perf_session *session);
177 167
178struct addr_location; 168struct addr_location;
179int event__preprocess_sample(const event_t *self, struct perf_session *session, 169int event__preprocess_sample(const event_t *self, struct perf_session *session,
180 struct addr_location *al, symbol_filter_t filter); 170 struct addr_location *al, struct sample_data *data,
181int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 171 symbol_filter_t filter);
172int event__parse_sample(const event_t *event, struct perf_session *session,
173 struct sample_data *sample);
174
175const char *event__get_event_name(unsigned int id);
182 176
183#endif /* __PERF_RECORD_H */ 177#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
new file mode 100644
index 000000000000..f5cfed60af98
--- /dev/null
+++ b/tools/perf/util/evsel.c
@@ -0,0 +1,201 @@
1#include "evsel.h"
2#include "../perf.h"
3#include "util.h"
4#include "cpumap.h"
5#include "thread.h"
6
7#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
8
9struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
10{
11 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
12
13 if (evsel != NULL) {
14 evsel->idx = idx;
15 evsel->attr = *attr;
16 INIT_LIST_HEAD(&evsel->node);
17 }
18
19 return evsel;
20}
21
22int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
23{
24 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
25 return evsel->fd != NULL ? 0 : -ENOMEM;
26}
27
28int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
29{
30 evsel->counts = zalloc((sizeof(*evsel->counts) +
31 (ncpus * sizeof(struct perf_counts_values))));
32 return evsel->counts != NULL ? 0 : -ENOMEM;
33}
34
35void perf_evsel__free_fd(struct perf_evsel *evsel)
36{
37 xyarray__delete(evsel->fd);
38 evsel->fd = NULL;
39}
40
41void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
42{
43 int cpu, thread;
44
45 for (cpu = 0; cpu < ncpus; cpu++)
46 for (thread = 0; thread < nthreads; ++thread) {
47 close(FD(evsel, cpu, thread));
48 FD(evsel, cpu, thread) = -1;
49 }
50}
51
52void perf_evsel__delete(struct perf_evsel *evsel)
53{
54 assert(list_empty(&evsel->node));
55 xyarray__delete(evsel->fd);
56 free(evsel);
57}
58
59int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
60 int cpu, int thread, bool scale)
61{
62 struct perf_counts_values count;
63 size_t nv = scale ? 3 : 1;
64
65 if (FD(evsel, cpu, thread) < 0)
66 return -EINVAL;
67
68 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
69 return -ENOMEM;
70
71 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
72 return -errno;
73
74 if (scale) {
75 if (count.run == 0)
76 count.val = 0;
77 else if (count.run < count.ena)
78 count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
79 } else
80 count.ena = count.run = 0;
81
82 evsel->counts->cpu[cpu] = count;
83 return 0;
84}
85
86int __perf_evsel__read(struct perf_evsel *evsel,
87 int ncpus, int nthreads, bool scale)
88{
89 size_t nv = scale ? 3 : 1;
90 int cpu, thread;
91 struct perf_counts_values *aggr = &evsel->counts->aggr, count;
92
93 aggr->val = 0;
94
95 for (cpu = 0; cpu < ncpus; cpu++) {
96 for (thread = 0; thread < nthreads; thread++) {
97 if (FD(evsel, cpu, thread) < 0)
98 continue;
99
100 if (readn(FD(evsel, cpu, thread),
101 &count, nv * sizeof(u64)) < 0)
102 return -errno;
103
104 aggr->val += count.val;
105 if (scale) {
106 aggr->ena += count.ena;
107 aggr->run += count.run;
108 }
109 }
110 }
111
112 evsel->counts->scaled = 0;
113 if (scale) {
114 if (aggr->run == 0) {
115 evsel->counts->scaled = -1;
116 aggr->val = 0;
117 return 0;
118 }
119
120 if (aggr->run < aggr->ena) {
121 evsel->counts->scaled = 1;
122 aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
123 }
124 } else
125 aggr->ena = aggr->run = 0;
126
127 return 0;
128}
129
130static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
131 struct thread_map *threads)
132{
133 int cpu, thread;
134
135 if (evsel->fd == NULL &&
136 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0)
137 return -1;
138
139 for (cpu = 0; cpu < cpus->nr; cpu++) {
140 for (thread = 0; thread < threads->nr; thread++) {
141 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr,
142 threads->map[thread],
143 cpus->map[cpu], -1, 0);
144 if (FD(evsel, cpu, thread) < 0)
145 goto out_close;
146 }
147 }
148
149 return 0;
150
151out_close:
152 do {
153 while (--thread >= 0) {
154 close(FD(evsel, cpu, thread));
155 FD(evsel, cpu, thread) = -1;
156 }
157 thread = threads->nr;
158 } while (--cpu >= 0);
159 return -1;
160}
161
162static struct {
163 struct cpu_map map;
164 int cpus[1];
165} empty_cpu_map = {
166 .map.nr = 1,
167 .cpus = { -1, },
168};
169
170static struct {
171 struct thread_map map;
172 int threads[1];
173} empty_thread_map = {
174 .map.nr = 1,
175 .threads = { -1, },
176};
177
178int perf_evsel__open(struct perf_evsel *evsel,
179 struct cpu_map *cpus, struct thread_map *threads)
180{
181
182 if (cpus == NULL) {
183 /* Work around old compiler warnings about strict aliasing */
184 cpus = &empty_cpu_map.map;
185 }
186
187 if (threads == NULL)
188 threads = &empty_thread_map.map;
189
190 return __perf_evsel__open(evsel, cpus, threads);
191}
192
193int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus)
194{
195 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map);
196}
197
198int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads)
199{
200 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads);
201}
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
new file mode 100644
index 000000000000..b2d755fe88a5
--- /dev/null
+++ b/tools/perf/util/evsel.h
@@ -0,0 +1,115 @@
1#ifndef __PERF_EVSEL_H
2#define __PERF_EVSEL_H 1
3
4#include <linux/list.h>
5#include <stdbool.h>
6#include "../../../include/linux/perf_event.h"
7#include "types.h"
8#include "xyarray.h"
9
10struct perf_counts_values {
11 union {
12 struct {
13 u64 val;
14 u64 ena;
15 u64 run;
16 };
17 u64 values[3];
18 };
19};
20
21struct perf_counts {
22 s8 scaled;
23 struct perf_counts_values aggr;
24 struct perf_counts_values cpu[];
25};
26
27struct perf_evsel {
28 struct list_head node;
29 struct perf_event_attr attr;
30 char *filter;
31 struct xyarray *fd;
32 struct perf_counts *counts;
33 int idx;
34 void *priv;
35};
36
37struct cpu_map;
38struct thread_map;
39
40struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx);
41void perf_evsel__delete(struct perf_evsel *evsel);
42
43int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
44int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
45void perf_evsel__free_fd(struct perf_evsel *evsel);
46void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
47
48int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus);
49int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads);
50int perf_evsel__open(struct perf_evsel *evsel,
51 struct cpu_map *cpus, struct thread_map *threads);
52
53#define perf_evsel__match(evsel, t, c) \
54 (evsel->attr.type == PERF_TYPE_##t && \
55 evsel->attr.config == PERF_COUNT_##c)
56
57int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
58 int cpu, int thread, bool scale);
59
60/**
61 * perf_evsel__read_on_cpu - Read out the results on a CPU and thread
62 *
63 * @evsel - event selector to read value
64 * @cpu - CPU of interest
65 * @thread - thread of interest
66 */
67static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel,
68 int cpu, int thread)
69{
70 return __perf_evsel__read_on_cpu(evsel, cpu, thread, false);
71}
72
73/**
74 * perf_evsel__read_on_cpu_scaled - Read out the results on a CPU and thread, scaled
75 *
76 * @evsel - event selector to read value
77 * @cpu - CPU of interest
78 * @thread - thread of interest
79 */
80static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel,
81 int cpu, int thread)
82{
83 return __perf_evsel__read_on_cpu(evsel, cpu, thread, true);
84}
85
86int __perf_evsel__read(struct perf_evsel *evsel, int ncpus, int nthreads,
87 bool scale);
88
89/**
90 * perf_evsel__read - Read the aggregate results on all CPUs
91 *
92 * @evsel - event selector to read value
93 * @ncpus - Number of cpus affected, from zero
94 * @nthreads - Number of threads affected, from zero
95 */
96static inline int perf_evsel__read(struct perf_evsel *evsel,
97 int ncpus, int nthreads)
98{
99 return __perf_evsel__read(evsel, ncpus, nthreads, false);
100}
101
102/**
103 * perf_evsel__read_scaled - Read the aggregate results on all CPUs, scaled
104 *
105 * @evsel - event selector to read value
106 * @ncpus - Number of cpus affected, from zero
107 * @nthreads - Number of threads affected, from zero
108 */
109static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
110 int ncpus, int nthreads)
111{
112 return __perf_evsel__read(evsel, ncpus, nthreads, true);
113}
114
115#endif /* __PERF_EVSEL_H */
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index 2745605dba11..67eeff571568 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -53,8 +53,8 @@ const char *perf_extract_argv0_path(const char *argv0)
53 slash--; 53 slash--;
54 54
55 if (slash >= argv0) { 55 if (slash >= argv0) {
56 argv0_path = xstrndup(argv0, slash - argv0); 56 argv0_path = strndup(argv0, slash - argv0);
57 return slash + 1; 57 return argv0_path ? slash + 1 : NULL;
58 } 58 }
59 59
60 return argv0; 60 return argv0;
@@ -116,7 +116,7 @@ void setup_path(void)
116 strbuf_release(&new_path); 116 strbuf_release(&new_path);
117} 117}
118 118
119const char **prepare_perf_cmd(const char **argv) 119static const char **prepare_perf_cmd(const char **argv)
120{ 120{
121 int argc; 121 int argc;
122 const char **nargv; 122 const char **nargv;
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
index 31647ac92ed1..bc4b915963f5 100644
--- a/tools/perf/util/exec_cmd.h
+++ b/tools/perf/util/exec_cmd.h
@@ -5,7 +5,6 @@ extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path); 5extern const char *perf_extract_argv0_path(const char *path);
6extern const char *perf_exec_path(void); 6extern const char *perf_exec_path(void);
7extern void setup_path(void); 7extern void setup_path(void);
8extern const char **prepare_perf_cmd(const char **argv);
9extern int execv_perf_cmd(const char **argv); /* NULL terminated */ 8extern int execv_perf_cmd(const char **argv); /* NULL terminated */
10extern int execl_perf_cmd(const char *cmd, ...); 9extern int execl_perf_cmd(const char *cmd, ...);
11extern const char *system_path(const char *path); 10extern const char *system_path(const char *path);
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 8a0bca55106f..989fa2dee2fd 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,8 +1,12 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <sys/types.h> 3#include <sys/types.h>
4#include <byteswap.h>
2#include <unistd.h> 5#include <unistd.h>
3#include <stdio.h> 6#include <stdio.h>
4#include <stdlib.h> 7#include <stdlib.h>
5#include <linux/list.h> 8#include <linux/list.h>
9#include <linux/kernel.h>
6 10
7#include "util.h" 11#include "util.h"
8#include "header.h" 12#include "header.h"
@@ -12,6 +16,8 @@
12#include "symbol.h" 16#include "symbol.h"
13#include "debug.h" 17#include "debug.h"
14 18
19static bool no_buildid_cache = false;
20
15/* 21/*
16 * Create new perf.data header attribute: 22 * Create new perf.data header attribute:
17 */ 23 */
@@ -95,34 +101,31 @@ int perf_header__add_attr(struct perf_header *self,
95 return 0; 101 return 0;
96} 102}
97 103
98#define MAX_EVENT_NAME 64
99
100struct perf_trace_event_type {
101 u64 event_id;
102 char name[MAX_EVENT_NAME];
103};
104
105static int event_count; 104static int event_count;
106static struct perf_trace_event_type *events; 105static struct perf_trace_event_type *events;
107 106
108void perf_header__push_event(u64 id, const char *name) 107int perf_header__push_event(u64 id, const char *name)
109{ 108{
110 if (strlen(name) > MAX_EVENT_NAME) 109 if (strlen(name) > MAX_EVENT_NAME)
111 pr_warning("Event %s will be truncated\n", name); 110 pr_warning("Event %s will be truncated\n", name);
112 111
113 if (!events) { 112 if (!events) {
114 events = malloc(sizeof(struct perf_trace_event_type)); 113 events = malloc(sizeof(struct perf_trace_event_type));
115 if (!events) 114 if (events == NULL)
116 die("nomem"); 115 return -ENOMEM;
117 } else { 116 } else {
118 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type)); 117 struct perf_trace_event_type *nevents;
119 if (!events) 118
120 die("nomem"); 119 nevents = realloc(events, (event_count + 1) * sizeof(*events));
120 if (nevents == NULL)
121 return -ENOMEM;
122 events = nevents;
121 } 123 }
122 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 124 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
123 events[event_count].event_id = id; 125 events[event_count].event_id = id;
124 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 126 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
125 event_count++; 127 event_count++;
128 return 0;
126} 129}
127 130
128char *perf_header__find_event(u64 id) 131char *perf_header__find_event(u64 id)
@@ -149,6 +152,11 @@ void perf_header__set_feat(struct perf_header *self, int feat)
149 set_bit(feat, self->adds_features); 152 set_bit(feat, self->adds_features);
150} 153}
151 154
155void perf_header__clear_feat(struct perf_header *self, int feat)
156{
157 clear_bit(feat, self->adds_features);
158}
159
152bool perf_header__has_feat(const struct perf_header *self, int feat) 160bool perf_header__has_feat(const struct perf_header *self, int feat)
153{ 161{
154 return test_bit(feat, self->adds_features); 162 return test_bit(feat, self->adds_features);
@@ -169,31 +177,50 @@ static int do_write(int fd, const void *buf, size_t size)
169 return 0; 177 return 0;
170} 178}
171 179
172static int __dsos__write_buildid_table(struct list_head *head, int fd) 180#define NAME_ALIGN 64
181
182static int write_padded(int fd, const void *bf, size_t count,
183 size_t count_aligned)
173{ 184{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN]; 185 static const char zero_buf[NAME_ALIGN];
186 int err = do_write(fd, bf, count);
187
188 if (!err)
189 err = do_write(fd, zero_buf, count_aligned - count);
190
191 return err;
192}
177 193
178 list_for_each_entry(pos, head, node) { 194#define dsos__for_each_with_build_id(pos, head) \
195 list_for_each_entry(pos, head, node) \
196 if (!pos->has_build_id) \
197 continue; \
198 else
199
200static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
201 u16 misc, int fd)
202{
203 struct dso *pos;
204
205 dsos__for_each_with_build_id(pos, head) {
179 int err; 206 int err;
180 struct build_id_event b; 207 struct build_id_event b;
181 size_t len; 208 size_t len;
182 209
183 if (!pos->has_build_id) 210 if (!pos->hit)
184 continue; 211 continue;
185 len = pos->long_name_len + 1; 212 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN); 213 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b)); 214 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 215 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
216 b.pid = pid;
217 b.header.misc = misc;
189 b.header.size = sizeof(b) + len; 218 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b)); 219 err = do_write(fd, &b, sizeof(b));
191 if (err < 0) 220 if (err < 0)
192 return err; 221 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1); 222 err = write_padded(fd, pos->long_name,
194 if (err < 0) 223 pos->long_name_len + 1, len);
195 return err;
196 err = do_write(fd, zero_buf, len - pos->long_name_len - 1);
197 if (err < 0) 224 if (err < 0)
198 return err; 225 return err;
199 } 226 }
@@ -201,24 +228,220 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
201 return 0; 228 return 0;
202} 229}
203 230
204static int dsos__write_buildid_table(int fd) 231static int machine__write_buildid_table(struct machine *self, int fd)
205{ 232{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd); 233 int err;
234 u16 kmisc = PERF_RECORD_MISC_KERNEL,
235 umisc = PERF_RECORD_MISC_USER;
236
237 if (!machine__is_host(self)) {
238 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
239 umisc = PERF_RECORD_MISC_GUEST_USER;
240 }
241
242 err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid,
243 kmisc, fd);
207 if (err == 0) 244 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd); 245 err = __dsos__write_buildid_table(&self->user_dsos,
246 self->pid, umisc, fd);
247 return err;
248}
249
250static int dsos__write_buildid_table(struct perf_header *header, int fd)
251{
252 struct perf_session *session = container_of(header,
253 struct perf_session, header);
254 struct rb_node *nd;
255 int err = machine__write_buildid_table(&session->host_machine, fd);
256
257 if (err)
258 return err;
259
260 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
261 struct machine *pos = rb_entry(nd, struct machine, rb_node);
262 err = machine__write_buildid_table(pos, fd);
263 if (err)
264 break;
265 }
266 return err;
267}
268
269int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
270 const char *name, bool is_kallsyms)
271{
272 const size_t size = PATH_MAX;
273 char *realname = realpath(name, NULL),
274 *filename = malloc(size),
275 *linkname = malloc(size), *targetname;
276 int len, err = -1;
277
278 if (realname == NULL || filename == NULL || linkname == NULL)
279 goto out_free;
280
281 len = snprintf(filename, size, "%s%s%s",
282 debugdir, is_kallsyms ? "/" : "", realname);
283 if (mkdir_p(filename, 0755))
284 goto out_free;
285
286 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
287
288 if (access(filename, F_OK)) {
289 if (is_kallsyms) {
290 if (copyfile("/proc/kallsyms", filename))
291 goto out_free;
292 } else if (link(realname, filename) && copyfile(name, filename))
293 goto out_free;
294 }
295
296 len = snprintf(linkname, size, "%s/.build-id/%.2s",
297 debugdir, sbuild_id);
298
299 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
300 goto out_free;
301
302 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
303 targetname = filename + strlen(debugdir) - 5;
304 memcpy(targetname, "../..", 5);
305
306 if (symlink(targetname, linkname) == 0)
307 err = 0;
308out_free:
309 free(realname);
310 free(filename);
311 free(linkname);
312 return err;
313}
314
315static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
316 const char *name, const char *debugdir,
317 bool is_kallsyms)
318{
319 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
320
321 build_id__sprintf(build_id, build_id_size, sbuild_id);
322
323 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
324}
325
326int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
327{
328 const size_t size = PATH_MAX;
329 char *filename = malloc(size),
330 *linkname = malloc(size);
331 int err = -1;
332
333 if (filename == NULL || linkname == NULL)
334 goto out_free;
335
336 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
337 debugdir, sbuild_id, sbuild_id + 2);
338
339 if (access(linkname, F_OK))
340 goto out_free;
341
342 if (readlink(linkname, filename, size) < 0)
343 goto out_free;
344
345 if (unlink(linkname))
346 goto out_free;
347
348 /*
349 * Since the link is relative, we must make it absolute:
350 */
351 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
352 debugdir, sbuild_id, filename);
353
354 if (unlink(linkname))
355 goto out_free;
356
357 err = 0;
358out_free:
359 free(filename);
360 free(linkname);
361 return err;
362}
363
364static int dso__cache_build_id(struct dso *self, const char *debugdir)
365{
366 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
367
368 return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
369 self->long_name, debugdir, is_kallsyms);
370}
371
372static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
373{
374 struct dso *pos;
375 int err = 0;
376
377 dsos__for_each_with_build_id(pos, head)
378 if (dso__cache_build_id(pos, debugdir))
379 err = -1;
380
209 return err; 381 return err;
210} 382}
211 383
384static int machine__cache_build_ids(struct machine *self, const char *debugdir)
385{
386 int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir);
387 ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir);
388 return ret;
389}
390
391static int perf_session__cache_build_ids(struct perf_session *self)
392{
393 struct rb_node *nd;
394 int ret;
395 char debugdir[PATH_MAX];
396
397 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
398
399 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
400 return -1;
401
402 ret = machine__cache_build_ids(&self->host_machine, debugdir);
403
404 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
405 struct machine *pos = rb_entry(nd, struct machine, rb_node);
406 ret |= machine__cache_build_ids(pos, debugdir);
407 }
408 return ret ? -1 : 0;
409}
410
411static bool machine__read_build_ids(struct machine *self, bool with_hits)
412{
413 bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits);
414 ret |= __dsos__read_build_ids(&self->user_dsos, with_hits);
415 return ret;
416}
417
418static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits)
419{
420 struct rb_node *nd;
421 bool ret = machine__read_build_ids(&self->host_machine, with_hits);
422
423 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
424 struct machine *pos = rb_entry(nd, struct machine, rb_node);
425 ret |= machine__read_build_ids(pos, with_hits);
426 }
427
428 return ret;
429}
430
212static int perf_header__adds_write(struct perf_header *self, int fd) 431static int perf_header__adds_write(struct perf_header *self, int fd)
213{ 432{
214 int nr_sections; 433 int nr_sections;
434 struct perf_session *session;
215 struct perf_file_section *feat_sec; 435 struct perf_file_section *feat_sec;
216 int sec_size; 436 int sec_size;
217 u64 sec_start; 437 u64 sec_start;
218 int idx = 0, err; 438 int idx = 0, err;
219 439
220 if (dsos__read_build_ids()) 440 session = container_of(self, struct perf_session, header);
221 perf_header__set_feat(self, HEADER_BUILD_ID); 441
442 if (perf_header__has_feat(self, HEADER_BUILD_ID &&
443 !perf_session__read_build_ids(session, true)))
444 perf_header__clear_feat(self, HEADER_BUILD_ID);
222 445
223 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 446 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
224 if (!nr_sections) 447 if (!nr_sections)
@@ -240,11 +463,10 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
240 463
241 /* Write trace info */ 464 /* Write trace info */
242 trace_sec->offset = lseek(fd, 0, SEEK_CUR); 465 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
243 read_tracing_data(fd, attrs, nr_counters); 466 read_tracing_data(fd, &evsel_list);
244 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 467 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
245 } 468 }
246 469
247
248 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 470 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
249 struct perf_file_section *buildid_sec; 471 struct perf_file_section *buildid_sec;
250 472
@@ -252,12 +474,15 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
252 474
253 /* Write build-ids */ 475 /* Write build-ids */
254 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 476 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
255 err = dsos__write_buildid_table(fd); 477 err = dsos__write_buildid_table(self, fd);
256 if (err < 0) { 478 if (err < 0) {
257 pr_debug("failed to write buildid table\n"); 479 pr_debug("failed to write buildid table\n");
258 goto out_free; 480 goto out_free;
259 } 481 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 482 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
483 buildid_sec->offset;
484 if (!no_buildid_cache)
485 perf_session__cache_build_ids(session);
261 } 486 }
262 487
263 lseek(fd, sec_start, SEEK_SET); 488 lseek(fd, sec_start, SEEK_SET);
@@ -269,6 +494,25 @@ out_free:
269 return err; 494 return err;
270} 495}
271 496
497int perf_header__write_pipe(int fd)
498{
499 struct perf_pipe_file_header f_header;
500 int err;
501
502 f_header = (struct perf_pipe_file_header){
503 .magic = PERF_MAGIC,
504 .size = sizeof(f_header),
505 };
506
507 err = do_write(fd, &f_header, sizeof(f_header));
508 if (err < 0) {
509 pr_debug("failed to write perf pipe header\n");
510 return err;
511 }
512
513 return 0;
514}
515
272int perf_header__write(struct perf_header *self, int fd, bool at_exit) 516int perf_header__write(struct perf_header *self, int fd, bool at_exit)
273{ 517{
274 struct perf_file_header f_header; 518 struct perf_file_header f_header;
@@ -278,7 +522,6 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
278 522
279 lseek(fd, sizeof(f_header), SEEK_SET); 523 lseek(fd, sizeof(f_header), SEEK_SET);
280 524
281
282 for (i = 0; i < self->attrs; i++) { 525 for (i = 0; i < self->attrs; i++) {
283 attr = self->attr[i]; 526 attr = self->attr[i];
284 527
@@ -360,30 +603,28 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
360 return 0; 603 return 0;
361} 604}
362 605
363static void do_read(int fd, void *buf, size_t size) 606static int perf_header__getbuffer64(struct perf_header *self,
607 int fd, void *buf, size_t size)
364{ 608{
365 while (size) { 609 if (readn(fd, buf, size) <= 0)
366 int ret = read(fd, buf, size); 610 return -1;
367 611
368 if (ret < 0) 612 if (self->needs_swap)
369 die("failed to read"); 613 mem_bswap_64(buf, size);
370 if (ret == 0)
371 die("failed to read: missing data");
372 614
373 size -= ret; 615 return 0;
374 buf += ret;
375 }
376} 616}
377 617
378int perf_header__process_sections(struct perf_header *self, int fd, 618int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self, 619 int (*process)(struct perf_file_section *self,
620 struct perf_header *ph,
380 int feat, int fd)) 621 int feat, int fd))
381{ 622{
382 struct perf_file_section *feat_sec; 623 struct perf_file_section *feat_sec;
383 int nr_sections; 624 int nr_sections;
384 int sec_size; 625 int sec_size;
385 int idx = 0; 626 int idx = 0;
386 int err = 0, feat = 1; 627 int err = -1, feat = 1;
387 628
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 629 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections) 630 if (!nr_sections)
@@ -397,33 +638,45 @@ int perf_header__process_sections(struct perf_header *self, int fd,
397 638
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 639 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399 640
400 do_read(fd, feat_sec, sec_size); 641 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
642 goto out_free;
401 643
644 err = 0;
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 645 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) { 646 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++]; 647 struct perf_file_section *sec = &feat_sec[idx++];
405 648
406 err = process(sec, feat, fd); 649 err = process(sec, self, feat, fd);
407 if (err < 0) 650 if (err < 0)
408 break; 651 break;
409 } 652 }
410 ++feat; 653 ++feat;
411 } 654 }
412 655out_free:
413 free(feat_sec); 656 free(feat_sec);
414 return err; 657 return err;
415}; 658}
416 659
417int perf_file_header__read(struct perf_file_header *self, 660int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd) 661 struct perf_header *ph, int fd)
419{ 662{
420 lseek(fd, 0, SEEK_SET); 663 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422 664
423 if (self->magic != PERF_MAGIC || 665 if (readn(fd, self, sizeof(*self)) <= 0 ||
424 self->attr_size != sizeof(struct perf_file_attr)) 666 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
425 return -1; 667 return -1;
426 668
669 if (self->attr_size != sizeof(struct perf_file_attr)) {
670 u64 attr_size = bswap_64(self->attr_size);
671
672 if (attr_size != sizeof(struct perf_file_attr))
673 return -1;
674
675 mem_bswap_64(self, offsetof(struct perf_file_header,
676 adds_features));
677 ph->needs_swap = true;
678 }
679
427 if (self->size != sizeof(*self)) { 680 if (self->size != sizeof(*self)) {
428 /* Support the previous format */ 681 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features)) 682 if (self->size == offsetof(typeof(*self), adds_features))
@@ -433,19 +686,118 @@ int perf_file_header__read(struct perf_file_header *self,
433 } 686 }
434 687
435 memcpy(&ph->adds_features, &self->adds_features, 688 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(self->adds_features)); 689 sizeof(ph->adds_features));
690 /*
691 * FIXME: hack that assumes that if we need swap the perf.data file
692 * may be coming from an arch with a different word-size, ergo different
693 * DEFINE_BITMAP format, investigate more later, but for now its mostly
694 * safe to assume that we have a build-id section. Trace files probably
695 * have several other issues in this realm anyway...
696 */
697 if (ph->needs_swap) {
698 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
699 perf_header__set_feat(ph, HEADER_BUILD_ID);
700 }
437 701
438 ph->event_offset = self->event_types.offset; 702 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size; 703 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset; 704 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size; 705 ph->data_size = self->data.size;
442 return 0; 706 return 0;
443} 707}
444 708
709static int __event_process_build_id(struct build_id_event *bev,
710 char *filename,
711 struct perf_session *session)
712{
713 int err = -1;
714 struct list_head *head;
715 struct machine *machine;
716 u16 misc;
717 struct dso *dso;
718 enum dso_kernel_type dso_type;
719
720 machine = perf_session__findnew_machine(session, bev->pid);
721 if (!machine)
722 goto out;
723
724 misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
725
726 switch (misc) {
727 case PERF_RECORD_MISC_KERNEL:
728 dso_type = DSO_TYPE_KERNEL;
729 head = &machine->kernel_dsos;
730 break;
731 case PERF_RECORD_MISC_GUEST_KERNEL:
732 dso_type = DSO_TYPE_GUEST_KERNEL;
733 head = &machine->kernel_dsos;
734 break;
735 case PERF_RECORD_MISC_USER:
736 case PERF_RECORD_MISC_GUEST_USER:
737 dso_type = DSO_TYPE_USER;
738 head = &machine->user_dsos;
739 break;
740 default:
741 goto out;
742 }
743
744 dso = __dsos__findnew(head, filename);
745 if (dso != NULL) {
746 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
747
748 dso__set_build_id(dso, &bev->build_id);
749
750 if (filename[0] == '[')
751 dso->kernel = dso_type;
752
753 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
754 sbuild_id);
755 pr_debug("build id event received for %s: %s\n",
756 dso->long_name, sbuild_id);
757 }
758
759 err = 0;
760out:
761 return err;
762}
763
764static int perf_header__read_build_ids(struct perf_header *self,
765 int input, u64 offset, u64 size)
766{
767 struct perf_session *session = container_of(self,
768 struct perf_session, header);
769 struct build_id_event bev;
770 char filename[PATH_MAX];
771 u64 limit = offset + size;
772 int err = -1;
773
774 while (offset < limit) {
775 ssize_t len;
776
777 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
778 goto out;
779
780 if (self->needs_swap)
781 perf_event_header__bswap(&bev.header);
782
783 len = bev.header.size - sizeof(bev);
784 if (read(input, filename, len) != len)
785 goto out;
786
787 __event_process_build_id(&bev, filename, session);
788
789 offset += bev.header.size;
790 }
791 err = 0;
792out:
793 return err;
794}
795
445static int perf_file_section__process(struct perf_file_section *self, 796static int perf_file_section__process(struct perf_file_section *self,
797 struct perf_header *ph,
446 int feat, int fd) 798 int feat, int fd)
447{ 799{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) { 800 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
449 pr_debug("Failed to lseek to %Ld offset for feature %d, " 801 pr_debug("Failed to lseek to %Ld offset for feature %d, "
450 "continuing...\n", self->offset, feat); 802 "continuing...\n", self->offset, feat);
451 return 0; 803 return 0;
@@ -453,11 +805,11 @@ static int perf_file_section__process(struct perf_file_section *self,
453 805
454 switch (feat) { 806 switch (feat) {
455 case HEADER_TRACE_INFO: 807 case HEADER_TRACE_INFO:
456 trace_report(fd); 808 trace_report(fd, false);
457 break; 809 break;
458 810
459 case HEADER_BUILD_ID: 811 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size)) 812 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n"); 813 pr_debug("Failed to read buildids, continuing...\n");
462 break; 814 break;
463 default: 815 default:
@@ -467,13 +819,56 @@ static int perf_file_section__process(struct perf_file_section *self,
467 return 0; 819 return 0;
468} 820}
469 821
470int perf_header__read(struct perf_header *self, int fd) 822static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
823 struct perf_header *ph, int fd,
824 bool repipe)
471{ 825{
472 struct perf_file_header f_header; 826 if (readn(fd, self, sizeof(*self)) <= 0 ||
827 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
828 return -1;
829
830 if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0)
831 return -1;
832
833 if (self->size != sizeof(*self)) {
834 u64 size = bswap_64(self->size);
835
836 if (size != sizeof(*self))
837 return -1;
838
839 ph->needs_swap = true;
840 }
841
842 return 0;
843}
844
845static int perf_header__read_pipe(struct perf_session *session, int fd)
846{
847 struct perf_header *self = &session->header;
848 struct perf_pipe_file_header f_header;
849
850 if (perf_file_header__read_pipe(&f_header, self, fd,
851 session->repipe) < 0) {
852 pr_debug("incompatible file format\n");
853 return -EINVAL;
854 }
855
856 session->fd = fd;
857
858 return 0;
859}
860
861int perf_header__read(struct perf_session *session, int fd)
862{
863 struct perf_header *self = &session->header;
864 struct perf_file_header f_header;
473 struct perf_file_attr f_attr; 865 struct perf_file_attr f_attr;
474 u64 f_id; 866 u64 f_id;
475 int nr_attrs, nr_ids, i, j; 867 int nr_attrs, nr_ids, i, j;
476 868
869 if (session->fd_pipe)
870 return perf_header__read_pipe(session, fd);
871
477 if (perf_file_header__read(&f_header, self, fd) < 0) { 872 if (perf_file_header__read(&f_header, self, fd) < 0) {
478 pr_debug("incompatible file format\n"); 873 pr_debug("incompatible file format\n");
479 return -EINVAL; 874 return -EINVAL;
@@ -486,7 +881,9 @@ int perf_header__read(struct perf_header *self, int fd)
486 struct perf_header_attr *attr; 881 struct perf_header_attr *attr;
487 off_t tmp; 882 off_t tmp;
488 883
489 do_read(fd, &f_attr, sizeof(f_attr)); 884 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
885 goto out_errno;
886
490 tmp = lseek(fd, 0, SEEK_CUR); 887 tmp = lseek(fd, 0, SEEK_CUR);
491 888
492 attr = perf_header_attr__new(&f_attr.attr); 889 attr = perf_header_attr__new(&f_attr.attr);
@@ -497,7 +894,8 @@ int perf_header__read(struct perf_header *self, int fd)
497 lseek(fd, f_attr.ids.offset, SEEK_SET); 894 lseek(fd, f_attr.ids.offset, SEEK_SET);
498 895
499 for (j = 0; j < nr_ids; j++) { 896 for (j = 0; j < nr_ids; j++) {
500 do_read(fd, &f_id, sizeof(f_id)); 897 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
898 goto out_errno;
501 899
502 if (perf_header_attr__add_id(attr, f_id) < 0) { 900 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr); 901 perf_header_attr__delete(attr);
@@ -517,7 +915,9 @@ int perf_header__read(struct perf_header *self, int fd)
517 events = malloc(f_header.event_types.size); 915 events = malloc(f_header.event_types.size);
518 if (events == NULL) 916 if (events == NULL)
519 return -ENOMEM; 917 return -ENOMEM;
520 do_read(fd, events, f_header.event_types.size); 918 if (perf_header__getbuffer64(self, fd, events,
919 f_header.event_types.size))
920 goto out_errno;
521 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 921 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
522 } 922 }
523 923
@@ -527,6 +927,8 @@ int perf_header__read(struct perf_header *self, int fd)
527 927
528 self->frozen = 1; 928 self->frozen = 1;
529 return 0; 929 return 0;
930out_errno:
931 return -errno;
530} 932}
531 933
532u64 perf_header__sample_type(struct perf_header *header) 934u64 perf_header__sample_type(struct perf_header *header)
@@ -546,11 +948,42 @@ u64 perf_header__sample_type(struct perf_header *header)
546 return type; 948 return type;
547} 949}
548 950
951bool perf_header__sample_id_all(const struct perf_header *header)
952{
953 bool value = false, first = true;
954 int i;
955
956 for (i = 0; i < header->attrs; i++) {
957 struct perf_header_attr *attr = header->attr[i];
958
959 if (first) {
960 value = attr->attr.sample_id_all;
961 first = false;
962 } else if (value != attr->attr.sample_id_all)
963 die("non matching sample_id_all");
964 }
965
966 return value;
967}
968
549struct perf_event_attr * 969struct perf_event_attr *
550perf_header__find_attr(u64 id, struct perf_header *header) 970perf_header__find_attr(u64 id, struct perf_header *header)
551{ 971{
552 int i; 972 int i;
553 973
974 /*
975 * We set id to -1 if the data file doesn't contain sample
976 * ids. This can happen when the data file contains one type
977 * of event and in that case, the header can still store the
978 * event attribute information. Check for this and avoid
979 * walking through the entire list of ids which may be large.
980 */
981 if (id == -1ULL) {
982 if (header->attrs > 0)
983 return &header->attr[0]->attr;
984 return NULL;
985 }
986
554 for (i = 0; i < header->attrs; i++) { 987 for (i = 0; i < header->attrs; i++) {
555 struct perf_header_attr *attr = header->attr[i]; 988 struct perf_header_attr *attr = header->attr[i];
556 int j; 989 int j;
@@ -563,3 +996,237 @@ perf_header__find_attr(u64 id, struct perf_header *header)
563 996
564 return NULL; 997 return NULL;
565} 998}
999
1000int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
1001 event__handler_t process,
1002 struct perf_session *session)
1003{
1004 event_t *ev;
1005 size_t size;
1006 int err;
1007
1008 size = sizeof(struct perf_event_attr);
1009 size = ALIGN(size, sizeof(u64));
1010 size += sizeof(struct perf_event_header);
1011 size += ids * sizeof(u64);
1012
1013 ev = malloc(size);
1014
1015 if (ev == NULL)
1016 return -ENOMEM;
1017
1018 ev->attr.attr = *attr;
1019 memcpy(ev->attr.id, id, ids * sizeof(u64));
1020
1021 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
1022 ev->attr.header.size = size;
1023
1024 err = process(ev, NULL, session);
1025
1026 free(ev);
1027
1028 return err;
1029}
1030
1031int event__synthesize_attrs(struct perf_header *self, event__handler_t process,
1032 struct perf_session *session)
1033{
1034 struct perf_header_attr *attr;
1035 int i, err = 0;
1036
1037 for (i = 0; i < self->attrs; i++) {
1038 attr = self->attr[i];
1039
1040 err = event__synthesize_attr(&attr->attr, attr->ids, attr->id,
1041 process, session);
1042 if (err) {
1043 pr_debug("failed to create perf header attribute\n");
1044 return err;
1045 }
1046 }
1047
1048 return err;
1049}
1050
1051int event__process_attr(event_t *self, struct perf_session *session)
1052{
1053 struct perf_header_attr *attr;
1054 unsigned int i, ids, n_ids;
1055
1056 attr = perf_header_attr__new(&self->attr.attr);
1057 if (attr == NULL)
1058 return -ENOMEM;
1059
1060 ids = self->header.size;
1061 ids -= (void *)&self->attr.id - (void *)self;
1062 n_ids = ids / sizeof(u64);
1063
1064 for (i = 0; i < n_ids; i++) {
1065 if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) {
1066 perf_header_attr__delete(attr);
1067 return -ENOMEM;
1068 }
1069 }
1070
1071 if (perf_header__add_attr(&session->header, attr) < 0) {
1072 perf_header_attr__delete(attr);
1073 return -ENOMEM;
1074 }
1075
1076 perf_session__update_sample_type(session);
1077
1078 return 0;
1079}
1080
1081int event__synthesize_event_type(u64 event_id, char *name,
1082 event__handler_t process,
1083 struct perf_session *session)
1084{
1085 event_t ev;
1086 size_t size = 0;
1087 int err = 0;
1088
1089 memset(&ev, 0, sizeof(ev));
1090
1091 ev.event_type.event_type.event_id = event_id;
1092 memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
1093 strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
1094
1095 ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
1096 size = strlen(name);
1097 size = ALIGN(size, sizeof(u64));
1098 ev.event_type.header.size = sizeof(ev.event_type) -
1099 (sizeof(ev.event_type.event_type.name) - size);
1100
1101 err = process(&ev, NULL, session);
1102
1103 return err;
1104}
1105
1106int event__synthesize_event_types(event__handler_t process,
1107 struct perf_session *session)
1108{
1109 struct perf_trace_event_type *type;
1110 int i, err = 0;
1111
1112 for (i = 0; i < event_count; i++) {
1113 type = &events[i];
1114
1115 err = event__synthesize_event_type(type->event_id, type->name,
1116 process, session);
1117 if (err) {
1118 pr_debug("failed to create perf header event type\n");
1119 return err;
1120 }
1121 }
1122
1123 return err;
1124}
1125
1126int event__process_event_type(event_t *self,
1127 struct perf_session *session __unused)
1128{
1129 if (perf_header__push_event(self->event_type.event_type.event_id,
1130 self->event_type.event_type.name) < 0)
1131 return -ENOMEM;
1132
1133 return 0;
1134}
1135
1136int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
1137 event__handler_t process,
1138 struct perf_session *session __unused)
1139{
1140 event_t ev;
1141 ssize_t size = 0, aligned_size = 0, padding;
1142 int err = 0;
1143
1144 memset(&ev, 0, sizeof(ev));
1145
1146 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1147 size = read_tracing_data_size(fd, pattrs);
1148 if (size <= 0)
1149 return size;
1150 aligned_size = ALIGN(size, sizeof(u64));
1151 padding = aligned_size - size;
1152 ev.tracing_data.header.size = sizeof(ev.tracing_data);
1153 ev.tracing_data.size = aligned_size;
1154
1155 process(&ev, NULL, session);
1156
1157 err = read_tracing_data(fd, pattrs);
1158 write_padded(fd, NULL, 0, padding);
1159
1160 return aligned_size;
1161}
1162
1163int event__process_tracing_data(event_t *self,
1164 struct perf_session *session)
1165{
1166 ssize_t size_read, padding, size = self->tracing_data.size;
1167 off_t offset = lseek(session->fd, 0, SEEK_CUR);
1168 char buf[BUFSIZ];
1169
1170 /* setup for reading amidst mmap */
1171 lseek(session->fd, offset + sizeof(struct tracing_data_event),
1172 SEEK_SET);
1173
1174 size_read = trace_report(session->fd, session->repipe);
1175
1176 padding = ALIGN(size_read, sizeof(u64)) - size_read;
1177
1178 if (read(session->fd, buf, padding) < 0)
1179 die("reading input file");
1180 if (session->repipe) {
1181 int retw = write(STDOUT_FILENO, buf, padding);
1182 if (retw <= 0 || retw != padding)
1183 die("repiping tracing data padding");
1184 }
1185
1186 if (size_read + padding != size)
1187 die("tracing data size mismatch");
1188
1189 return size_read + padding;
1190}
1191
1192int event__synthesize_build_id(struct dso *pos, u16 misc,
1193 event__handler_t process,
1194 struct machine *machine,
1195 struct perf_session *session)
1196{
1197 event_t ev;
1198 size_t len;
1199 int err = 0;
1200
1201 if (!pos->hit)
1202 return err;
1203
1204 memset(&ev, 0, sizeof(ev));
1205
1206 len = pos->long_name_len + 1;
1207 len = ALIGN(len, NAME_ALIGN);
1208 memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
1209 ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
1210 ev.build_id.header.misc = misc;
1211 ev.build_id.pid = machine->pid;
1212 ev.build_id.header.size = sizeof(ev.build_id) + len;
1213 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
1214
1215 err = process(&ev, NULL, session);
1216
1217 return err;
1218}
1219
1220int event__process_build_id(event_t *self,
1221 struct perf_session *session)
1222{
1223 __event_process_build_id(&self->build_id,
1224 self->build_id.filename,
1225 session);
1226 return 0;
1227}
1228
1229void disable_buildid_cache(void)
1230{
1231 no_buildid_cache = true;
1232}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d118d05d3abe..33f16be7b72f 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -5,6 +5,7 @@
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"
8#include "event.h"
8 9
9#include <linux/bitmap.h> 10#include <linux/bitmap.h>
10 11
@@ -38,6 +39,11 @@ struct perf_file_header {
38 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); 39 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
39}; 40};
40 41
42struct perf_pipe_file_header {
43 u64 magic;
44 u64 size;
45};
46
41struct perf_header; 47struct perf_header;
42 48
43int perf_file_header__read(struct perf_file_header *self, 49int perf_file_header__read(struct perf_file_header *self,
@@ -46,6 +52,7 @@ int perf_file_header__read(struct perf_file_header *self,
46struct perf_header { 52struct perf_header {
47 int frozen; 53 int frozen;
48 int attrs, size; 54 int attrs, size;
55 bool needs_swap;
49 struct perf_header_attr **attr; 56 struct perf_header_attr **attr;
50 s64 attr_offset; 57 s64 attr_offset;
51 u64 data_offset; 58 u64 data_offset;
@@ -58,13 +65,14 @@ struct perf_header {
58int perf_header__init(struct perf_header *self); 65int perf_header__init(struct perf_header *self);
59void perf_header__exit(struct perf_header *self); 66void perf_header__exit(struct perf_header *self);
60 67
61int perf_header__read(struct perf_header *self, int fd); 68int perf_header__read(struct perf_session *session, int fd);
62int perf_header__write(struct perf_header *self, int fd, bool at_exit); 69int perf_header__write(struct perf_header *self, int fd, bool at_exit);
70int perf_header__write_pipe(int fd);
63 71
64int perf_header__add_attr(struct perf_header *self, 72int perf_header__add_attr(struct perf_header *self,
65 struct perf_header_attr *attr); 73 struct perf_header_attr *attr);
66 74
67void perf_header__push_event(u64 id, const char *name); 75int perf_header__push_event(u64 id, const char *name);
68char *perf_header__find_event(u64 id); 76char *perf_header__find_event(u64 id);
69 77
70struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); 78struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
@@ -73,13 +81,48 @@ void perf_header_attr__delete(struct perf_header_attr *self);
73int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); 81int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
74 82
75u64 perf_header__sample_type(struct perf_header *header); 83u64 perf_header__sample_type(struct perf_header *header);
84bool perf_header__sample_id_all(const struct perf_header *header);
76struct perf_event_attr * 85struct perf_event_attr *
77perf_header__find_attr(u64 id, struct perf_header *header); 86perf_header__find_attr(u64 id, struct perf_header *header);
78void perf_header__set_feat(struct perf_header *self, int feat); 87void perf_header__set_feat(struct perf_header *self, int feat);
88void perf_header__clear_feat(struct perf_header *self, int feat);
79bool perf_header__has_feat(const struct perf_header *self, int feat); 89bool perf_header__has_feat(const struct perf_header *self, int feat);
80 90
81int perf_header__process_sections(struct perf_header *self, int fd, 91int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self, 92 int (*process)(struct perf_file_section *self,
93 struct perf_header *ph,
83 int feat, int fd)); 94 int feat, int fd));
84 95
96int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
97 const char *name, bool is_kallsyms);
98int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
99
100int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
101 event__handler_t process,
102 struct perf_session *session);
103int event__synthesize_attrs(struct perf_header *self,
104 event__handler_t process,
105 struct perf_session *session);
106int event__process_attr(event_t *self, struct perf_session *session);
107
108int event__synthesize_event_type(u64 event_id, char *name,
109 event__handler_t process,
110 struct perf_session *session);
111int event__synthesize_event_types(event__handler_t process,
112 struct perf_session *session);
113int event__process_event_type(event_t *self,
114 struct perf_session *session);
115
116int event__synthesize_tracing_data(int fd, struct list_head *pattrs,
117 event__handler_t process,
118 struct perf_session *session);
119int event__process_tracing_data(event_t *self,
120 struct perf_session *session);
121
122int event__synthesize_build_id(struct dso *pos, u16 misc,
123 event__handler_t process,
124 struct machine *machine,
125 struct perf_session *session);
126int event__process_build_id(event_t *self, struct perf_session *session);
127
85#endif /* __PERF_HEADER_H */ 128#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
index fbb00978b2e2..6f2975a00358 100644
--- a/tools/perf/util/help.c
+++ b/tools/perf/util/help.c
@@ -4,28 +4,6 @@
4#include "levenshtein.h" 4#include "levenshtein.h"
5#include "help.h" 5#include "help.h"
6 6
7/* most GUI terminals set COLUMNS (although some don't export it) */
8static int term_columns(void)
9{
10 char *col_string = getenv("COLUMNS");
11 int n_cols;
12
13 if (col_string && (n_cols = atoi(col_string)) > 0)
14 return n_cols;
15
16#ifdef TIOCGWINSZ
17 {
18 struct winsize ws;
19 if (!ioctl(1, TIOCGWINSZ, &ws)) {
20 if (ws.ws_col)
21 return ws.ws_col;
22 }
23 }
24#endif
25
26 return 80;
27}
28
29void add_cmdname(struct cmdnames *cmds, const char *name, size_t len) 7void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
30{ 8{
31 struct cmdname *ent = malloc(sizeof(*ent) + len + 1); 9 struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
@@ -96,9 +74,13 @@ static void pretty_print_string_list(struct cmdnames *cmds, int longest)
96{ 74{
97 int cols = 1, rows; 75 int cols = 1, rows;
98 int space = longest + 1; /* min 1 SP between words */ 76 int space = longest + 1; /* min 1 SP between words */
99 int max_cols = term_columns() - 1; /* don't print *on* the edge */ 77 struct winsize win;
78 int max_cols;
100 int i, j; 79 int i, j;
101 80
81 get_term_dimensions(&win);
82 max_cols = win.ws_col - 1; /* don't print *on* the edge */
83
102 if (space < max_cols) 84 if (space < max_cols)
103 cols = max_cols / space; 85 cols = max_cols / space;
104 rows = (cmds->cnt + cols - 1) / cols; 86 rows = (cmds->cnt + cols - 1) / cols;
@@ -324,7 +306,7 @@ const char *help_unknown_cmd(const char *cmd)
324 306
325 main_cmds.names[0] = NULL; 307 main_cmds.names[0] = NULL;
326 clean_cmdnames(&main_cmds); 308 clean_cmdnames(&main_cmds);
327 fprintf(stderr, "WARNING: You called a Git program named '%s', " 309 fprintf(stderr, "WARNING: You called a perf program named '%s', "
328 "which does not exist.\n" 310 "which does not exist.\n"
329 "Continuing under the assumption that you meant '%s'\n", 311 "Continuing under the assumption that you meant '%s'\n",
330 cmd, assumed); 312 cmd, assumed);
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e8daf5ca6fd2..c749ba6136a0 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1,33 +1,141 @@
1#include "util.h"
2#include "build-id.h"
1#include "hist.h" 3#include "hist.h"
2#include "session.h" 4#include "session.h"
3#include "sort.h" 5#include "sort.h"
4#include <math.h> 6#include <math.h>
5 7
8enum hist_filter {
9 HIST_FILTER__DSO,
10 HIST_FILTER__THREAD,
11 HIST_FILTER__PARENT,
12};
13
6struct callchain_param callchain_param = { 14struct callchain_param callchain_param = {
7 .mode = CHAIN_GRAPH_REL, 15 .mode = CHAIN_GRAPH_REL,
8 .min_percent = 0.5 16 .min_percent = 0.5
9}; 17};
10 18
19u16 hists__col_len(struct hists *self, enum hist_column col)
20{
21 return self->col_len[col];
22}
23
24void hists__set_col_len(struct hists *self, enum hist_column col, u16 len)
25{
26 self->col_len[col] = len;
27}
28
29bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len)
30{
31 if (len > hists__col_len(self, col)) {
32 hists__set_col_len(self, col, len);
33 return true;
34 }
35 return false;
36}
37
38static void hists__reset_col_len(struct hists *self)
39{
40 enum hist_column col;
41
42 for (col = 0; col < HISTC_NR_COLS; ++col)
43 hists__set_col_len(self, col, 0);
44}
45
46static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
47{
48 u16 len;
49
50 if (h->ms.sym)
51 hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
52
53 len = thread__comm_len(h->thread);
54 if (hists__new_col_len(self, HISTC_COMM, len))
55 hists__set_col_len(self, HISTC_THREAD, len + 6);
56
57 if (h->ms.map) {
58 len = dso__name_len(h->ms.map->dso);
59 hists__new_col_len(self, HISTC_DSO, len);
60 }
61}
62
63static void hist_entry__add_cpumode_period(struct hist_entry *self,
64 unsigned int cpumode, u64 period)
65{
66 switch (cpumode) {
67 case PERF_RECORD_MISC_KERNEL:
68 self->period_sys += period;
69 break;
70 case PERF_RECORD_MISC_USER:
71 self->period_us += period;
72 break;
73 case PERF_RECORD_MISC_GUEST_KERNEL:
74 self->period_guest_sys += period;
75 break;
76 case PERF_RECORD_MISC_GUEST_USER:
77 self->period_guest_us += period;
78 break;
79 default:
80 break;
81 }
82}
83
11/* 84/*
12 * histogram, sorted on item, collects counts 85 * histogram, sorted on item, collects periods
13 */ 86 */
14 87
15struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, 88static struct hist_entry *hist_entry__new(struct hist_entry *template)
16 struct addr_location *al, 89{
17 struct symbol *sym_parent, 90 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
18 u64 count, bool *hit) 91 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
92
93 if (self != NULL) {
94 *self = *template;
95 self->nr_events = 1;
96 if (self->ms.map)
97 self->ms.map->referenced = true;
98 if (symbol_conf.use_callchain)
99 callchain_init(self->callchain);
100 }
101
102 return self;
103}
104
105static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h)
106{
107 if (!h->filtered) {
108 hists__calc_col_len(self, h);
109 ++self->nr_entries;
110 }
111}
112
113static u8 symbol__parent_filter(const struct symbol *parent)
114{
115 if (symbol_conf.exclude_other && parent == NULL)
116 return 1 << HIST_FILTER__PARENT;
117 return 0;
118}
119
120struct hist_entry *__hists__add_entry(struct hists *self,
121 struct addr_location *al,
122 struct symbol *sym_parent, u64 period)
19{ 123{
20 struct rb_node **p = &self->hists.rb_node; 124 struct rb_node **p = &self->entries.rb_node;
21 struct rb_node *parent = NULL; 125 struct rb_node *parent = NULL;
22 struct hist_entry *he; 126 struct hist_entry *he;
23 struct hist_entry entry = { 127 struct hist_entry entry = {
24 .thread = al->thread, 128 .thread = al->thread,
25 .map = al->map, 129 .ms = {
26 .sym = al->sym, 130 .map = al->map,
131 .sym = al->sym,
132 },
133 .cpu = al->cpu,
27 .ip = al->addr, 134 .ip = al->addr,
28 .level = al->level, 135 .level = al->level,
29 .count = count, 136 .period = period,
30 .parent = sym_parent, 137 .parent = sym_parent,
138 .filtered = symbol__parent_filter(sym_parent),
31 }; 139 };
32 int cmp; 140 int cmp;
33 141
@@ -38,8 +146,9 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
38 cmp = hist_entry__cmp(&entry, he); 146 cmp = hist_entry__cmp(&entry, he);
39 147
40 if (!cmp) { 148 if (!cmp) {
41 *hit = true; 149 he->period += period;
42 return he; 150 ++he->nr_events;
151 goto out;
43 } 152 }
44 153
45 if (cmp < 0) 154 if (cmp < 0)
@@ -48,13 +157,14 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,
48 p = &(*p)->rb_right; 157 p = &(*p)->rb_right;
49 } 158 }
50 159
51 he = malloc(sizeof(*he)); 160 he = hist_entry__new(&entry);
52 if (!he) 161 if (!he)
53 return NULL; 162 return NULL;
54 *he = entry;
55 rb_link_node(&he->rb_node, parent, p); 163 rb_link_node(&he->rb_node, parent, p);
56 rb_insert_color(&he->rb_node, &self->hists); 164 rb_insert_color(&he->rb_node, &self->entries);
57 *hit = false; 165 hists__inc_nr_entries(self, he);
166out:
167 hist_entry__add_cpumode_period(he, al->cpumode, period);
58 return he; 168 return he;
59} 169}
60 170
@@ -65,7 +175,7 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
65 int64_t cmp = 0; 175 int64_t cmp = 0;
66 176
67 list_for_each_entry(se, &hist_entry__sort_list, list) { 177 list_for_each_entry(se, &hist_entry__sort_list, list) {
68 cmp = se->cmp(left, right); 178 cmp = se->se_cmp(left, right);
69 if (cmp) 179 if (cmp)
70 break; 180 break;
71 } 181 }
@@ -82,7 +192,7 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
82 list_for_each_entry(se, &hist_entry__sort_list, list) { 192 list_for_each_entry(se, &hist_entry__sort_list, list) {
83 int64_t (*f)(struct hist_entry *, struct hist_entry *); 193 int64_t (*f)(struct hist_entry *, struct hist_entry *);
84 194
85 f = se->collapse ?: se->cmp; 195 f = se->se_collapse ?: se->se_cmp;
86 196
87 cmp = f(left, right); 197 cmp = f(left, right);
88 if (cmp) 198 if (cmp)
@@ -101,7 +211,7 @@ void hist_entry__free(struct hist_entry *he)
101 * collapse the histogram 211 * collapse the histogram
102 */ 212 */
103 213
104static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he) 214static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
105{ 215{
106 struct rb_node **p = &root->rb_node; 216 struct rb_node **p = &root->rb_node;
107 struct rb_node *parent = NULL; 217 struct rb_node *parent = NULL;
@@ -115,9 +225,11 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
115 cmp = hist_entry__collapse(iter, he); 225 cmp = hist_entry__collapse(iter, he);
116 226
117 if (!cmp) { 227 if (!cmp) {
118 iter->count += he->count; 228 iter->period += he->period;
229 if (symbol_conf.use_callchain)
230 callchain_merge(iter->callchain, he->callchain);
119 hist_entry__free(he); 231 hist_entry__free(he);
120 return; 232 return false;
121 } 233 }
122 234
123 if (cmp < 0) 235 if (cmp < 0)
@@ -128,9 +240,10 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
128 240
129 rb_link_node(&he->rb_node, parent, p); 241 rb_link_node(&he->rb_node, parent, p);
130 rb_insert_color(&he->rb_node, root); 242 rb_insert_color(&he->rb_node, root);
243 return true;
131} 244}
132 245
133void perf_session__collapse_resort(struct perf_session *self) 246void hists__collapse_resort(struct hists *self)
134{ 247{
135 struct rb_root tmp; 248 struct rb_root tmp;
136 struct rb_node *next; 249 struct rb_node *next;
@@ -140,72 +253,77 @@ void perf_session__collapse_resort(struct perf_session *self)
140 return; 253 return;
141 254
142 tmp = RB_ROOT; 255 tmp = RB_ROOT;
143 next = rb_first(&self->hists); 256 next = rb_first(&self->entries);
257 self->nr_entries = 0;
258 hists__reset_col_len(self);
144 259
145 while (next) { 260 while (next) {
146 n = rb_entry(next, struct hist_entry, rb_node); 261 n = rb_entry(next, struct hist_entry, rb_node);
147 next = rb_next(&n->rb_node); 262 next = rb_next(&n->rb_node);
148 263
149 rb_erase(&n->rb_node, &self->hists); 264 rb_erase(&n->rb_node, &self->entries);
150 collapse__insert_entry(&tmp, n); 265 if (collapse__insert_entry(&tmp, n))
266 hists__inc_nr_entries(self, n);
151 } 267 }
152 268
153 self->hists = tmp; 269 self->entries = tmp;
154} 270}
155 271
156/* 272/*
157 * reverse the map, sort on count. 273 * reverse the map, sort on period.
158 */ 274 */
159 275
160static void perf_session__insert_output_hist_entry(struct rb_root *root, 276static void __hists__insert_output_entry(struct rb_root *entries,
161 struct hist_entry *he, 277 struct hist_entry *he,
162 u64 min_callchain_hits) 278 u64 min_callchain_hits)
163{ 279{
164 struct rb_node **p = &root->rb_node; 280 struct rb_node **p = &entries->rb_node;
165 struct rb_node *parent = NULL; 281 struct rb_node *parent = NULL;
166 struct hist_entry *iter; 282 struct hist_entry *iter;
167 283
168 if (symbol_conf.use_callchain) 284 if (symbol_conf.use_callchain)
169 callchain_param.sort(&he->sorted_chain, &he->callchain, 285 callchain_param.sort(&he->sorted_chain, he->callchain,
170 min_callchain_hits, &callchain_param); 286 min_callchain_hits, &callchain_param);
171 287
172 while (*p != NULL) { 288 while (*p != NULL) {
173 parent = *p; 289 parent = *p;
174 iter = rb_entry(parent, struct hist_entry, rb_node); 290 iter = rb_entry(parent, struct hist_entry, rb_node);
175 291
176 if (he->count > iter->count) 292 if (he->period > iter->period)
177 p = &(*p)->rb_left; 293 p = &(*p)->rb_left;
178 else 294 else
179 p = &(*p)->rb_right; 295 p = &(*p)->rb_right;
180 } 296 }
181 297
182 rb_link_node(&he->rb_node, parent, p); 298 rb_link_node(&he->rb_node, parent, p);
183 rb_insert_color(&he->rb_node, root); 299 rb_insert_color(&he->rb_node, entries);
184} 300}
185 301
186void perf_session__output_resort(struct perf_session *self, u64 total_samples) 302void hists__output_resort(struct hists *self)
187{ 303{
188 struct rb_root tmp; 304 struct rb_root tmp;
189 struct rb_node *next; 305 struct rb_node *next;
190 struct hist_entry *n; 306 struct hist_entry *n;
191 u64 min_callchain_hits; 307 u64 min_callchain_hits;
192 308
193 min_callchain_hits = 309 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100);
194 total_samples * (callchain_param.min_percent / 100);
195 310
196 tmp = RB_ROOT; 311 tmp = RB_ROOT;
197 next = rb_first(&self->hists); 312 next = rb_first(&self->entries);
313
314 self->nr_entries = 0;
315 hists__reset_col_len(self);
198 316
199 while (next) { 317 while (next) {
200 n = rb_entry(next, struct hist_entry, rb_node); 318 n = rb_entry(next, struct hist_entry, rb_node);
201 next = rb_next(&n->rb_node); 319 next = rb_next(&n->rb_node);
202 320
203 rb_erase(&n->rb_node, &self->hists); 321 rb_erase(&n->rb_node, &self->entries);
204 perf_session__insert_output_hist_entry(&tmp, n, 322 __hists__insert_output_entry(&tmp, n, min_callchain_hits);
205 min_callchain_hits); 323 hists__inc_nr_entries(self, n);
206 } 324 }
207 325
208 self->hists = tmp; 326 self->entries = tmp;
209} 327}
210 328
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 329static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -237,8 +355,8 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
237} 355}
238 356
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 357static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count, 358 int depth, int depth_mask, int period,
241 u64 total_samples, int hits, 359 u64 total_samples, u64 hits,
242 int left_margin) 360 int left_margin)
243{ 361{
244 int i; 362 int i;
@@ -250,7 +368,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
250 ret += fprintf(fp, "|"); 368 ret += fprintf(fp, "|");
251 else 369 else
252 ret += fprintf(fp, " "); 370 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) { 371 if (!period && i == depth - 1) {
254 double percent; 372 double percent;
255 373
256 percent = hits * 100.0 / total_samples; 374 percent = hits * 100.0 / total_samples;
@@ -258,8 +376,8 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
258 } else 376 } else
259 ret += fprintf(fp, "%s", " "); 377 ret += fprintf(fp, "%s", " ");
260 } 378 }
261 if (chain->sym) 379 if (chain->ms.sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name); 380 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
263 else 381 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); 382 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265 383
@@ -278,7 +396,7 @@ static void init_rem_hits(void)
278 } 396 }
279 397
280 strcpy(rem_sq_bracket->name, "[...]"); 398 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket; 399 rem_hits.ms.sym = rem_sq_bracket;
282} 400}
283 401
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 402static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
@@ -293,6 +411,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
293 u64 remaining; 411 u64 remaining;
294 size_t ret = 0; 412 size_t ret = 0;
295 int i; 413 int i;
414 uint entries_printed = 0;
296 415
297 if (callchain_param.mode == CHAIN_GRAPH_REL) 416 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit; 417 new_total = self->children_hit;
@@ -321,15 +440,13 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
321 new_depth_mask &= ~(1 << (depth - 1)); 440 new_depth_mask &= ~(1 << (depth - 1));
322 441
323 /* 442 /*
324 * But we keep the older depth mask for the line seperator 443 * But we keep the older depth mask for the line separator
325 * to keep the level link until we reach the last child 444 * to keep the level link until we reach the last child
326 */ 445 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 446 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin); 447 left_margin);
329 i = 0; 448 i = 0;
330 list_for_each_entry(chain, &child->val, list) { 449 list_for_each_entry(chain, &child->val, list) {
331 if (chain->ip >= PERF_CONTEXT_MAX)
332 continue;
333 ret += ipchain__fprintf_graph(fp, chain, depth, 450 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++, 451 new_depth_mask, i++,
335 new_total, 452 new_total,
@@ -341,6 +458,8 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
341 new_depth_mask | (1 << depth), 458 new_depth_mask | (1 << depth),
342 left_margin); 459 left_margin);
343 node = next; 460 node = next;
461 if (++entries_printed == callchain_param.print_limit)
462 break;
344 } 463 }
345 464
346 if (callchain_param.mode == CHAIN_GRAPH_REL && 465 if (callchain_param.mode == CHAIN_GRAPH_REL &&
@@ -366,11 +485,9 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
366 bool printed = false; 485 bool printed = false;
367 int i = 0; 486 int i = 0;
368 int ret = 0; 487 int ret = 0;
488 u32 entries_printed = 0;
369 489
370 list_for_each_entry(chain, &self->val, list) { 490 list_for_each_entry(chain, &self->val, list) {
371 if (chain->ip >= PERF_CONTEXT_MAX)
372 continue;
373
374 if (!i++ && sort__first_dimension == SORT_SYM) 491 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue; 492 continue;
376 493
@@ -385,10 +502,13 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
385 } else 502 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin); 503 ret += callchain__fprintf_left_margin(fp, left_margin);
387 504
388 if (chain->sym) 505 if (chain->ms.sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name); 506 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
390 else 507 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 508 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
509
510 if (++entries_printed == callchain_param.print_limit)
511 break;
392 } 512 }
393 513
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 514 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
@@ -411,8 +531,8 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
411 list_for_each_entry(chain, &self->val, list) { 531 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX) 532 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue; 533 continue;
414 if (chain->sym) 534 if (chain->ms.sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name); 535 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
416 else 536 else
417 ret += fprintf(fp, " %p\n", 537 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip); 538 (void *)(long)chain->ip);
@@ -427,6 +547,7 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
427 struct rb_node *rb_node; 547 struct rb_node *rb_node;
428 struct callchain_node *chain; 548 struct callchain_node *chain;
429 size_t ret = 0; 549 size_t ret = 0;
550 u32 entries_printed = 0;
430 551
431 rb_node = rb_first(&self->sorted_chain); 552 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) { 553 while (rb_node) {
@@ -449,55 +570,89 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
449 break; 570 break;
450 } 571 }
451 ret += fprintf(fp, "\n"); 572 ret += fprintf(fp, "\n");
573 if (++entries_printed == callchain_param.print_limit)
574 break;
452 rb_node = rb_next(rb_node); 575 rb_node = rb_next(rb_node);
453 } 576 }
454 577
455 return ret; 578 return ret;
456} 579}
457 580
458static size_t hist_entry__fprintf(struct hist_entry *self, 581int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
459 struct perf_session *session, 582 struct hists *hists, struct hists *pair_hists,
460 struct perf_session *pair_session, 583 bool show_displacement, long displacement,
461 bool show_displacement, 584 bool color, u64 session_total)
462 long displacement, FILE *fp)
463{ 585{
464 struct sort_entry *se; 586 struct sort_entry *se;
465 u64 count, total; 587 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
466 const char *sep = symbol_conf.field_sep; 588 const char *sep = symbol_conf.field_sep;
467 size_t ret; 589 int ret;
468 590
469 if (symbol_conf.exclude_other && !self->parent) 591 if (symbol_conf.exclude_other && !self->parent)
470 return 0; 592 return 0;
471 593
472 if (pair_session) { 594 if (pair_hists) {
473 count = self->pair ? self->pair->count : 0; 595 period = self->pair ? self->pair->period : 0;
474 total = pair_session->events_stats.total; 596 total = pair_hists->stats.total_period;
597 period_sys = self->pair ? self->pair->period_sys : 0;
598 period_us = self->pair ? self->pair->period_us : 0;
599 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
600 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
475 } else { 601 } else {
476 count = self->count; 602 period = self->period;
477 total = session->events_stats.total; 603 total = session_total;
604 period_sys = self->period_sys;
605 period_us = self->period_us;
606 period_guest_sys = self->period_guest_sys;
607 period_guest_us = self->period_guest_us;
478 } 608 }
479 609
480 if (total) 610 if (total) {
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%", 611 if (color)
482 (count * 100.0) / total); 612 ret = percent_color_snprintf(s, size,
483 else 613 sep ? "%.2f" : " %6.2f%%",
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count); 614 (period * 100.0) / total);
615 else
616 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
617 (period * 100.0) / total);
618 if (symbol_conf.show_cpu_utilization) {
619 ret += percent_color_snprintf(s + ret, size - ret,
620 sep ? "%.2f" : " %6.2f%%",
621 (period_sys * 100.0) / total);
622 ret += percent_color_snprintf(s + ret, size - ret,
623 sep ? "%.2f" : " %6.2f%%",
624 (period_us * 100.0) / total);
625 if (perf_guest) {
626 ret += percent_color_snprintf(s + ret,
627 size - ret,
628 sep ? "%.2f" : " %6.2f%%",
629 (period_guest_sys * 100.0) /
630 total);
631 ret += percent_color_snprintf(s + ret,
632 size - ret,
633 sep ? "%.2f" : " %6.2f%%",
634 (period_guest_us * 100.0) /
635 total);
636 }
637 }
638 } else
639 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period);
485 640
486 if (symbol_conf.show_nr_samples) { 641 if (symbol_conf.show_nr_samples) {
487 if (sep) 642 if (sep)
488 fprintf(fp, "%c%lld", *sep, count); 643 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period);
489 else 644 else
490 fprintf(fp, "%11lld", count); 645 ret += snprintf(s + ret, size - ret, "%11lld", period);
491 } 646 }
492 647
493 if (pair_session) { 648 if (pair_hists) {
494 char bf[32]; 649 char bf[32];
495 double old_percent = 0, new_percent = 0, diff; 650 double old_percent = 0, new_percent = 0, diff;
496 651
497 if (total > 0) 652 if (total > 0)
498 old_percent = (count * 100.0) / total; 653 old_percent = (period * 100.0) / total;
499 if (session->events_stats.total > 0) 654 if (session_total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total; 655 new_percent = (self->period * 100.0) / session_total;
501 656
502 diff = new_percent - old_percent; 657 diff = new_percent - old_percent;
503 658
@@ -507,9 +662,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
507 snprintf(bf, sizeof(bf), " "); 662 snprintf(bf, sizeof(bf), " ");
508 663
509 if (sep) 664 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf); 665 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
511 else 666 else
512 ret += fprintf(fp, "%11.11s", bf); 667 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
513 668
514 if (show_displacement) { 669 if (show_displacement) {
515 if (displacement) 670 if (displacement)
@@ -518,9 +673,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
518 snprintf(bf, sizeof(bf), " "); 673 snprintf(bf, sizeof(bf), " ");
519 674
520 if (sep) 675 if (sep)
521 fprintf(fp, "%c%s", *sep, bf); 676 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
522 else 677 else
523 fprintf(fp, "%6.6s", bf); 678 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
524 } 679 }
525 } 680 }
526 681
@@ -528,32 +683,44 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
528 if (se->elide) 683 if (se->elide)
529 continue; 684 continue;
530 685
531 fprintf(fp, "%s", sep ?: " "); 686 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0); 687 ret += se->se_snprintf(self, s + ret, size - ret,
688 hists__col_len(hists, se->se_width_idx));
533 } 689 }
534 690
535 ret += fprintf(fp, "\n"); 691 return ret;
692}
536 693
537 if (symbol_conf.use_callchain) { 694int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
538 int left_margin = 0; 695 struct hists *pair_hists, bool show_displacement,
696 long displacement, FILE *fp, u64 session_total)
697{
698 char bf[512];
699 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
700 show_displacement, displacement,
701 true, session_total);
702 return fprintf(fp, "%s\n", bf);
703}
539 704
540 if (sort__first_dimension == SORT_COMM) { 705static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se), 706 struct hists *hists, FILE *fp,
542 list); 707 u64 session_total)
543 left_margin = se->width ? *se->width : 0; 708{
544 left_margin -= thread__comm_len(self->thread); 709 int left_margin = 0;
545 }
546 710
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total, 711 if (sort__first_dimension == SORT_COMM) {
548 left_margin); 712 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
713 typeof(*se), list);
714 left_margin = hists__col_len(hists, se->se_width_idx);
715 left_margin -= thread__comm_len(self->thread);
549 } 716 }
550 717
551 return ret; 718 return hist_entry_callchain__fprintf(fp, self, session_total,
719 left_margin);
552} 720}
553 721
554size_t perf_session__fprintf_hists(struct perf_session *self, 722size_t hists__fprintf(struct hists *self, struct hists *pair,
555 struct perf_session *pair, 723 bool show_displacement, FILE *fp)
556 bool show_displacement, FILE *fp)
557{ 724{
558 struct sort_entry *se; 725 struct sort_entry *se;
559 struct rb_node *nd; 726 struct rb_node *nd;
@@ -562,7 +729,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
562 long displacement = 0; 729 long displacement = 0;
563 unsigned int width; 730 unsigned int width;
564 const char *sep = symbol_conf.field_sep; 731 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str; 732 const char *col_width = symbol_conf.col_width_list_str;
566 733
567 init_rem_hits(); 734 init_rem_hits();
568 735
@@ -575,6 +742,24 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
575 fputs(" Samples ", fp); 742 fputs(" Samples ", fp);
576 } 743 }
577 744
745 if (symbol_conf.show_cpu_utilization) {
746 if (sep) {
747 ret += fprintf(fp, "%csys", *sep);
748 ret += fprintf(fp, "%cus", *sep);
749 if (perf_guest) {
750 ret += fprintf(fp, "%cguest sys", *sep);
751 ret += fprintf(fp, "%cguest us", *sep);
752 }
753 } else {
754 ret += fprintf(fp, " sys ");
755 ret += fprintf(fp, " us ");
756 if (perf_guest) {
757 ret += fprintf(fp, " guest sys ");
758 ret += fprintf(fp, " guest us ");
759 }
760 }
761 }
762
578 if (pair) { 763 if (pair) {
579 if (sep) 764 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep); 765 ret += fprintf(fp, "%cDelta", *sep);
@@ -593,22 +778,22 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
593 if (se->elide) 778 if (se->elide)
594 continue; 779 continue;
595 if (sep) { 780 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header); 781 fprintf(fp, "%c%s", *sep, se->se_header);
597 continue; 782 continue;
598 } 783 }
599 width = strlen(se->header); 784 width = strlen(se->se_header);
600 if (se->width) { 785 if (symbol_conf.col_width_list_str) {
601 if (symbol_conf.col_width_list_str) { 786 if (col_width) {
602 if (col_width) { 787 hists__set_col_len(self, se->se_width_idx,
603 *se->width = atoi(col_width); 788 atoi(col_width));
604 col_width = strchr(col_width, ','); 789 col_width = strchr(col_width, ',');
605 if (col_width) 790 if (col_width)
606 ++col_width; 791 ++col_width;
607 }
608 } 792 }
609 width = *se->width = max(*se->width, width);
610 } 793 }
611 fprintf(fp, " %*s", width, se->header); 794 if (!hists__new_col_len(self, se->se_width_idx, width))
795 width = hists__col_len(self, se->se_width_idx);
796 fprintf(fp, " %*s", width, se->se_header);
612 } 797 }
613 fprintf(fp, "\n"); 798 fprintf(fp, "\n");
614 799
@@ -630,10 +815,9 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
630 continue; 815 continue;
631 816
632 fprintf(fp, " "); 817 fprintf(fp, " ");
633 if (se->width) 818 width = hists__col_len(self, se->se_width_idx);
634 width = *se->width; 819 if (width == 0)
635 else 820 width = strlen(se->se_header);
636 width = strlen(se->header);
637 for (i = 0; i < width; i++) 821 for (i = 0; i < width; i++)
638 fprintf(fp, "."); 822 fprintf(fp, ".");
639 } 823 }
@@ -641,7 +825,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
641 fprintf(fp, "\n#\n"); 825 fprintf(fp, "\n#\n");
642 826
643print_entries: 827print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { 828 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 829 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646 830
647 if (show_displacement) { 831 if (show_displacement) {
@@ -653,10 +837,353 @@ print_entries:
653 ++position; 837 ++position;
654 } 838 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement, 839 ret += hist_entry__fprintf(h, self, pair, show_displacement,
656 displacement, fp); 840 displacement, fp, self->stats.total_period);
841
842 if (symbol_conf.use_callchain)
843 ret += hist_entry__fprintf_callchain(h, self, fp,
844 self->stats.total_period);
845 if (h->ms.map == NULL && verbose > 1) {
846 __map_groups__fprintf_maps(&h->thread->mg,
847 MAP__FUNCTION, verbose, fp);
848 fprintf(fp, "%.10s end\n", graph_dotted_line);
849 }
657 } 850 }
658 851
659 free(rem_sq_bracket); 852 free(rem_sq_bracket);
660 853
661 return ret; 854 return ret;
662} 855}
856
857/*
858 * See hists__fprintf to match the column widths
859 */
860unsigned int hists__sort_list_width(struct hists *self)
861{
862 struct sort_entry *se;
863 int ret = 9; /* total % */
864
865 if (symbol_conf.show_cpu_utilization) {
866 ret += 7; /* count_sys % */
867 ret += 6; /* count_us % */
868 if (perf_guest) {
869 ret += 13; /* count_guest_sys % */
870 ret += 12; /* count_guest_us % */
871 }
872 }
873
874 if (symbol_conf.show_nr_samples)
875 ret += 11;
876
877 list_for_each_entry(se, &hist_entry__sort_list, list)
878 if (!se->elide)
879 ret += 2 + hists__col_len(self, se->se_width_idx);
880
881 if (verbose) /* Addr + origin */
882 ret += 3 + BITS_PER_LONG / 4;
883
884 return ret;
885}
886
887static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
888 enum hist_filter filter)
889{
890 h->filtered &= ~(1 << filter);
891 if (h->filtered)
892 return;
893
894 ++self->nr_entries;
895 if (h->ms.unfolded)
896 self->nr_entries += h->nr_rows;
897 h->row_offset = 0;
898 self->stats.total_period += h->period;
899 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
900
901 hists__calc_col_len(self, h);
902}
903
904void hists__filter_by_dso(struct hists *self, const struct dso *dso)
905{
906 struct rb_node *nd;
907
908 self->nr_entries = self->stats.total_period = 0;
909 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
910 hists__reset_col_len(self);
911
912 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
913 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
914
915 if (symbol_conf.exclude_other && !h->parent)
916 continue;
917
918 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
919 h->filtered |= (1 << HIST_FILTER__DSO);
920 continue;
921 }
922
923 hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
924 }
925}
926
927void hists__filter_by_thread(struct hists *self, const struct thread *thread)
928{
929 struct rb_node *nd;
930
931 self->nr_entries = self->stats.total_period = 0;
932 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
933 hists__reset_col_len(self);
934
935 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
936 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
937
938 if (thread != NULL && h->thread != thread) {
939 h->filtered |= (1 << HIST_FILTER__THREAD);
940 continue;
941 }
942
943 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
944 }
945}
946
947static int symbol__alloc_hist(struct symbol *self)
948{
949 struct sym_priv *priv = symbol__priv(self);
950 const int size = (sizeof(*priv->hist) +
951 (self->end - self->start) * sizeof(u64));
952
953 priv->hist = zalloc(size);
954 return priv->hist == NULL ? -1 : 0;
955}
956
957int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
958{
959 unsigned int sym_size, offset;
960 struct symbol *sym = self->ms.sym;
961 struct sym_priv *priv;
962 struct sym_hist *h;
963
964 if (!sym || !self->ms.map)
965 return 0;
966
967 priv = symbol__priv(sym);
968 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
969 return -ENOMEM;
970
971 sym_size = sym->end - sym->start;
972 offset = ip - sym->start;
973
974 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
975
976 if (offset >= sym_size)
977 return 0;
978
979 h = priv->hist;
980 h->sum++;
981 h->ip[offset]++;
982
983 pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
984 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
985 return 0;
986}
987
988static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
989{
990 struct objdump_line *self = malloc(sizeof(*self) + privsize);
991
992 if (self != NULL) {
993 self->offset = offset;
994 self->line = line;
995 }
996
997 return self;
998}
999
1000void objdump_line__free(struct objdump_line *self)
1001{
1002 free(self->line);
1003 free(self);
1004}
1005
1006static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1007{
1008 list_add_tail(&line->node, head);
1009}
1010
1011struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1012 struct objdump_line *pos)
1013{
1014 list_for_each_entry_continue(pos, head, node)
1015 if (pos->offset >= 0)
1016 return pos;
1017
1018 return NULL;
1019}
1020
1021static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1022 struct list_head *head, size_t privsize)
1023{
1024 struct symbol *sym = self->ms.sym;
1025 struct objdump_line *objdump_line;
1026 char *line = NULL, *tmp, *tmp2, *c;
1027 size_t line_len;
1028 s64 line_ip, offset = -1;
1029
1030 if (getline(&line, &line_len, file) < 0)
1031 return -1;
1032
1033 if (!line)
1034 return -1;
1035
1036 while (line_len != 0 && isspace(line[line_len - 1]))
1037 line[--line_len] = '\0';
1038
1039 c = strchr(line, '\n');
1040 if (c)
1041 *c = 0;
1042
1043 line_ip = -1;
1044
1045 /*
1046 * Strip leading spaces:
1047 */
1048 tmp = line;
1049 while (*tmp) {
1050 if (*tmp != ' ')
1051 break;
1052 tmp++;
1053 }
1054
1055 if (*tmp) {
1056 /*
1057 * Parse hexa addresses followed by ':'
1058 */
1059 line_ip = strtoull(tmp, &tmp2, 16);
1060 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1061 line_ip = -1;
1062 }
1063
1064 if (line_ip != -1) {
1065 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1066 end = map__rip_2objdump(self->ms.map, sym->end);
1067
1068 offset = line_ip - start;
1069 if (offset < 0 || (u64)line_ip > end)
1070 offset = -1;
1071 }
1072
1073 objdump_line = objdump_line__new(offset, line, privsize);
1074 if (objdump_line == NULL) {
1075 free(line);
1076 return -1;
1077 }
1078 objdump__add_line(head, objdump_line);
1079
1080 return 0;
1081}
1082
1083int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
1084 size_t privsize)
1085{
1086 struct symbol *sym = self->ms.sym;
1087 struct map *map = self->ms.map;
1088 struct dso *dso = map->dso;
1089 char *filename = dso__build_id_filename(dso, NULL, 0);
1090 bool free_filename = true;
1091 char command[PATH_MAX * 2];
1092 FILE *file;
1093 int err = 0;
1094 u64 len;
1095 char symfs_filename[PATH_MAX];
1096
1097 if (filename) {
1098 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1099 symbol_conf.symfs, filename);
1100 }
1101
1102 if (filename == NULL) {
1103 if (dso->has_build_id) {
1104 pr_err("Can't annotate %s: not enough memory\n",
1105 sym->name);
1106 return -ENOMEM;
1107 }
1108 goto fallback;
1109 } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
1110 strstr(command, "[kernel.kallsyms]") ||
1111 access(symfs_filename, R_OK)) {
1112 free(filename);
1113fallback:
1114 /*
1115 * If we don't have build-ids or the build-id file isn't in the
1116 * cache, or is just a kallsyms file, well, lets hope that this
1117 * DSO is the same as when 'perf record' ran.
1118 */
1119 filename = dso->long_name;
1120 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
1121 symbol_conf.symfs, filename);
1122 free_filename = false;
1123 }
1124
1125 if (dso->origin == DSO__ORIG_KERNEL) {
1126 if (dso->annotate_warned)
1127 goto out_free_filename;
1128 err = -ENOENT;
1129 dso->annotate_warned = 1;
1130 pr_err("Can't annotate %s: No vmlinux file was found in the "
1131 "path\n", sym->name);
1132 goto out_free_filename;
1133 }
1134
1135 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1136 filename, sym->name, map->unmap_ip(map, sym->start),
1137 map->unmap_ip(map, sym->end));
1138
1139 len = sym->end - sym->start;
1140
1141 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1142 dso, dso->long_name, sym, sym->name);
1143
1144 snprintf(command, sizeof(command),
1145 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1146 map__rip_2objdump(map, sym->start),
1147 map__rip_2objdump(map, sym->end),
1148 symfs_filename, filename);
1149
1150 pr_debug("Executing: %s\n", command);
1151
1152 file = popen(command, "r");
1153 if (!file)
1154 goto out_free_filename;
1155
1156 while (!feof(file))
1157 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1158 break;
1159
1160 pclose(file);
1161out_free_filename:
1162 if (free_filename)
1163 free(filename);
1164 return err;
1165}
1166
1167void hists__inc_nr_events(struct hists *self, u32 type)
1168{
1169 ++self->stats.nr_events[0];
1170 ++self->stats.nr_events[type];
1171}
1172
1173size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1174{
1175 int i;
1176 size_t ret = 0;
1177
1178 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1179 const char *name = event__get_event_name(i);
1180
1181 if (!strcmp(name, "UNKNOWN"))
1182 continue;
1183
1184 ret += fprintf(fp, "%16s events: %10d\n", name,
1185 self->stats.nr_events[i]);
1186 }
1187
1188 return ret;
1189}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index e5f99b24048b..ee789856a8c9 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -6,22 +6,145 @@
6 6
7extern struct callchain_param callchain_param; 7extern struct callchain_param callchain_param;
8 8
9struct perf_session;
10struct hist_entry; 9struct hist_entry;
11struct addr_location; 10struct addr_location;
12struct symbol; 11struct symbol;
12struct rb_root;
13 13
14struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, 14struct objdump_line {
15 struct addr_location *al, 15 struct list_head node;
16 struct symbol *parent, 16 s64 offset;
17 u64 count, bool *hit); 17 char *line;
18};
19
20void objdump_line__free(struct objdump_line *self);
21struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
22 struct objdump_line *pos);
23
24struct sym_hist {
25 u64 sum;
26 u64 ip[0];
27};
28
29struct sym_ext {
30 struct rb_node node;
31 double percent;
32 char *path;
33};
34
35struct sym_priv {
36 struct sym_hist *hist;
37 struct sym_ext *ext;
38};
39
40/*
41 * The kernel collects the number of events it couldn't send in a stretch and
42 * when possible sends this number in a PERF_RECORD_LOST event. The number of
43 * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while
44 * total_lost tells exactly how many events the kernel in fact lost, i.e. it is
45 * the sum of all struct lost_event.lost fields reported.
46 *
47 * The total_period is needed because by default auto-freq is used, so
48 * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get
49 * the total number of low level events, it is necessary to to sum all struct
50 * sample_event.period and stash the result in total_period.
51 */
52struct events_stats {
53 u64 total_period;
54 u64 total_lost;
55 u64 total_invalid_chains;
56 u32 nr_events[PERF_RECORD_HEADER_MAX];
57 u32 nr_unknown_events;
58 u32 nr_invalid_chains;
59};
60
61enum hist_column {
62 HISTC_SYMBOL,
63 HISTC_DSO,
64 HISTC_THREAD,
65 HISTC_COMM,
66 HISTC_PARENT,
67 HISTC_CPU,
68 HISTC_NR_COLS, /* Last entry */
69};
70
71struct hists {
72 struct rb_node rb_node;
73 struct rb_root entries;
74 u64 nr_entries;
75 struct events_stats stats;
76 u64 config;
77 u64 event_stream;
78 u32 type;
79 u16 col_len[HISTC_NR_COLS];
80};
81
82struct hist_entry *__hists__add_entry(struct hists *self,
83 struct addr_location *al,
84 struct symbol *parent, u64 period);
18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 85extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 86extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
87int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
88 struct hists *pair_hists, bool show_displacement,
89 long displacement, FILE *fp, u64 total);
90int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
91 struct hists *hists, struct hists *pair_hists,
92 bool show_displacement, long displacement,
93 bool color, u64 total);
20void hist_entry__free(struct hist_entry *); 94void hist_entry__free(struct hist_entry *);
21 95
22void perf_session__output_resort(struct perf_session *self, u64 total_samples); 96void hists__output_resort(struct hists *self);
23void perf_session__collapse_resort(struct perf_session *self); 97void hists__collapse_resort(struct hists *self);
24size_t perf_session__fprintf_hists(struct perf_session *self, 98
25 struct perf_session *pair, 99void hists__inc_nr_events(struct hists *self, u32 type);
26 bool show_displacement, FILE *fp); 100size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
101
102size_t hists__fprintf(struct hists *self, struct hists *pair,
103 bool show_displacement, FILE *fp);
104
105int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip);
106int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
107 size_t privsize);
108
109void hists__filter_by_dso(struct hists *self, const struct dso *dso);
110void hists__filter_by_thread(struct hists *self, const struct thread *thread);
111
112u16 hists__col_len(struct hists *self, enum hist_column col);
113void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
114bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
115
116#ifdef NO_NEWT_SUPPORT
117static inline int hists__browse(struct hists *self __used,
118 const char *helpline __used,
119 const char *ev_name __used)
120{
121 return 0;
122}
123
124static inline int hists__tui_browse_tree(struct rb_root *self __used,
125 const char *help __used)
126{
127 return 0;
128}
129
130static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
131{
132 return 0;
133}
134#define KEY_LEFT -1
135#define KEY_RIGHT -2
136#else
137#include <newt.h>
138int hists__browse(struct hists *self, const char *helpline,
139 const char *ev_name);
140int hist_entry__tui_annotate(struct hist_entry *self);
141
142#define KEY_LEFT NEWT_KEY_LEFT
143#define KEY_RIGHT NEWT_KEY_RIGHT
144
145int hists__tui_browse_tree(struct rb_root *self, const char *help);
146#endif
147
148unsigned int hists__sort_list_width(struct hists *self);
149
27#endif /* __PERF_HIST_H */ 150#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/hweight.c b/tools/perf/util/hweight.c
new file mode 100644
index 000000000000..5c1d0d099f0d
--- /dev/null
+++ b/tools/perf/util/hweight.c
@@ -0,0 +1,31 @@
1#include <linux/bitops.h>
2
3/**
4 * hweightN - returns the hamming weight of a N-bit word
5 * @x: the word to weigh
6 *
7 * The Hamming Weight of a number is the total number of bits set in it.
8 */
9
10unsigned int hweight32(unsigned int w)
11{
12 unsigned int res = w - ((w >> 1) & 0x55555555);
13 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
14 res = (res + (res >> 4)) & 0x0F0F0F0F;
15 res = res + (res >> 8);
16 return (res + (res >> 16)) & 0x000000FF;
17}
18
19unsigned long hweight64(__u64 w)
20{
21#if BITS_PER_LONG == 32
22 return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
23#elif BITS_PER_LONG == 64
24 __u64 res = w - ((w >> 1) & 0x5555555555555555ul);
25 res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
26 res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
27 res = res + (res >> 8);
28 res = res + (res >> 16);
29 return (res + (res >> 32)) & 0x00000000000000FFul;
30#endif
31}
diff --git a/tools/perf/util/include/asm/bitops.h b/tools/perf/util/include/asm/bitops.h
deleted file mode 100644
index 58e9817ffae0..000000000000
--- a/tools/perf/util/include/asm/bitops.h
+++ /dev/null
@@ -1,18 +0,0 @@
1#ifndef _PERF_ASM_BITOPS_H_
2#define _PERF_ASM_BITOPS_H_
3
4#include <sys/types.h>
5#include "../../types.h"
6#include <linux/compiler.h>
7
8/* CHECKME: Not sure both always match */
9#define BITS_PER_LONG __WORDSIZE
10
11#include "../../../../include/asm-generic/bitops/__fls.h"
12#include "../../../../include/asm-generic/bitops/fls.h"
13#include "../../../../include/asm-generic/bitops/fls64.h"
14#include "../../../../include/asm-generic/bitops/__ffs.h"
15#include "../../../../include/asm-generic/bitops/ffz.h"
16#include "../../../../include/asm-generic/bitops/hweight.h"
17
18#endif
diff --git a/tools/perf/util/include/asm/cpufeature.h b/tools/perf/util/include/asm/cpufeature.h
new file mode 100644
index 000000000000..acffd5e4d1d4
--- /dev/null
+++ b/tools/perf/util/include/asm/cpufeature.h
@@ -0,0 +1,9 @@
1
2#ifndef PERF_CPUFEATURE_H
3#define PERF_CPUFEATURE_H
4
5/* cpufeature.h ... dummy header file for including arch/x86/lib/memcpy_64.S */
6
7#define X86_FEATURE_REP_GOOD 0
8
9#endif /* PERF_CPUFEATURE_H */
diff --git a/tools/perf/util/include/asm/dwarf2.h b/tools/perf/util/include/asm/dwarf2.h
new file mode 100644
index 000000000000..bb4198e7837a
--- /dev/null
+++ b/tools/perf/util/include/asm/dwarf2.h
@@ -0,0 +1,11 @@
1
2#ifndef PERF_DWARF2_H
3#define PERF_DWARF2_H
4
5/* dwarf2.h ... dummy header file for including arch/x86/lib/memcpy_64.S */
6
7#define CFI_STARTPROC
8#define CFI_ENDPROC
9
10#endif /* PERF_DWARF2_H */
11
diff --git a/tools/perf/util/include/asm/hweight.h b/tools/perf/util/include/asm/hweight.h
new file mode 100644
index 000000000000..36cf26d434a5
--- /dev/null
+++ b/tools/perf/util/include/asm/hweight.h
@@ -0,0 +1,8 @@
1#ifndef PERF_HWEIGHT_H
2#define PERF_HWEIGHT_H
3
4#include <linux/types.h>
5unsigned int hweight32(unsigned int w);
6unsigned long hweight64(__u64 w);
7
8#endif /* PERF_HWEIGHT_H */
diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h
new file mode 100644
index 000000000000..cf6727e99c44
--- /dev/null
+++ b/tools/perf/util/include/dwarf-regs.h
@@ -0,0 +1,8 @@
1#ifndef _PERF_DWARF_REGS_H_
2#define _PERF_DWARF_REGS_H_
3
4#ifdef DWARF_SUPPORT
5const char *get_arch_regstr(unsigned int n);
6#endif
7
8#endif
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index 94507639a8c4..eda4416efa0a 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -1,3 +1,35 @@
1#include "../../../../include/linux/bitmap.h" 1#ifndef _PERF_BITOPS_H
2#include "../../../../include/asm-generic/bitops/find.h" 2#define _PERF_BITOPS_H
3#include <linux/errno.h> 3
4#include <string.h>
5#include <linux/bitops.h>
6
7int __bitmap_weight(const unsigned long *bitmap, int bits);
8
9#define BITMAP_LAST_WORD_MASK(nbits) \
10( \
11 ((nbits) % BITS_PER_LONG) ? \
12 (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \
13)
14
15#define small_const_nbits(nbits) \
16 (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
17
18static inline void bitmap_zero(unsigned long *dst, int nbits)
19{
20 if (small_const_nbits(nbits))
21 *dst = 0UL;
22 else {
23 int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
24 memset(dst, 0, len);
25 }
26}
27
28static inline int bitmap_weight(const unsigned long *src, int nbits)
29{
30 if (small_const_nbits(nbits))
31 return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));
32 return __bitmap_weight(src, nbits);
33}
34
35#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index 8d63116e9435..8be0b968ca0b 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -1,29 +1,32 @@
1#ifndef _PERF_LINUX_BITOPS_H_ 1#ifndef _PERF_LINUX_BITOPS_H_
2#define _PERF_LINUX_BITOPS_H_ 2#define _PERF_LINUX_BITOPS_H_
3 3
4#define __KERNEL__ 4#include <linux/kernel.h>
5#include <asm/hweight.h>
5 6
6#define CONFIG_GENERIC_FIND_NEXT_BIT 7#define BITS_PER_LONG __WORDSIZE
7#define CONFIG_GENERIC_FIND_FIRST_BIT 8#define BITS_PER_BYTE 8
8#include "../../../../include/linux/bitops.h" 9#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
9
10#undef __KERNEL__
11 10
12static inline void set_bit(int nr, unsigned long *addr) 11static inline void set_bit(int nr, unsigned long *addr)
13{ 12{
14 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); 13 addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
15} 14}
16 15
16static inline void clear_bit(int nr, unsigned long *addr)
17{
18 addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
19}
20
17static __always_inline int test_bit(unsigned int nr, const unsigned long *addr) 21static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
18{ 22{
19 return ((1UL << (nr % BITS_PER_LONG)) & 23 return ((1UL << (nr % BITS_PER_LONG)) &
20 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0; 24 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
21} 25}
22 26
23unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned 27static inline unsigned long hweight_long(unsigned long w)
24 long size, unsigned long offset); 28{
25 29 return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
26unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned 30}
27 long size, unsigned long offset);
28 31
29#endif 32#endif
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
index dfb0713ed47f..791f9dd27ebf 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/perf/util/include/linux/compiler.h
@@ -7,4 +7,6 @@
7#define __user 7#define __user
8#define __attribute_const__ 8#define __attribute_const__
9 9
10#define __used __attribute__((__unused__))
11
10#endif 12#endif
diff --git a/tools/perf/util/include/linux/hash.h b/tools/perf/util/include/linux/hash.h
new file mode 100644
index 000000000000..201f57397997
--- /dev/null
+++ b/tools/perf/util/include/linux/hash.h
@@ -0,0 +1,5 @@
1#include "../../../../include/linux/hash.h"
2
3#ifndef PERF_HASH_H
4#define PERF_HASH_H
5#endif
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 21c0274c02fa..1eb804fd3fbf 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -28,6 +28,8 @@
28 (type *)((char *)__mptr - offsetof(type, member)); }) 28 (type *)((char *)__mptr - offsetof(type, member)); })
29#endif 29#endif
30 30
31#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
32
31#ifndef max 33#ifndef max
32#define max(x, y) ({ \ 34#define max(x, y) ({ \
33 typeof(x) _max1 = (x); \ 35 typeof(x) _max1 = (x); \
@@ -85,21 +87,25 @@ simple_strtoul(const char *nptr, char **endptr, int base)
85 return strtoul(nptr, endptr, base); 87 return strtoul(nptr, endptr, base);
86} 88}
87 89
90int eprintf(int level,
91 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
92
88#ifndef pr_fmt 93#ifndef pr_fmt
89#define pr_fmt(fmt) fmt 94#define pr_fmt(fmt) fmt
90#endif 95#endif
91 96
92#define pr_err(fmt, ...) \ 97#define pr_err(fmt, ...) \
93 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 98 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
94#define pr_warning(fmt, ...) \ 99#define pr_warning(fmt, ...) \
95 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 100 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
96#define pr_info(fmt, ...) \ 101#define pr_info(fmt, ...) \
97 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 102 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
98#define pr_debug(fmt, ...) \ 103#define pr_debug(fmt, ...) \
99 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) 104 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
100#define pr_debugN(n, fmt, ...) \ 105#define pr_debugN(n, fmt, ...) \
101 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__) 106 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
102#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__) 107#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
103#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) 108#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
109#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
104 110
105#endif 111#endif
diff --git a/tools/perf/util/include/linux/linkage.h b/tools/perf/util/include/linux/linkage.h
new file mode 100644
index 000000000000..06387cffe125
--- /dev/null
+++ b/tools/perf/util/include/linux/linkage.h
@@ -0,0 +1,13 @@
1
2#ifndef PERF_LINUX_LINKAGE_H_
3#define PERF_LINUX_LINKAGE_H_
4
5/* linkage.h ... for including arch/x86/lib/memcpy_64.S */
6
7#define ENTRY(name) \
8 .globl name; \
9 name:
10
11#define ENDPROC(name)
12
13#endif /* PERF_LINUX_LINKAGE_H_ */
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index dbe4b814382a..f5ca26e53fbb 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -15,4 +15,12 @@ static inline void list_del_range(struct list_head *begin,
15 begin->prev->next = end->next; 15 begin->prev->next = end->next;
16 end->next->prev = begin->prev; 16 end->next->prev = begin->prev;
17} 17}
18
19/**
20 * list_for_each_from - iterate over a list from one of its nodes
21 * @pos: the &struct list_head to use as a loop cursor, from where to start
22 * @head: the head for your list.
23 */
24#define list_for_each_from(pos, head) \
25 for (; prefetch(pos->next), pos != (head); pos = pos->next)
18#endif 26#endif
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
index 196862a81a21..12de3b8112f9 100644
--- a/tools/perf/util/include/linux/types.h
+++ b/tools/perf/util/include/linux/types.h
@@ -6,4 +6,16 @@
6#define DECLARE_BITMAP(name,bits) \ 6#define DECLARE_BITMAP(name,bits) \
7 unsigned long name[BITS_TO_LONGS(bits)] 7 unsigned long name[BITS_TO_LONGS(bits)]
8 8
9struct list_head {
10 struct list_head *next, *prev;
11};
12
13struct hlist_head {
14 struct hlist_node *first;
15};
16
17struct hlist_node {
18 struct hlist_node *next, **pprev;
19};
20
9#endif 21#endif
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index c4d55a0da2ea..3a7eb6ec0eec 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -1,25 +1,22 @@
1#include "event.h"
2#include "symbol.h" 1#include "symbol.h"
2#include <errno.h>
3#include <limits.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <string.h> 5#include <string.h>
5#include <stdio.h> 6#include <stdio.h>
6#include "debug.h" 7#include <unistd.h>
8#include "map.h"
9
10const char *map_type__name[MAP__NR_TYPES] = {
11 [MAP__FUNCTION] = "Functions",
12 [MAP__VARIABLE] = "Variables",
13};
7 14
8static inline int is_anon_memory(const char *filename) 15static inline int is_anon_memory(const char *filename)
9{ 16{
10 return strcmp(filename, "//anon") == 0; 17 return strcmp(filename, "//anon") == 0;
11} 18}
12 19
13static int strcommon(const char *pathname, char *cwd, int cwdlen)
14{
15 int n = 0;
16
17 while (n < cwdlen && pathname[n] == cwd[n])
18 ++n;
19
20 return n;
21}
22
23void map__init(struct map *self, enum map_type type, 20void map__init(struct map *self, enum map_type type,
24 u64 start, u64 end, u64 pgoff, struct dso *dso) 21 u64 start, u64 end, u64 pgoff, struct dso *dso)
25{ 22{
@@ -31,45 +28,41 @@ void map__init(struct map *self, enum map_type type,
31 self->map_ip = map__map_ip; 28 self->map_ip = map__map_ip;
32 self->unmap_ip = map__unmap_ip; 29 self->unmap_ip = map__unmap_ip;
33 RB_CLEAR_NODE(&self->rb_node); 30 RB_CLEAR_NODE(&self->rb_node);
31 self->groups = NULL;
32 self->referenced = false;
34} 33}
35 34
36struct map *map__new(struct mmap_event *event, enum map_type type, 35struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
37 char *cwd, int cwdlen) 36 u64 pgoff, u32 pid, char *filename,
37 enum map_type type)
38{ 38{
39 struct map *self = malloc(sizeof(*self)); 39 struct map *self = malloc(sizeof(*self));
40 40
41 if (self != NULL) { 41 if (self != NULL) {
42 const char *filename = event->filename;
43 char newfilename[PATH_MAX]; 42 char newfilename[PATH_MAX];
44 struct dso *dso; 43 struct dso *dso;
45 int anon; 44 int anon;
46 45
47 if (cwd) {
48 int n = strcommon(filename, cwd, cwdlen);
49
50 if (n == cwdlen) {
51 snprintf(newfilename, sizeof(newfilename),
52 ".%s", filename + n);
53 filename = newfilename;
54 }
55 }
56
57 anon = is_anon_memory(filename); 46 anon = is_anon_memory(filename);
58 47
59 if (anon) { 48 if (anon) {
60 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid); 49 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
61 filename = newfilename; 50 filename = newfilename;
62 } 51 }
63 52
64 dso = dsos__findnew(filename); 53 dso = __dsos__findnew(dsos__list, filename);
65 if (dso == NULL) 54 if (dso == NULL)
66 goto out_delete; 55 goto out_delete;
67 56
68 map__init(self, type, event->start, event->start + event->len, 57 map__init(self, type, start, start + len, pgoff, dso);
69 event->pgoff, dso);
70 58
71 if (self->dso == vdso || anon) 59 if (anon) {
60set_identity:
72 self->map_ip = self->unmap_ip = identity__map_ip; 61 self->map_ip = self->unmap_ip = identity__map_ip;
62 } else if (strcmp(filename, "[vdso]") == 0) {
63 dso__set_loaded(dso, self->type);
64 goto set_identity;
65 }
73 } 66 }
74 return self; 67 return self;
75out_delete: 68out_delete:
@@ -104,8 +97,7 @@ void map__fixup_end(struct map *self)
104 97
105#define DSO__DELETED "(deleted)" 98#define DSO__DELETED "(deleted)"
106 99
107int map__load(struct map *self, struct perf_session *session, 100int map__load(struct map *self, symbol_filter_t filter)
108 symbol_filter_t filter)
109{ 101{
110 const char *name = self->dso->long_name; 102 const char *name = self->dso->long_name;
111 int nr; 103 int nr;
@@ -113,7 +105,7 @@ int map__load(struct map *self, struct perf_session *session,
113 if (dso__loaded(self->dso, self->type)) 105 if (dso__loaded(self->dso, self->type))
114 return 0; 106 return 0;
115 107
116 nr = dso__load(self->dso, self, session, filter); 108 nr = dso__load(self->dso, self, filter);
117 if (nr < 0) { 109 if (nr < 0) {
118 if (self->dso->has_build_id) { 110 if (self->dso->has_build_id) {
119 char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 111 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
@@ -144,24 +136,29 @@ int map__load(struct map *self, struct perf_session *session,
144 136
145 return -1; 137 return -1;
146 } 138 }
139 /*
140 * Only applies to the kernel, as its symtabs aren't relative like the
141 * module ones.
142 */
143 if (self->dso->kernel)
144 map__reloc_vmlinux(self);
147 145
148 return 0; 146 return 0;
149} 147}
150 148
151struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 149struct symbol *map__find_symbol(struct map *self, u64 addr,
152 u64 addr, symbol_filter_t filter) 150 symbol_filter_t filter)
153{ 151{
154 if (map__load(self, session, filter) < 0) 152 if (map__load(self, filter) < 0)
155 return NULL; 153 return NULL;
156 154
157 return dso__find_symbol(self->dso, self->type, addr); 155 return dso__find_symbol(self->dso, self->type, addr);
158} 156}
159 157
160struct symbol *map__find_symbol_by_name(struct map *self, const char *name, 158struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
161 struct perf_session *session,
162 symbol_filter_t filter) 159 symbol_filter_t filter)
163{ 160{
164 if (map__load(self, session, filter) < 0) 161 if (map__load(self, filter) < 0)
165 return NULL; 162 return NULL;
166 163
167 if (!dso__sorted_by_name(self->dso, self->type)) 164 if (!dso__sorted_by_name(self->dso, self->type))
@@ -201,3 +198,485 @@ size_t map__fprintf(struct map *self, FILE *fp)
201 return fprintf(fp, " %Lx-%Lx %Lx %s\n", 198 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
202 self->start, self->end, self->pgoff, self->dso->name); 199 self->start, self->end, self->pgoff, self->dso->name);
203} 200}
201
202/*
203 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
204 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
205 */
206u64 map__rip_2objdump(struct map *map, u64 rip)
207{
208 u64 addr = map->dso->adjust_symbols ?
209 map->unmap_ip(map, rip) : /* RIP -> IP */
210 rip;
211 return addr;
212}
213
214u64 map__objdump_2ip(struct map *map, u64 addr)
215{
216 u64 ip = map->dso->adjust_symbols ?
217 addr :
218 map->unmap_ip(map, addr); /* RIP -> IP */
219 return ip;
220}
221
222void map_groups__init(struct map_groups *self)
223{
224 int i;
225 for (i = 0; i < MAP__NR_TYPES; ++i) {
226 self->maps[i] = RB_ROOT;
227 INIT_LIST_HEAD(&self->removed_maps[i]);
228 }
229 self->machine = NULL;
230}
231
232static void maps__delete(struct rb_root *self)
233{
234 struct rb_node *next = rb_first(self);
235
236 while (next) {
237 struct map *pos = rb_entry(next, struct map, rb_node);
238
239 next = rb_next(&pos->rb_node);
240 rb_erase(&pos->rb_node, self);
241 map__delete(pos);
242 }
243}
244
245static void maps__delete_removed(struct list_head *self)
246{
247 struct map *pos, *n;
248
249 list_for_each_entry_safe(pos, n, self, node) {
250 list_del(&pos->node);
251 map__delete(pos);
252 }
253}
254
255void map_groups__exit(struct map_groups *self)
256{
257 int i;
258
259 for (i = 0; i < MAP__NR_TYPES; ++i) {
260 maps__delete(&self->maps[i]);
261 maps__delete_removed(&self->removed_maps[i]);
262 }
263}
264
265void map_groups__flush(struct map_groups *self)
266{
267 int type;
268
269 for (type = 0; type < MAP__NR_TYPES; type++) {
270 struct rb_root *root = &self->maps[type];
271 struct rb_node *next = rb_first(root);
272
273 while (next) {
274 struct map *pos = rb_entry(next, struct map, rb_node);
275 next = rb_next(&pos->rb_node);
276 rb_erase(&pos->rb_node, root);
277 /*
278 * We may have references to this map, for
279 * instance in some hist_entry instances, so
280 * just move them to a separate list.
281 */
282 list_add_tail(&pos->node, &self->removed_maps[pos->type]);
283 }
284 }
285}
286
287struct symbol *map_groups__find_symbol(struct map_groups *self,
288 enum map_type type, u64 addr,
289 struct map **mapp,
290 symbol_filter_t filter)
291{
292 struct map *map = map_groups__find(self, type, addr);
293
294 if (map != NULL) {
295 if (mapp != NULL)
296 *mapp = map;
297 return map__find_symbol(map, map->map_ip(map, addr), filter);
298 }
299
300 return NULL;
301}
302
303struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
304 enum map_type type,
305 const char *name,
306 struct map **mapp,
307 symbol_filter_t filter)
308{
309 struct rb_node *nd;
310
311 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
312 struct map *pos = rb_entry(nd, struct map, rb_node);
313 struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
314
315 if (sym == NULL)
316 continue;
317 if (mapp != NULL)
318 *mapp = pos;
319 return sym;
320 }
321
322 return NULL;
323}
324
325size_t __map_groups__fprintf_maps(struct map_groups *self,
326 enum map_type type, int verbose, FILE *fp)
327{
328 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
329 struct rb_node *nd;
330
331 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
332 struct map *pos = rb_entry(nd, struct map, rb_node);
333 printed += fprintf(fp, "Map:");
334 printed += map__fprintf(pos, fp);
335 if (verbose > 2) {
336 printed += dso__fprintf(pos->dso, type, fp);
337 printed += fprintf(fp, "--\n");
338 }
339 }
340
341 return printed;
342}
343
344size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp)
345{
346 size_t printed = 0, i;
347 for (i = 0; i < MAP__NR_TYPES; ++i)
348 printed += __map_groups__fprintf_maps(self, i, verbose, fp);
349 return printed;
350}
351
352static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
353 enum map_type type,
354 int verbose, FILE *fp)
355{
356 struct map *pos;
357 size_t printed = 0;
358
359 list_for_each_entry(pos, &self->removed_maps[type], node) {
360 printed += fprintf(fp, "Map:");
361 printed += map__fprintf(pos, fp);
362 if (verbose > 1) {
363 printed += dso__fprintf(pos->dso, type, fp);
364 printed += fprintf(fp, "--\n");
365 }
366 }
367 return printed;
368}
369
370static size_t map_groups__fprintf_removed_maps(struct map_groups *self,
371 int verbose, FILE *fp)
372{
373 size_t printed = 0, i;
374 for (i = 0; i < MAP__NR_TYPES; ++i)
375 printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp);
376 return printed;
377}
378
379size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp)
380{
381 size_t printed = map_groups__fprintf_maps(self, verbose, fp);
382 printed += fprintf(fp, "Removed maps:\n");
383 return printed + map_groups__fprintf_removed_maps(self, verbose, fp);
384}
385
386int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
387 int verbose, FILE *fp)
388{
389 struct rb_root *root = &self->maps[map->type];
390 struct rb_node *next = rb_first(root);
391 int err = 0;
392
393 while (next) {
394 struct map *pos = rb_entry(next, struct map, rb_node);
395 next = rb_next(&pos->rb_node);
396
397 if (!map__overlap(pos, map))
398 continue;
399
400 if (verbose >= 2) {
401 fputs("overlapping maps:\n", fp);
402 map__fprintf(map, fp);
403 map__fprintf(pos, fp);
404 }
405
406 rb_erase(&pos->rb_node, root);
407 /*
408 * Now check if we need to create new maps for areas not
409 * overlapped by the new map:
410 */
411 if (map->start > pos->start) {
412 struct map *before = map__clone(pos);
413
414 if (before == NULL) {
415 err = -ENOMEM;
416 goto move_map;
417 }
418
419 before->end = map->start - 1;
420 map_groups__insert(self, before);
421 if (verbose >= 2)
422 map__fprintf(before, fp);
423 }
424
425 if (map->end < pos->end) {
426 struct map *after = map__clone(pos);
427
428 if (after == NULL) {
429 err = -ENOMEM;
430 goto move_map;
431 }
432
433 after->start = map->end + 1;
434 map_groups__insert(self, after);
435 if (verbose >= 2)
436 map__fprintf(after, fp);
437 }
438move_map:
439 /*
440 * If we have references, just move them to a separate list.
441 */
442 if (pos->referenced)
443 list_add_tail(&pos->node, &self->removed_maps[map->type]);
444 else
445 map__delete(pos);
446
447 if (err)
448 return err;
449 }
450
451 return 0;
452}
453
454/*
455 * XXX This should not really _copy_ te maps, but refcount them.
456 */
457int map_groups__clone(struct map_groups *self,
458 struct map_groups *parent, enum map_type type)
459{
460 struct rb_node *nd;
461 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
462 struct map *map = rb_entry(nd, struct map, rb_node);
463 struct map *new = map__clone(map);
464 if (new == NULL)
465 return -ENOMEM;
466 map_groups__insert(self, new);
467 }
468 return 0;
469}
470
471static u64 map__reloc_map_ip(struct map *map, u64 ip)
472{
473 return ip + (s64)map->pgoff;
474}
475
476static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
477{
478 return ip - (s64)map->pgoff;
479}
480
481void map__reloc_vmlinux(struct map *self)
482{
483 struct kmap *kmap = map__kmap(self);
484 s64 reloc;
485
486 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->unrelocated_addr)
487 return;
488
489 reloc = (kmap->ref_reloc_sym->unrelocated_addr -
490 kmap->ref_reloc_sym->addr);
491
492 if (!reloc)
493 return;
494
495 self->map_ip = map__reloc_map_ip;
496 self->unmap_ip = map__reloc_unmap_ip;
497 self->pgoff = reloc;
498}
499
500void maps__insert(struct rb_root *maps, struct map *map)
501{
502 struct rb_node **p = &maps->rb_node;
503 struct rb_node *parent = NULL;
504 const u64 ip = map->start;
505 struct map *m;
506
507 while (*p != NULL) {
508 parent = *p;
509 m = rb_entry(parent, struct map, rb_node);
510 if (ip < m->start)
511 p = &(*p)->rb_left;
512 else
513 p = &(*p)->rb_right;
514 }
515
516 rb_link_node(&map->rb_node, parent, p);
517 rb_insert_color(&map->rb_node, maps);
518}
519
520void maps__remove(struct rb_root *self, struct map *map)
521{
522 rb_erase(&map->rb_node, self);
523}
524
525struct map *maps__find(struct rb_root *maps, u64 ip)
526{
527 struct rb_node **p = &maps->rb_node;
528 struct rb_node *parent = NULL;
529 struct map *m;
530
531 while (*p != NULL) {
532 parent = *p;
533 m = rb_entry(parent, struct map, rb_node);
534 if (ip < m->start)
535 p = &(*p)->rb_left;
536 else if (ip > m->end)
537 p = &(*p)->rb_right;
538 else
539 return m;
540 }
541
542 return NULL;
543}
544
545int machine__init(struct machine *self, const char *root_dir, pid_t pid)
546{
547 map_groups__init(&self->kmaps);
548 RB_CLEAR_NODE(&self->rb_node);
549 INIT_LIST_HEAD(&self->user_dsos);
550 INIT_LIST_HEAD(&self->kernel_dsos);
551
552 self->kmaps.machine = self;
553 self->pid = pid;
554 self->root_dir = strdup(root_dir);
555 return self->root_dir == NULL ? -ENOMEM : 0;
556}
557
558static void dsos__delete(struct list_head *self)
559{
560 struct dso *pos, *n;
561
562 list_for_each_entry_safe(pos, n, self, node) {
563 list_del(&pos->node);
564 dso__delete(pos);
565 }
566}
567
568void machine__exit(struct machine *self)
569{
570 map_groups__exit(&self->kmaps);
571 dsos__delete(&self->user_dsos);
572 dsos__delete(&self->kernel_dsos);
573 free(self->root_dir);
574 self->root_dir = NULL;
575}
576
577void machine__delete(struct machine *self)
578{
579 machine__exit(self);
580 free(self);
581}
582
583struct machine *machines__add(struct rb_root *self, pid_t pid,
584 const char *root_dir)
585{
586 struct rb_node **p = &self->rb_node;
587 struct rb_node *parent = NULL;
588 struct machine *pos, *machine = malloc(sizeof(*machine));
589
590 if (!machine)
591 return NULL;
592
593 if (machine__init(machine, root_dir, pid) != 0) {
594 free(machine);
595 return NULL;
596 }
597
598 while (*p != NULL) {
599 parent = *p;
600 pos = rb_entry(parent, struct machine, rb_node);
601 if (pid < pos->pid)
602 p = &(*p)->rb_left;
603 else
604 p = &(*p)->rb_right;
605 }
606
607 rb_link_node(&machine->rb_node, parent, p);
608 rb_insert_color(&machine->rb_node, self);
609
610 return machine;
611}
612
613struct machine *machines__find(struct rb_root *self, pid_t pid)
614{
615 struct rb_node **p = &self->rb_node;
616 struct rb_node *parent = NULL;
617 struct machine *machine;
618 struct machine *default_machine = NULL;
619
620 while (*p != NULL) {
621 parent = *p;
622 machine = rb_entry(parent, struct machine, rb_node);
623 if (pid < machine->pid)
624 p = &(*p)->rb_left;
625 else if (pid > machine->pid)
626 p = &(*p)->rb_right;
627 else
628 return machine;
629 if (!machine->pid)
630 default_machine = machine;
631 }
632
633 return default_machine;
634}
635
636struct machine *machines__findnew(struct rb_root *self, pid_t pid)
637{
638 char path[PATH_MAX];
639 const char *root_dir;
640 struct machine *machine = machines__find(self, pid);
641
642 if (!machine || machine->pid != pid) {
643 if (pid == HOST_KERNEL_ID || pid == DEFAULT_GUEST_KERNEL_ID)
644 root_dir = "";
645 else {
646 if (!symbol_conf.guestmount)
647 goto out;
648 sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
649 if (access(path, R_OK)) {
650 pr_err("Can't access file %s\n", path);
651 goto out;
652 }
653 root_dir = path;
654 }
655 machine = machines__add(self, pid, root_dir);
656 }
657
658out:
659 return machine;
660}
661
662void machines__process(struct rb_root *self, machine__process_t process, void *data)
663{
664 struct rb_node *nd;
665
666 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
667 struct machine *pos = rb_entry(nd, struct machine, rb_node);
668 process(pos, data);
669 }
670}
671
672char *machine__mmap_name(struct machine *self, char *bf, size_t size)
673{
674 if (machine__is_host(self))
675 snprintf(bf, size, "[%s]", "kernel.kallsyms");
676 else if (machine__is_default_guest(self))
677 snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
678 else
679 snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid);
680
681 return bf;
682}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
new file mode 100644
index 000000000000..b397c0383728
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,237 @@
1#ifndef __PERF_MAP_H
2#define __PERF_MAP_H
3
4#include <linux/compiler.h>
5#include <linux/list.h>
6#include <linux/rbtree.h>
7#include <stdio.h>
8#include <stdbool.h>
9#include "types.h"
10
11enum map_type {
12 MAP__FUNCTION = 0,
13 MAP__VARIABLE,
14};
15
16#define MAP__NR_TYPES (MAP__VARIABLE + 1)
17
18extern const char *map_type__name[MAP__NR_TYPES];
19
20struct dso;
21struct ref_reloc_sym;
22struct map_groups;
23struct machine;
24
25struct map {
26 union {
27 struct rb_node rb_node;
28 struct list_head node;
29 };
30 u64 start;
31 u64 end;
32 u8 /* enum map_type */ type;
33 bool referenced;
34 u32 priv;
35 u64 pgoff;
36
37 /* ip -> dso rip */
38 u64 (*map_ip)(struct map *, u64);
39 /* dso rip -> ip */
40 u64 (*unmap_ip)(struct map *, u64);
41
42 struct dso *dso;
43 struct map_groups *groups;
44};
45
46struct kmap {
47 struct ref_reloc_sym *ref_reloc_sym;
48 struct map_groups *kmaps;
49};
50
51struct map_groups {
52 struct rb_root maps[MAP__NR_TYPES];
53 struct list_head removed_maps[MAP__NR_TYPES];
54 struct machine *machine;
55};
56
57/* Native host kernel uses -1 as pid index in machine */
58#define HOST_KERNEL_ID (-1)
59#define DEFAULT_GUEST_KERNEL_ID (0)
60
61struct machine {
62 struct rb_node rb_node;
63 pid_t pid;
64 char *root_dir;
65 struct list_head user_dsos;
66 struct list_head kernel_dsos;
67 struct map_groups kmaps;
68 struct map *vmlinux_maps[MAP__NR_TYPES];
69};
70
71static inline
72struct map *machine__kernel_map(struct machine *self, enum map_type type)
73{
74 return self->vmlinux_maps[type];
75}
76
77static inline struct kmap *map__kmap(struct map *self)
78{
79 return (struct kmap *)(self + 1);
80}
81
82static inline u64 map__map_ip(struct map *map, u64 ip)
83{
84 return ip - map->start + map->pgoff;
85}
86
87static inline u64 map__unmap_ip(struct map *map, u64 ip)
88{
89 return ip + map->start - map->pgoff;
90}
91
92static inline u64 identity__map_ip(struct map *map __used, u64 ip)
93{
94 return ip;
95}
96
97
98/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
99u64 map__rip_2objdump(struct map *map, u64 rip);
100u64 map__objdump_2ip(struct map *map, u64 addr);
101
102struct symbol;
103
104typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
105
106void map__init(struct map *self, enum map_type type,
107 u64 start, u64 end, u64 pgoff, struct dso *dso);
108struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
109 u64 pgoff, u32 pid, char *filename,
110 enum map_type type);
111void map__delete(struct map *self);
112struct map *map__clone(struct map *self);
113int map__overlap(struct map *l, struct map *r);
114size_t map__fprintf(struct map *self, FILE *fp);
115
116int map__load(struct map *self, symbol_filter_t filter);
117struct symbol *map__find_symbol(struct map *self,
118 u64 addr, symbol_filter_t filter);
119struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
120 symbol_filter_t filter);
121void map__fixup_start(struct map *self);
122void map__fixup_end(struct map *self);
123
124void map__reloc_vmlinux(struct map *self);
125
126size_t __map_groups__fprintf_maps(struct map_groups *self,
127 enum map_type type, int verbose, FILE *fp);
128void maps__insert(struct rb_root *maps, struct map *map);
129void maps__remove(struct rb_root *self, struct map *map);
130struct map *maps__find(struct rb_root *maps, u64 addr);
131void map_groups__init(struct map_groups *self);
132void map_groups__exit(struct map_groups *self);
133int map_groups__clone(struct map_groups *self,
134 struct map_groups *parent, enum map_type type);
135size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
136size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
137
138typedef void (*machine__process_t)(struct machine *self, void *data);
139
140void machines__process(struct rb_root *self, machine__process_t process, void *data);
141struct machine *machines__add(struct rb_root *self, pid_t pid,
142 const char *root_dir);
143struct machine *machines__find_host(struct rb_root *self);
144struct machine *machines__find(struct rb_root *self, pid_t pid);
145struct machine *machines__findnew(struct rb_root *self, pid_t pid);
146char *machine__mmap_name(struct machine *self, char *bf, size_t size);
147int machine__init(struct machine *self, const char *root_dir, pid_t pid);
148void machine__exit(struct machine *self);
149void machine__delete(struct machine *self);
150
151/*
152 * Default guest kernel is defined by parameter --guestkallsyms
153 * and --guestmodules
154 */
155static inline bool machine__is_default_guest(struct machine *self)
156{
157 return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false;
158}
159
160static inline bool machine__is_host(struct machine *self)
161{
162 return self ? self->pid == HOST_KERNEL_ID : false;
163}
164
165static inline void map_groups__insert(struct map_groups *self, struct map *map)
166{
167 maps__insert(&self->maps[map->type], map);
168 map->groups = self;
169}
170
171static inline void map_groups__remove(struct map_groups *self, struct map *map)
172{
173 maps__remove(&self->maps[map->type], map);
174}
175
176static inline struct map *map_groups__find(struct map_groups *self,
177 enum map_type type, u64 addr)
178{
179 return maps__find(&self->maps[type], addr);
180}
181
182struct symbol *map_groups__find_symbol(struct map_groups *self,
183 enum map_type type, u64 addr,
184 struct map **mapp,
185 symbol_filter_t filter);
186
187struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
188 enum map_type type,
189 const char *name,
190 struct map **mapp,
191 symbol_filter_t filter);
192
193static inline
194struct symbol *machine__find_kernel_symbol(struct machine *self,
195 enum map_type type, u64 addr,
196 struct map **mapp,
197 symbol_filter_t filter)
198{
199 return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter);
200}
201
202static inline
203struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
204 struct map **mapp,
205 symbol_filter_t filter)
206{
207 return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter);
208}
209
210static inline
211struct symbol *map_groups__find_function_by_name(struct map_groups *self,
212 const char *name, struct map **mapp,
213 symbol_filter_t filter)
214{
215 return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
216}
217
218static inline
219struct symbol *machine__find_kernel_function_by_name(struct machine *self,
220 const char *name,
221 struct map **mapp,
222 symbol_filter_t filter)
223{
224 return map_groups__find_function_by_name(&self->kmaps, name, mapp,
225 filter);
226}
227
228int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
229 int verbose, FILE *fp);
230
231struct map *map_groups__find_by_name(struct map_groups *self,
232 enum map_type type, const char *name);
233struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
234
235void map_groups__flush(struct map_groups *self);
236
237#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e5bc0fb016b2..bc2732ee23eb 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,18 +1,19 @@
1#include "../../../include/linux/hw_breakpoint.h" 1#include "../../../include/linux/hw_breakpoint.h"
2#include "util.h" 2#include "util.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "evsel.h"
4#include "parse-options.h" 5#include "parse-options.h"
5#include "parse-events.h" 6#include "parse-events.h"
6#include "exec_cmd.h" 7#include "exec_cmd.h"
7#include "string.h" 8#include "string.h"
9#include "symbol.h"
8#include "cache.h" 10#include "cache.h"
9#include "header.h" 11#include "header.h"
10#include "debugfs.h" 12#include "debugfs.h"
11 13
12int nr_counters; 14int nr_counters;
13 15
14struct perf_event_attr attrs[MAX_COUNTERS]; 16LIST_HEAD(evsel_list);
15char *filters[MAX_COUNTERS];
16 17
17struct event_symbol { 18struct event_symbol {
18 u8 type; 19 u8 type;
@@ -265,10 +266,10 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
265 return name; 266 return name;
266} 267}
267 268
268const char *event_name(int counter) 269const char *event_name(struct perf_evsel *evsel)
269{ 270{
270 u64 config = attrs[counter].config; 271 u64 config = evsel->attr.config;
271 int type = attrs[counter].type; 272 int type = evsel->attr.type;
272 273
273 return __event_name(type, config); 274 return __event_name(type, config);
274} 275}
@@ -409,7 +410,6 @@ static enum event_result
409parse_single_tracepoint_event(char *sys_name, 410parse_single_tracepoint_event(char *sys_name,
410 const char *evt_name, 411 const char *evt_name,
411 unsigned int evt_length, 412 unsigned int evt_length,
412 char *flags,
413 struct perf_event_attr *attr, 413 struct perf_event_attr *attr,
414 const char **strp) 414 const char **strp)
415{ 415{
@@ -418,14 +418,6 @@ parse_single_tracepoint_event(char *sys_name,
418 u64 id; 418 u64 id;
419 int fd; 419 int fd;
420 420
421 if (flags) {
422 if (!strncmp(flags, "record", strlen(flags))) {
423 attr->sample_type |= PERF_SAMPLE_RAW;
424 attr->sample_type |= PERF_SAMPLE_TIME;
425 attr->sample_type |= PERF_SAMPLE_CPU;
426 }
427 }
428
429 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, 421 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
430 sys_name, evt_name); 422 sys_name, evt_name);
431 423
@@ -442,7 +434,14 @@ parse_single_tracepoint_event(char *sys_name,
442 id = atoll(id_buf); 434 id = atoll(id_buf);
443 attr->config = id; 435 attr->config = id;
444 attr->type = PERF_TYPE_TRACEPOINT; 436 attr->type = PERF_TYPE_TRACEPOINT;
445 *strp = evt_name + evt_length; 437 *strp += strlen(sys_name) + evt_length + 1; /* + 1 for the ':' */
438
439 attr->sample_type |= PERF_SAMPLE_RAW;
440 attr->sample_type |= PERF_SAMPLE_TIME;
441 attr->sample_type |= PERF_SAMPLE_CPU;
442
443 attr->sample_period = 1;
444
446 445
447 return EVT_HANDLED; 446 return EVT_HANDLED;
448} 447}
@@ -450,7 +449,8 @@ parse_single_tracepoint_event(char *sys_name,
450/* sys + ':' + event + ':' + flags*/ 449/* sys + ':' + event + ':' + flags*/
451#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) 450#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
452static enum event_result 451static enum event_result
453parse_subsystem_tracepoint_event(char *sys_name, char *flags) 452parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp,
453 char *flags)
454{ 454{
455 char evt_path[MAXPATHLEN]; 455 char evt_path[MAXPATHLEN];
456 struct dirent *evt_ent; 456 struct dirent *evt_ent;
@@ -474,6 +474,9 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
474 || !strcmp(evt_ent->d_name, "filter")) 474 || !strcmp(evt_ent->d_name, "filter"))
475 continue; 475 continue;
476 476
477 if (!strglobmatch(evt_ent->d_name, evt_exp))
478 continue;
479
477 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name, 480 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s%s%s", sys_name,
478 evt_ent->d_name, flags ? ":" : "", 481 evt_ent->d_name, flags ? ":" : "",
479 flags ?: ""); 482 flags ?: "");
@@ -487,12 +490,11 @@ parse_subsystem_tracepoint_event(char *sys_name, char *flags)
487 return EVT_HANDLED_ALL; 490 return EVT_HANDLED_ALL;
488} 491}
489 492
490
491static enum event_result parse_tracepoint_event(const char **strp, 493static enum event_result parse_tracepoint_event(const char **strp,
492 struct perf_event_attr *attr) 494 struct perf_event_attr *attr)
493{ 495{
494 const char *evt_name; 496 const char *evt_name;
495 char *flags; 497 char *flags = NULL, *comma_loc;
496 char sys_name[MAX_EVENT_LENGTH]; 498 char sys_name[MAX_EVENT_LENGTH];
497 unsigned int sys_length, evt_length; 499 unsigned int sys_length, evt_length;
498 500
@@ -511,6 +513,11 @@ static enum event_result parse_tracepoint_event(const char **strp,
511 sys_name[sys_length] = '\0'; 513 sys_name[sys_length] = '\0';
512 evt_name = evt_name + 1; 514 evt_name = evt_name + 1;
513 515
516 comma_loc = strchr(evt_name, ',');
517 if (comma_loc) {
518 /* take the event name up to the comma */
519 evt_name = strndup(evt_name, comma_loc - evt_name);
520 }
514 flags = strchr(evt_name, ':'); 521 flags = strchr(evt_name, ':');
515 if (flags) { 522 if (flags) {
516 /* split it out: */ 523 /* split it out: */
@@ -521,14 +528,14 @@ static enum event_result parse_tracepoint_event(const char **strp,
521 evt_length = strlen(evt_name); 528 evt_length = strlen(evt_name);
522 if (evt_length >= MAX_EVENT_LENGTH) 529 if (evt_length >= MAX_EVENT_LENGTH)
523 return EVT_FAILED; 530 return EVT_FAILED;
524 531 if (strpbrk(evt_name, "*?")) {
525 if (!strcmp(evt_name, "*")) { 532 *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */
526 *strp = evt_name + evt_length; 533 return parse_multiple_tracepoint_event(sys_name, evt_name,
527 return parse_subsystem_tracepoint_event(sys_name, flags); 534 flags);
528 } else 535 } else {
529 return parse_single_tracepoint_event(sys_name, evt_name, 536 return parse_single_tracepoint_event(sys_name, evt_name,
530 evt_length, flags, 537 evt_length, attr, strp);
531 attr, strp); 538 }
532} 539}
533 540
534static enum event_result 541static enum event_result
@@ -599,8 +606,15 @@ parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
599 return EVT_FAILED; 606 return EVT_FAILED;
600 } 607 }
601 608
602 /* We should find a nice way to override the access type */ 609 /*
603 attr->bp_len = HW_BREAKPOINT_LEN_4; 610 * We should find a nice way to override the access length
611 * Provide some defaults for now
612 */
613 if (attr->bp_type == HW_BREAKPOINT_X)
614 attr->bp_len = sizeof(long);
615 else
616 attr->bp_len = HW_BREAKPOINT_LEN_4;
617
604 attr->type = PERF_TYPE_BREAKPOINT; 618 attr->type = PERF_TYPE_BREAKPOINT;
605 619
606 return EVT_HANDLED; 620 return EVT_HANDLED;
@@ -685,19 +699,29 @@ static enum event_result
685parse_event_modifier(const char **strp, struct perf_event_attr *attr) 699parse_event_modifier(const char **strp, struct perf_event_attr *attr)
686{ 700{
687 const char *str = *strp; 701 const char *str = *strp;
688 int eu = 1, ek = 1, eh = 1; 702 int exclude = 0;
703 int eu = 0, ek = 0, eh = 0, precise = 0;
689 704
690 if (*str++ != ':') 705 if (*str++ != ':')
691 return 0; 706 return 0;
692 while (*str) { 707 while (*str) {
693 if (*str == 'u') 708 if (*str == 'u') {
709 if (!exclude)
710 exclude = eu = ek = eh = 1;
694 eu = 0; 711 eu = 0;
695 else if (*str == 'k') 712 } else if (*str == 'k') {
713 if (!exclude)
714 exclude = eu = ek = eh = 1;
696 ek = 0; 715 ek = 0;
697 else if (*str == 'h') 716 } else if (*str == 'h') {
717 if (!exclude)
718 exclude = eu = ek = eh = 1;
698 eh = 0; 719 eh = 0;
699 else 720 } else if (*str == 'p') {
721 precise++;
722 } else
700 break; 723 break;
724
701 ++str; 725 ++str;
702 } 726 }
703 if (str >= *strp + 2) { 727 if (str >= *strp + 2) {
@@ -705,6 +729,7 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
705 attr->exclude_user = eu; 729 attr->exclude_user = eu;
706 attr->exclude_kernel = ek; 730 attr->exclude_kernel = ek;
707 attr->exclude_hv = eh; 731 attr->exclude_hv = eh;
732 attr->precise_ip = precise;
708 return 1; 733 return 1;
709 } 734 }
710 return 0; 735 return 0;
@@ -753,41 +778,12 @@ modifier:
753 return ret; 778 return ret;
754} 779}
755 780
756static void store_event_type(const char *orgname)
757{
758 char filename[PATH_MAX], *c;
759 FILE *file;
760 int id;
761
762 sprintf(filename, "%s/", debugfs_path);
763 strncat(filename, orgname, strlen(orgname));
764 strcat(filename, "/id");
765
766 c = strchr(filename, ':');
767 if (c)
768 *c = '/';
769
770 file = fopen(filename, "r");
771 if (!file)
772 return;
773 if (fscanf(file, "%i", &id) < 1)
774 die("cannot store event ID");
775 fclose(file);
776 perf_header__push_event(id, orgname);
777}
778
779int parse_events(const struct option *opt __used, const char *str, int unset __used) 781int parse_events(const struct option *opt __used, const char *str, int unset __used)
780{ 782{
781 struct perf_event_attr attr; 783 struct perf_event_attr attr;
782 enum event_result ret; 784 enum event_result ret;
783 785
784 if (strchr(str, ':'))
785 store_event_type(str);
786
787 for (;;) { 786 for (;;) {
788 if (nr_counters == MAX_COUNTERS)
789 return -1;
790
791 memset(&attr, 0, sizeof(attr)); 787 memset(&attr, 0, sizeof(attr));
792 ret = parse_event_symbols(&str, &attr); 788 ret = parse_event_symbols(&str, &attr);
793 if (ret == EVT_FAILED) 789 if (ret == EVT_FAILED)
@@ -797,8 +793,13 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
797 return -1; 793 return -1;
798 794
799 if (ret != EVT_HANDLED_ALL) { 795 if (ret != EVT_HANDLED_ALL) {
800 attrs[nr_counters] = attr; 796 struct perf_evsel *evsel;
801 nr_counters++; 797 evsel = perf_evsel__new(&attr,
798 nr_counters);
799 if (evsel == NULL)
800 return -1;
801 list_add_tail(&evsel->node, &evsel_list);
802 ++nr_counters;
802 } 803 }
803 804
804 if (*str == 0) 805 if (*str == 0)
@@ -815,31 +816,33 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
815int parse_filter(const struct option *opt __used, const char *str, 816int parse_filter(const struct option *opt __used, const char *str,
816 int unset __used) 817 int unset __used)
817{ 818{
818 int i = nr_counters - 1; 819 struct perf_evsel *last = NULL;
819 int len = strlen(str); 820
821 if (!list_empty(&evsel_list))
822 last = list_entry(evsel_list.prev, struct perf_evsel, node);
820 823
821 if (i < 0 || attrs[i].type != PERF_TYPE_TRACEPOINT) { 824 if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) {
822 fprintf(stderr, 825 fprintf(stderr,
823 "-F option should follow a -e tracepoint option\n"); 826 "-F option should follow a -e tracepoint option\n");
824 return -1; 827 return -1;
825 } 828 }
826 829
827 filters[i] = malloc(len + 1); 830 last->filter = strdup(str);
828 if (!filters[i]) { 831 if (last->filter == NULL) {
829 fprintf(stderr, "not enough memory to hold filter string\n"); 832 fprintf(stderr, "not enough memory to hold filter string\n");
830 return -1; 833 return -1;
831 } 834 }
832 strcpy(filters[i], str);
833 835
834 return 0; 836 return 0;
835} 837}
836 838
837static const char * const event_type_descriptors[] = { 839static const char * const event_type_descriptors[] = {
838 "",
839 "Hardware event", 840 "Hardware event",
840 "Software event", 841 "Software event",
841 "Tracepoint event", 842 "Tracepoint event",
842 "Hardware cache event", 843 "Hardware cache event",
844 "Raw hardware event descriptor",
845 "Hardware breakpoint",
843}; 846};
844 847
845/* 848/*
@@ -872,7 +875,7 @@ static void print_tracepoint_events(void)
872 snprintf(evt_path, MAXPATHLEN, "%s:%s", 875 snprintf(evt_path, MAXPATHLEN, "%s:%s",
873 sys_dirent.d_name, evt_dirent.d_name); 876 sys_dirent.d_name, evt_dirent.d_name);
874 printf(" %-42s [%s]\n", evt_path, 877 printf(" %-42s [%s]\n", evt_path,
875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 878 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
876 } 879 }
877 closedir(evt_dir); 880 closedir(evt_dir);
878 } 881 }
@@ -880,6 +883,47 @@ static void print_tracepoint_events(void)
880} 883}
881 884
882/* 885/*
886 * Check whether event is in <debugfs_mount_point>/tracing/events
887 */
888
889int is_valid_tracepoint(const char *event_string)
890{
891 DIR *sys_dir, *evt_dir;
892 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
893 char evt_path[MAXPATHLEN];
894 char dir_path[MAXPATHLEN];
895
896 if (debugfs_valid_mountpoint(debugfs_path))
897 return 0;
898
899 sys_dir = opendir(debugfs_path);
900 if (!sys_dir)
901 return 0;
902
903 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
904
905 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
906 sys_dirent.d_name);
907 evt_dir = opendir(dir_path);
908 if (!evt_dir)
909 continue;
910
911 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
912 snprintf(evt_path, MAXPATHLEN, "%s:%s",
913 sys_dirent.d_name, evt_dirent.d_name);
914 if (!strcmp(evt_path, event_string)) {
915 closedir(evt_dir);
916 closedir(sys_dir);
917 return 1;
918 }
919 }
920 closedir(evt_dir);
921 }
922 closedir(sys_dir);
923 return 0;
924}
925
926/*
883 * Print the help text for the event symbols: 927 * Print the help text for the event symbols:
884 */ 928 */
885void print_events(void) 929void print_events(void)
@@ -892,9 +936,7 @@ void print_events(void)
892 printf("List of pre-defined events (to be used in -e):\n"); 936 printf("List of pre-defined events (to be used in -e):\n");
893 937
894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 938 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
895 type = syms->type + 1; 939 type = syms->type;
896 if (type >= ARRAY_SIZE(event_type_descriptors))
897 type = 0;
898 940
899 if (type != prev_type) 941 if (type != prev_type)
900 printf("\n"); 942 printf("\n");
@@ -919,20 +961,53 @@ void print_events(void)
919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 961 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
920 printf(" %-42s [%s]\n", 962 printf(" %-42s [%s]\n",
921 event_cache_name(type, op, i), 963 event_cache_name(type, op, i),
922 event_type_descriptors[4]); 964 event_type_descriptors[PERF_TYPE_HW_CACHE]);
923 } 965 }
924 } 966 }
925 } 967 }
926 968
927 printf("\n"); 969 printf("\n");
928 printf(" %-42s [raw hardware event descriptor]\n", 970 printf(" %-42s [%s]\n",
929 "rNNN"); 971 "rNNN (see 'perf list --help' on how to encode it)",
972 event_type_descriptors[PERF_TYPE_RAW]);
930 printf("\n"); 973 printf("\n");
931 974
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]"); 975 printf(" %-42s [%s]\n",
976 "mem:<addr>[:access]",
977 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
933 printf("\n"); 978 printf("\n");
934 979
935 print_tracepoint_events(); 980 print_tracepoint_events();
936 981
937 exit(129); 982 exit(129);
938} 983}
984
985int perf_evsel_list__create_default(void)
986{
987 struct perf_evsel *evsel;
988 struct perf_event_attr attr;
989
990 memset(&attr, 0, sizeof(attr));
991 attr.type = PERF_TYPE_HARDWARE;
992 attr.config = PERF_COUNT_HW_CPU_CYCLES;
993
994 evsel = perf_evsel__new(&attr, 0);
995
996 if (evsel == NULL)
997 return -ENOMEM;
998
999 list_add(&evsel->node, &evsel_list);
1000 ++nr_counters;
1001 return 0;
1002}
1003
1004void perf_evsel_list__delete(void)
1005{
1006 struct perf_evsel *pos, *n;
1007
1008 list_for_each_entry_safe(pos, n, &evsel_list, node) {
1009 list_del_init(&pos->node);
1010 perf_evsel__delete(pos);
1011 }
1012 nr_counters = 0;
1013}
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b8c1f64bc935..b82cafb83772 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,6 +4,16 @@
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
6 6
7#include "../../../include/linux/perf_event.h"
8
9struct list_head;
10struct perf_evsel;
11
12extern struct list_head evsel_list;
13
14int perf_evsel_list__create_default(void);
15void perf_evsel_list__delete(void);
16
7struct option; 17struct option;
8 18
9struct tracepoint_path { 19struct tracepoint_path {
@@ -13,13 +23,11 @@ struct tracepoint_path {
13}; 23};
14 24
15extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 25extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern bool have_tracepoints(struct list_head *evsel_list);
16 27
17extern int nr_counters; 28extern int nr_counters;
18 29
19extern struct perf_event_attr attrs[MAX_COUNTERS]; 30const char *event_name(struct perf_evsel *event);
20extern char *filters[MAX_COUNTERS];
21
22extern const char *event_name(int ctr);
23extern const char *__event_name(int type, u64 config); 31extern const char *__event_name(int type, u64 config);
24 32
25extern int parse_events(const struct option *opt, const char *str, int unset); 33extern int parse_events(const struct option *opt, const char *str, int unset);
@@ -28,9 +36,9 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
28#define EVENTS_HELP_MAX (128*1024) 36#define EVENTS_HELP_MAX (128*1024)
29 37
30extern void print_events(void); 38extern void print_events(void);
39extern int is_valid_tracepoint(const char *event_string);
31 40
32extern char debugfs_path[]; 41extern char debugfs_path[];
33extern int valid_debugfs_mount(const char *debugfs); 42extern int valid_debugfs_mount(const char *debugfs);
34 43
35
36#endif /* __PERF_PARSE_EVENTS_H */ 44#endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index efebd5b476b3..99d02aa57dbf 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -49,8 +49,9 @@ static int get_value(struct parse_opt_ctx_t *p,
49 break; 49 break;
50 /* FALLTHROUGH */ 50 /* FALLTHROUGH */
51 case OPTION_BOOLEAN: 51 case OPTION_BOOLEAN:
52 case OPTION_INCR:
52 case OPTION_BIT: 53 case OPTION_BIT:
53 case OPTION_SET_INT: 54 case OPTION_SET_UINT:
54 case OPTION_SET_PTR: 55 case OPTION_SET_PTR:
55 return opterror(opt, "takes no value", flags); 56 return opterror(opt, "takes no value", flags);
56 case OPTION_END: 57 case OPTION_END:
@@ -58,7 +59,9 @@ static int get_value(struct parse_opt_ctx_t *p,
58 case OPTION_GROUP: 59 case OPTION_GROUP:
59 case OPTION_STRING: 60 case OPTION_STRING:
60 case OPTION_INTEGER: 61 case OPTION_INTEGER:
62 case OPTION_UINTEGER:
61 case OPTION_LONG: 63 case OPTION_LONG:
64 case OPTION_U64:
62 default: 65 default:
63 break; 66 break;
64 } 67 }
@@ -73,11 +76,15 @@ static int get_value(struct parse_opt_ctx_t *p,
73 return 0; 76 return 0;
74 77
75 case OPTION_BOOLEAN: 78 case OPTION_BOOLEAN:
79 *(bool *)opt->value = unset ? false : true;
80 return 0;
81
82 case OPTION_INCR:
76 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; 83 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
77 return 0; 84 return 0;
78 85
79 case OPTION_SET_INT: 86 case OPTION_SET_UINT:
80 *(int *)opt->value = unset ? 0 : opt->defval; 87 *(unsigned int *)opt->value = unset ? 0 : opt->defval;
81 return 0; 88 return 0;
82 89
83 case OPTION_SET_PTR: 90 case OPTION_SET_PTR:
@@ -120,6 +127,22 @@ static int get_value(struct parse_opt_ctx_t *p,
120 return opterror(opt, "expects a numerical value", flags); 127 return opterror(opt, "expects a numerical value", flags);
121 return 0; 128 return 0;
122 129
130 case OPTION_UINTEGER:
131 if (unset) {
132 *(unsigned int *)opt->value = 0;
133 return 0;
134 }
135 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
136 *(unsigned int *)opt->value = opt->defval;
137 return 0;
138 }
139 if (get_arg(p, opt, flags, &arg))
140 return -1;
141 *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
142 if (*s)
143 return opterror(opt, "expects a numerical value", flags);
144 return 0;
145
123 case OPTION_LONG: 146 case OPTION_LONG:
124 if (unset) { 147 if (unset) {
125 *(long *)opt->value = 0; 148 *(long *)opt->value = 0;
@@ -136,6 +159,22 @@ static int get_value(struct parse_opt_ctx_t *p,
136 return opterror(opt, "expects a numerical value", flags); 159 return opterror(opt, "expects a numerical value", flags);
137 return 0; 160 return 0;
138 161
162 case OPTION_U64:
163 if (unset) {
164 *(u64 *)opt->value = 0;
165 return 0;
166 }
167 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
168 *(u64 *)opt->value = opt->defval;
169 return 0;
170 }
171 if (get_arg(p, opt, flags, &arg))
172 return -1;
173 *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
174 if (*s)
175 return opterror(opt, "expects a numerical value", flags);
176 return 0;
177
139 case OPTION_END: 178 case OPTION_END:
140 case OPTION_ARGUMENT: 179 case OPTION_ARGUMENT:
141 case OPTION_GROUP: 180 case OPTION_GROUP:
@@ -441,7 +480,10 @@ int usage_with_options_internal(const char * const *usagestr,
441 switch (opts->type) { 480 switch (opts->type) {
442 case OPTION_ARGUMENT: 481 case OPTION_ARGUMENT:
443 break; 482 break;
483 case OPTION_LONG:
484 case OPTION_U64:
444 case OPTION_INTEGER: 485 case OPTION_INTEGER:
486 case OPTION_UINTEGER:
445 if (opts->flags & PARSE_OPT_OPTARG) 487 if (opts->flags & PARSE_OPT_OPTARG)
446 if (opts->long_name) 488 if (opts->long_name)
447 pos += fprintf(stderr, "[=<n>]"); 489 pos += fprintf(stderr, "[=<n>]");
@@ -473,14 +515,14 @@ int usage_with_options_internal(const char * const *usagestr,
473 pos += fprintf(stderr, " ..."); 515 pos += fprintf(stderr, " ...");
474 } 516 }
475 break; 517 break;
476 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ 518 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
477 case OPTION_END: 519 case OPTION_END:
478 case OPTION_GROUP: 520 case OPTION_GROUP:
479 case OPTION_BIT: 521 case OPTION_BIT:
480 case OPTION_BOOLEAN: 522 case OPTION_BOOLEAN:
481 case OPTION_SET_INT: 523 case OPTION_INCR:
524 case OPTION_SET_UINT:
482 case OPTION_SET_PTR: 525 case OPTION_SET_PTR:
483 case OPTION_LONG:
484 break; 526 break;
485 } 527 }
486 528
@@ -500,6 +542,7 @@ int usage_with_options_internal(const char * const *usagestr,
500void usage_with_options(const char * const *usagestr, 542void usage_with_options(const char * const *usagestr,
501 const struct option *opts) 543 const struct option *opts)
502{ 544{
545 exit_browser(false);
503 usage_with_options_internal(usagestr, opts, 0); 546 usage_with_options_internal(usagestr, opts, 0);
504 exit(129); 547 exit(129);
505} 548}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 948805af43c2..abc31a1dac1a 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -1,6 +1,9 @@
1#ifndef __PERF_PARSE_OPTIONS_H 1#ifndef __PERF_PARSE_OPTIONS_H
2#define __PERF_PARSE_OPTIONS_H 2#define __PERF_PARSE_OPTIONS_H
3 3
4#include <linux/kernel.h>
5#include <stdbool.h>
6
4enum parse_opt_type { 7enum parse_opt_type {
5 /* special types */ 8 /* special types */
6 OPTION_END, 9 OPTION_END,
@@ -8,14 +11,17 @@ enum parse_opt_type {
8 OPTION_GROUP, 11 OPTION_GROUP,
9 /* options with no arguments */ 12 /* options with no arguments */
10 OPTION_BIT, 13 OPTION_BIT,
11 OPTION_BOOLEAN, /* _INCR would have been a better name */ 14 OPTION_BOOLEAN,
12 OPTION_SET_INT, 15 OPTION_INCR,
16 OPTION_SET_UINT,
13 OPTION_SET_PTR, 17 OPTION_SET_PTR,
14 /* options with arguments (usually) */ 18 /* options with arguments (usually) */
15 OPTION_STRING, 19 OPTION_STRING,
16 OPTION_INTEGER, 20 OPTION_INTEGER,
17 OPTION_LONG, 21 OPTION_LONG,
18 OPTION_CALLBACK, 22 OPTION_CALLBACK,
23 OPTION_U64,
24 OPTION_UINTEGER,
19}; 25};
20 26
21enum parse_opt_flags { 27enum parse_opt_flags {
@@ -73,7 +79,7 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
73 * 79 *
74 * `defval`:: 80 * `defval`::
75 * default value to fill (*->value) with for PARSE_OPT_OPTARG. 81 * default value to fill (*->value) with for PARSE_OPT_OPTARG.
76 * OPTION_{BIT,SET_INT,SET_PTR} store the {mask,integer,pointer} to put in 82 * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
77 * the value when met. 83 * the value when met.
78 * CALLBACKS can use it like they want. 84 * CALLBACKS can use it like they want.
79 */ 85 */
@@ -90,16 +96,21 @@ struct option {
90 intptr_t defval; 96 intptr_t defval;
91}; 97};
92 98
99#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
100
93#define OPT_END() { .type = OPTION_END } 101#define OPT_END() { .type = OPTION_END }
94#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) } 102#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
95#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } 103#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
96#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (b) } 104#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) }
97#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = (v), .help = (h) } 105#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
98#define OPT_SET_INT(s, l, v, h, i) { .type = OPTION_SET_INT, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (i) } 106#define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
107#define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) }
99#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) } 108#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
100#define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = (v), .help = (h) } 109#define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
101#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = (v), .help = (h) } 110#define OPT_UINTEGER(s, l, v, h) { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) }
102#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h) } 111#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
112#define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
113#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
103#define OPT_DATE(s, l, v, h) \ 114#define OPT_DATE(s, l, v, h) \
104 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb } 115 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
105#define OPT_CALLBACK(s, l, v, a, h, f) \ 116#define OPT_CALLBACK(s, l, v, a, h, f) \
@@ -108,6 +119,10 @@ struct option {
108 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG } 119 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
109#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \ 120#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
110 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT } 121 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
122#define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \
123 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
124 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
125 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
111 126
112/* parse_options() will filter out the processed options and leave the 127/* parse_options() will filter out the processed options and leave the
113 * non-option argments in argv[]. 128 * non-option argments in argv[].
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index fd1f2faaade4..bd7497711424 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -22,6 +22,7 @@ static const char *get_perf_dir(void)
22 return "."; 22 return ".";
23} 23}
24 24
25#ifdef NO_STRLCPY
25size_t strlcpy(char *dest, const char *src, size_t size) 26size_t strlcpy(char *dest, const char *src, size_t size)
26{ 27{
27 size_t ret = strlen(src); 28 size_t ret = strlen(src);
@@ -33,7 +34,7 @@ size_t strlcpy(char *dest, const char *src, size_t size)
33 } 34 }
34 return ret; 35 return ret;
35} 36}
36 37#endif
37 38
38static char *get_pathname(void) 39static char *get_pathname(void)
39{ 40{
@@ -54,21 +55,6 @@ static char *cleanup_path(char *path)
54 return path; 55 return path;
55} 56}
56 57
57char *mksnpath(char *buf, size_t n, const char *fmt, ...)
58{
59 va_list args;
60 unsigned len;
61
62 va_start(args, fmt);
63 len = vsnprintf(buf, n, fmt, args);
64 va_end(args);
65 if (len >= n) {
66 strlcpy(buf, bad_path, n);
67 return buf;
68 }
69 return cleanup_path(buf);
70}
71
72static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args) 58static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
73{ 59{
74 const char *perf_dir = get_perf_dir(); 60 const char *perf_dir = get_perf_dir();
@@ -89,15 +75,6 @@ bad:
89 return buf; 75 return buf;
90} 76}
91 77
92char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
93{
94 va_list args;
95 va_start(args, fmt);
96 (void)perf_vsnpath(buf, n, fmt, args);
97 va_end(args);
98 return buf;
99}
100
101char *perf_pathdup(const char *fmt, ...) 78char *perf_pathdup(const char *fmt, ...)
102{ 79{
103 char path[PATH_MAX]; 80 char path[PATH_MAX];
@@ -143,184 +120,6 @@ char *perf_path(const char *fmt, ...)
143 return cleanup_path(pathname); 120 return cleanup_path(pathname);
144} 121}
145 122
146
147/* perf_mkstemp() - create tmp file honoring TMPDIR variable */
148int perf_mkstemp(char *path, size_t len, const char *template)
149{
150 const char *tmp;
151 size_t n;
152
153 tmp = getenv("TMPDIR");
154 if (!tmp)
155 tmp = "/tmp";
156 n = snprintf(path, len, "%s/%s", tmp, template);
157 if (len <= n) {
158 errno = ENAMETOOLONG;
159 return -1;
160 }
161 return mkstemp(path);
162}
163
164
165const char *make_relative_path(const char *abs_path, const char *base)
166{
167 static char buf[PATH_MAX + 1];
168 int baselen;
169
170 if (!base)
171 return abs_path;
172
173 baselen = strlen(base);
174 if (prefixcmp(abs_path, base))
175 return abs_path;
176 if (abs_path[baselen] == '/')
177 baselen++;
178 else if (base[baselen - 1] != '/')
179 return abs_path;
180
181 strcpy(buf, abs_path + baselen);
182
183 return buf;
184}
185
186/*
187 * It is okay if dst == src, but they should not overlap otherwise.
188 *
189 * Performs the following normalizations on src, storing the result in dst:
190 * - Ensures that components are separated by '/' (Windows only)
191 * - Squashes sequences of '/'.
192 * - Removes "." components.
193 * - Removes ".." components, and the components the precede them.
194 * Returns failure (non-zero) if a ".." component appears as first path
195 * component anytime during the normalization. Otherwise, returns success (0).
196 *
197 * Note that this function is purely textual. It does not follow symlinks,
198 * verify the existence of the path, or make any system calls.
199 */
200int normalize_path_copy(char *dst, const char *src)
201{
202 char *dst0;
203
204 if (has_dos_drive_prefix(src)) {
205 *dst++ = *src++;
206 *dst++ = *src++;
207 }
208 dst0 = dst;
209
210 if (is_dir_sep(*src)) {
211 *dst++ = '/';
212 while (is_dir_sep(*src))
213 src++;
214 }
215
216 for (;;) {
217 char c = *src;
218
219 /*
220 * A path component that begins with . could be
221 * special:
222 * (1) "." and ends -- ignore and terminate.
223 * (2) "./" -- ignore them, eat slash and continue.
224 * (3) ".." and ends -- strip one and terminate.
225 * (4) "../" -- strip one, eat slash and continue.
226 */
227 if (c == '.') {
228 if (!src[1]) {
229 /* (1) */
230 src++;
231 } else if (is_dir_sep(src[1])) {
232 /* (2) */
233 src += 2;
234 while (is_dir_sep(*src))
235 src++;
236 continue;
237 } else if (src[1] == '.') {
238 if (!src[2]) {
239 /* (3) */
240 src += 2;
241 goto up_one;
242 } else if (is_dir_sep(src[2])) {
243 /* (4) */
244 src += 3;
245 while (is_dir_sep(*src))
246 src++;
247 goto up_one;
248 }
249 }
250 }
251
252 /* copy up to the next '/', and eat all '/' */
253 while ((c = *src++) != '\0' && !is_dir_sep(c))
254 *dst++ = c;
255 if (is_dir_sep(c)) {
256 *dst++ = '/';
257 while (is_dir_sep(c))
258 c = *src++;
259 src--;
260 } else if (!c)
261 break;
262 continue;
263
264 up_one:
265 /*
266 * dst0..dst is prefix portion, and dst[-1] is '/';
267 * go up one level.
268 */
269 dst--; /* go to trailing '/' */
270 if (dst <= dst0)
271 return -1;
272 /* Windows: dst[-1] cannot be backslash anymore */
273 while (dst0 < dst && dst[-1] != '/')
274 dst--;
275 }
276 *dst = '\0';
277 return 0;
278}
279
280/*
281 * path = Canonical absolute path
282 * prefix_list = Colon-separated list of absolute paths
283 *
284 * Determines, for each path in prefix_list, whether the "prefix" really
285 * is an ancestor directory of path. Returns the length of the longest
286 * ancestor directory, excluding any trailing slashes, or -1 if no prefix
287 * is an ancestor. (Note that this means 0 is returned if prefix_list is
288 * "/".) "/foo" is not considered an ancestor of "/foobar". Directories
289 * are not considered to be their own ancestors. path must be in a
290 * canonical form: empty components, or "." or ".." components are not
291 * allowed. prefix_list may be null, which is like "".
292 */
293int longest_ancestor_length(const char *path, const char *prefix_list)
294{
295 char buf[PATH_MAX+1];
296 const char *ceil, *colon;
297 int len, max_len = -1;
298
299 if (prefix_list == NULL || !strcmp(path, "/"))
300 return -1;
301
302 for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
303 for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
304 len = colon - ceil;
305 if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
306 continue;
307 strlcpy(buf, ceil, len+1);
308 if (normalize_path_copy(buf, buf) < 0)
309 continue;
310 len = strlen(buf);
311 if (len > 0 && buf[len-1] == '/')
312 buf[--len] = '\0';
313
314 if (!strncmp(path, buf, len) &&
315 path[len] == '/' &&
316 len > max_len) {
317 max_len = len;
318 }
319 }
320
321 return max_len;
322}
323
324/* strip arbitrary amount of directory separators at end of path */ 123/* strip arbitrary amount of directory separators at end of path */
325static inline int chomp_trailing_dir_sep(const char *path, int len) 124static inline int chomp_trailing_dir_sep(const char *path, int len)
326{ 125{
@@ -354,5 +153,5 @@ char *strip_path_suffix(const char *path, const char *suffix)
354 153
355 if (path_len && !is_dir_sep(path[path_len - 1])) 154 if (path_len && !is_dir_sep(path[path_len - 1]))
356 return NULL; 155 return NULL;
357 return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); 156 return strndup(path, chomp_trailing_dir_sep(path, path_len));
358} 157}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 29465d440043..128aaab0aeda 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * probe-event.c : perf-probe definition to kprobe_events format converter 2 * probe-event.c : perf-probe definition to probe_events format converter
3 * 3 *
4 * Written by Masami Hiramatsu <mhiramat@redhat.com> 4 * Written by Masami Hiramatsu <mhiramat@redhat.com>
5 * 5 *
@@ -33,18 +33,27 @@
33#include <limits.h> 33#include <limits.h>
34 34
35#undef _GNU_SOURCE 35#undef _GNU_SOURCE
36#include "util.h"
36#include "event.h" 37#include "event.h"
37#include "string.h" 38#include "string.h"
38#include "strlist.h" 39#include "strlist.h"
39#include "debug.h" 40#include "debug.h"
40#include "parse-events.h" /* For debugfs_path */ 41#include "cache.h"
42#include "color.h"
43#include "symbol.h"
44#include "thread.h"
45#include "debugfs.h"
46#include "trace-event.h" /* For __unused */
41#include "probe-event.h" 47#include "probe-event.h"
48#include "probe-finder.h"
42 49
43#define MAX_CMDLEN 256 50#define MAX_CMDLEN 256
44#define MAX_PROBE_ARGS 128 51#define MAX_PROBE_ARGS 128
45#define PERFPROBE_GROUP "probe" 52#define PERFPROBE_GROUP "probe"
46 53
47#define semantic_error(msg ...) die("Semantic error :" msg) 54bool probe_event_dry_run; /* Dry run flag */
55
56#define semantic_error(msg ...) pr_err("Semantic error :" msg)
48 57
49/* If there is no space to write, returns -E2BIG. */ 58/* If there is no space to write, returns -E2BIG. */
50static int e_snprintf(char *str, size_t size, const char *format, ...) 59static int e_snprintf(char *str, size_t size, const char *format, ...)
@@ -62,6 +71,556 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
62 return ret; 71 return ret;
63} 72}
64 73
74static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75static struct machine machine;
76
77/* Initialize symbol maps and path of vmlinux/modules */
78static int init_vmlinux(void)
79{
80 int ret;
81
82 symbol_conf.sort_by_name = true;
83 if (symbol_conf.vmlinux_name == NULL)
84 symbol_conf.try_vmlinux_path = true;
85 else
86 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
87 ret = symbol__init();
88 if (ret < 0) {
89 pr_debug("Failed to init symbol map.\n");
90 goto out;
91 }
92
93 ret = machine__init(&machine, "", HOST_KERNEL_ID);
94 if (ret < 0)
95 goto out;
96
97 if (machine__create_kernel_maps(&machine) < 0) {
98 pr_debug("machine__create_kernel_maps() failed.\n");
99 goto out;
100 }
101out:
102 if (ret < 0)
103 pr_warning("Failed to init vmlinux path.\n");
104 return ret;
105}
106
107static struct symbol *__find_kernel_function_by_name(const char *name,
108 struct map **mapp)
109{
110 return machine__find_kernel_function_by_name(&machine, name, mapp,
111 NULL);
112}
113
114const char *kernel_get_module_path(const char *module)
115{
116 struct dso *dso;
117 struct map *map;
118 const char *vmlinux_name;
119
120 if (module) {
121 list_for_each_entry(dso, &machine.kernel_dsos, node) {
122 if (strncmp(dso->short_name + 1, module,
123 dso->short_name_len - 2) == 0)
124 goto found;
125 }
126 pr_debug("Failed to find module %s.\n", module);
127 return NULL;
128 }
129
130 map = machine.vmlinux_maps[MAP__FUNCTION];
131 dso = map->dso;
132
133 vmlinux_name = symbol_conf.vmlinux_name;
134 if (vmlinux_name) {
135 if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0)
136 return NULL;
137 } else {
138 if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
139 pr_debug("Failed to load kernel map.\n");
140 return NULL;
141 }
142 }
143found:
144 return dso->long_name;
145}
146
147#ifdef DWARF_SUPPORT
148static int open_vmlinux(const char *module)
149{
150 const char *path = kernel_get_module_path(module);
151 if (!path) {
152 pr_err("Failed to find path of %s module.\n",
153 module ?: "kernel");
154 return -ENOENT;
155 }
156 pr_debug("Try to open %s\n", path);
157 return open(path, O_RDONLY);
158}
159
160/*
161 * Convert trace point to probe point with debuginfo
162 * Currently only handles kprobes.
163 */
164static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
165 struct perf_probe_point *pp)
166{
167 struct symbol *sym;
168 struct map *map;
169 u64 addr;
170 int ret = -ENOENT;
171
172 sym = __find_kernel_function_by_name(tp->symbol, &map);
173 if (sym) {
174 addr = map->unmap_ip(map, sym->start + tp->offset);
175 pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
176 tp->offset, addr);
177 ret = find_perf_probe_point((unsigned long)addr, pp);
178 }
179 if (ret <= 0) {
180 pr_debug("Failed to find corresponding probes from "
181 "debuginfo. Use kprobe event information.\n");
182 pp->function = strdup(tp->symbol);
183 if (pp->function == NULL)
184 return -ENOMEM;
185 pp->offset = tp->offset;
186 }
187 pp->retprobe = tp->retprobe;
188
189 return 0;
190}
191
192/* Try to find perf_probe_event with debuginfo */
193static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
194 struct probe_trace_event **tevs,
195 int max_tevs, const char *module)
196{
197 bool need_dwarf = perf_probe_event_need_dwarf(pev);
198 int fd, ntevs;
199
200 fd = open_vmlinux(module);
201 if (fd < 0) {
202 if (need_dwarf) {
203 pr_warning("Failed to open debuginfo file.\n");
204 return fd;
205 }
206 pr_debug("Could not open vmlinux. Try to use symbols.\n");
207 return 0;
208 }
209
210 /* Searching trace events corresponding to probe event */
211 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
212 close(fd);
213
214 if (ntevs > 0) { /* Succeeded to find trace events */
215 pr_debug("find %d probe_trace_events.\n", ntevs);
216 return ntevs;
217 }
218
219 if (ntevs == 0) { /* No error but failed to find probe point. */
220 pr_warning("Probe point '%s' not found.\n",
221 synthesize_perf_probe_point(&pev->point));
222 return -ENOENT;
223 }
224 /* Error path : ntevs < 0 */
225 pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
226 if (ntevs == -EBADF) {
227 pr_warning("Warning: No dwarf info found in the vmlinux - "
228 "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
229 if (!need_dwarf) {
230 pr_debug("Trying to use symbols.\n");
231 return 0;
232 }
233 }
234 return ntevs;
235}
236
237/*
238 * Find a src file from a DWARF tag path. Prepend optional source path prefix
239 * and chop off leading directories that do not exist. Result is passed back as
240 * a newly allocated path on success.
241 * Return 0 if file was found and readable, -errno otherwise.
242 */
243static int get_real_path(const char *raw_path, const char *comp_dir,
244 char **new_path)
245{
246 const char *prefix = symbol_conf.source_prefix;
247
248 if (!prefix) {
249 if (raw_path[0] != '/' && comp_dir)
250 /* If not an absolute path, try to use comp_dir */
251 prefix = comp_dir;
252 else {
253 if (access(raw_path, R_OK) == 0) {
254 *new_path = strdup(raw_path);
255 return 0;
256 } else
257 return -errno;
258 }
259 }
260
261 *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
262 if (!*new_path)
263 return -ENOMEM;
264
265 for (;;) {
266 sprintf(*new_path, "%s/%s", prefix, raw_path);
267
268 if (access(*new_path, R_OK) == 0)
269 return 0;
270
271 if (!symbol_conf.source_prefix)
272 /* In case of searching comp_dir, don't retry */
273 return -errno;
274
275 switch (errno) {
276 case ENAMETOOLONG:
277 case ENOENT:
278 case EROFS:
279 case EFAULT:
280 raw_path = strchr(++raw_path, '/');
281 if (!raw_path) {
282 free(*new_path);
283 *new_path = NULL;
284 return -ENOENT;
285 }
286 continue;
287
288 default:
289 free(*new_path);
290 *new_path = NULL;
291 return -errno;
292 }
293 }
294}
295
296#define LINEBUF_SIZE 256
297#define NR_ADDITIONAL_LINES 2
298
299static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
300{
301 char buf[LINEBUF_SIZE];
302 const char *color = show_num ? "" : PERF_COLOR_BLUE;
303 const char *prefix = NULL;
304
305 do {
306 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
307 goto error;
308 if (skip)
309 continue;
310 if (!prefix) {
311 prefix = show_num ? "%7d " : " ";
312 color_fprintf(stdout, color, prefix, l);
313 }
314 color_fprintf(stdout, color, "%s", buf);
315
316 } while (strchr(buf, '\n') == NULL);
317
318 return 1;
319error:
320 if (ferror(fp)) {
321 pr_warning("File read error: %s\n", strerror(errno));
322 return -1;
323 }
324 return 0;
325}
326
327static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
328{
329 int rv = __show_one_line(fp, l, skip, show_num);
330 if (rv == 0) {
331 pr_warning("Source file is shorter than expected.\n");
332 rv = -1;
333 }
334 return rv;
335}
336
337#define show_one_line_with_num(f,l) _show_one_line(f,l,false,true)
338#define show_one_line(f,l) _show_one_line(f,l,false,false)
339#define skip_one_line(f,l) _show_one_line(f,l,true,false)
340#define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false)
341
342/*
343 * Show line-range always requires debuginfo to find source file and
344 * line number.
345 */
346int show_line_range(struct line_range *lr, const char *module)
347{
348 int l = 1;
349 struct line_node *ln;
350 FILE *fp;
351 int fd, ret;
352 char *tmp;
353
354 /* Search a line range */
355 ret = init_vmlinux();
356 if (ret < 0)
357 return ret;
358
359 fd = open_vmlinux(module);
360 if (fd < 0) {
361 pr_warning("Failed to open debuginfo file.\n");
362 return fd;
363 }
364
365 ret = find_line_range(fd, lr);
366 close(fd);
367 if (ret == 0) {
368 pr_warning("Specified source line is not found.\n");
369 return -ENOENT;
370 } else if (ret < 0) {
371 pr_warning("Debuginfo analysis failed. (%d)\n", ret);
372 return ret;
373 }
374
375 /* Convert source file path */
376 tmp = lr->path;
377 ret = get_real_path(tmp, lr->comp_dir, &lr->path);
378 free(tmp); /* Free old path */
379 if (ret < 0) {
380 pr_warning("Failed to find source file. (%d)\n", ret);
381 return ret;
382 }
383
384 setup_pager();
385
386 if (lr->function)
387 fprintf(stdout, "<%s:%d>\n", lr->function,
388 lr->start - lr->offset);
389 else
390 fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
391
392 fp = fopen(lr->path, "r");
393 if (fp == NULL) {
394 pr_warning("Failed to open %s: %s\n", lr->path,
395 strerror(errno));
396 return -errno;
397 }
398 /* Skip to starting line number */
399 while (l < lr->start) {
400 ret = skip_one_line(fp, l++);
401 if (ret < 0)
402 goto end;
403 }
404
405 list_for_each_entry(ln, &lr->line_list, list) {
406 for (; ln->line > l; l++) {
407 ret = show_one_line(fp, l - lr->offset);
408 if (ret < 0)
409 goto end;
410 }
411 ret = show_one_line_with_num(fp, l++ - lr->offset);
412 if (ret < 0)
413 goto end;
414 }
415
416 if (lr->end == INT_MAX)
417 lr->end = l + NR_ADDITIONAL_LINES;
418 while (l <= lr->end) {
419 ret = show_one_line_or_eof(fp, l++ - lr->offset);
420 if (ret <= 0)
421 break;
422 }
423end:
424 fclose(fp);
425 return ret;
426}
427
428static int show_available_vars_at(int fd, struct perf_probe_event *pev,
429 int max_vls, bool externs)
430{
431 char *buf;
432 int ret, i;
433 struct str_node *node;
434 struct variable_list *vls = NULL, *vl;
435
436 buf = synthesize_perf_probe_point(&pev->point);
437 if (!buf)
438 return -EINVAL;
439 pr_debug("Searching variables at %s\n", buf);
440
441 ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
442 if (ret > 0) {
443 /* Some variables were found */
444 fprintf(stdout, "Available variables at %s\n", buf);
445 for (i = 0; i < ret; i++) {
446 vl = &vls[i];
447 /*
448 * A probe point might be converted to
449 * several trace points.
450 */
451 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
452 vl->point.offset);
453 free(vl->point.symbol);
454 if (vl->vars) {
455 strlist__for_each(node, vl->vars)
456 fprintf(stdout, "\t\t%s\n", node->s);
457 strlist__delete(vl->vars);
458 } else
459 fprintf(stdout, "(No variables)\n");
460 }
461 free(vls);
462 } else
463 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
464
465 free(buf);
466 return ret;
467}
468
469/* Show available variables on given probe point */
470int show_available_vars(struct perf_probe_event *pevs, int npevs,
471 int max_vls, const char *module, bool externs)
472{
473 int i, fd, ret = 0;
474
475 ret = init_vmlinux();
476 if (ret < 0)
477 return ret;
478
479 fd = open_vmlinux(module);
480 if (fd < 0) {
481 pr_warning("Failed to open debug information file.\n");
482 return fd;
483 }
484
485 setup_pager();
486
487 for (i = 0; i < npevs && ret >= 0; i++)
488 ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
489
490 close(fd);
491 return ret;
492}
493
494#else /* !DWARF_SUPPORT */
495
496static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
497 struct perf_probe_point *pp)
498{
499 struct symbol *sym;
500
501 sym = __find_kernel_function_by_name(tp->symbol, NULL);
502 if (!sym) {
503 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
504 return -ENOENT;
505 }
506 pp->function = strdup(tp->symbol);
507 if (pp->function == NULL)
508 return -ENOMEM;
509 pp->offset = tp->offset;
510 pp->retprobe = tp->retprobe;
511
512 return 0;
513}
514
515static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
516 struct probe_trace_event **tevs __unused,
517 int max_tevs __unused, const char *mod __unused)
518{
519 if (perf_probe_event_need_dwarf(pev)) {
520 pr_warning("Debuginfo-analysis is not supported.\n");
521 return -ENOSYS;
522 }
523 return 0;
524}
525
526int show_line_range(struct line_range *lr __unused, const char *module __unused)
527{
528 pr_warning("Debuginfo-analysis is not supported.\n");
529 return -ENOSYS;
530}
531
532int show_available_vars(struct perf_probe_event *pevs __unused,
533 int npevs __unused, int max_vls __unused,
534 const char *module __unused, bool externs __unused)
535{
536 pr_warning("Debuginfo-analysis is not supported.\n");
537 return -ENOSYS;
538}
539#endif
540
541static int parse_line_num(char **ptr, int *val, const char *what)
542{
543 const char *start = *ptr;
544
545 errno = 0;
546 *val = strtol(*ptr, ptr, 0);
547 if (errno || *ptr == start) {
548 semantic_error("'%s' is not a valid number.\n", what);
549 return -EINVAL;
550 }
551 return 0;
552}
553
554/*
555 * Stuff 'lr' according to the line range described by 'arg'.
556 * The line range syntax is described by:
557 *
558 * SRC[:SLN[+NUM|-ELN]]
559 * FNC[:SLN[+NUM|-ELN]]
560 */
561int parse_line_range_desc(const char *arg, struct line_range *lr)
562{
563 char *range, *name = strdup(arg);
564 int err;
565
566 if (!name)
567 return -ENOMEM;
568
569 lr->start = 0;
570 lr->end = INT_MAX;
571
572 range = strchr(name, ':');
573 if (range) {
574 *range++ = '\0';
575
576 err = parse_line_num(&range, &lr->start, "start line");
577 if (err)
578 goto err;
579
580 if (*range == '+' || *range == '-') {
581 const char c = *range++;
582
583 err = parse_line_num(&range, &lr->end, "end line");
584 if (err)
585 goto err;
586
587 if (c == '+') {
588 lr->end += lr->start;
589 /*
590 * Adjust the number of lines here.
591 * If the number of lines == 1, the
592 * the end of line should be equal to
593 * the start of line.
594 */
595 lr->end--;
596 }
597 }
598
599 pr_debug("Line range is %d to %d\n", lr->start, lr->end);
600
601 err = -EINVAL;
602 if (lr->start > lr->end) {
603 semantic_error("Start line must be smaller"
604 " than end line.\n");
605 goto err;
606 }
607 if (*range != '\0') {
608 semantic_error("Tailing with invalid str '%s'.\n", range);
609 goto err;
610 }
611 }
612
613 if (strchr(name, '.'))
614 lr->file = name;
615 else
616 lr->function = name;
617
618 return 0;
619err:
620 free(name);
621 return err;
622}
623
65/* Check the name is good for event/group */ 624/* Check the name is good for event/group */
66static bool check_event_name(const char *name) 625static bool check_event_name(const char *name)
67{ 626{
@@ -75,50 +634,66 @@ static bool check_event_name(const char *name)
75} 634}
76 635
77/* Parse probepoint definition. */ 636/* Parse probepoint definition. */
78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 637static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
79{ 638{
639 struct perf_probe_point *pp = &pev->point;
80 char *ptr, *tmp; 640 char *ptr, *tmp;
81 char c, nc = 0; 641 char c, nc = 0;
82 /* 642 /*
83 * <Syntax> 643 * <Syntax>
84 * perf probe [EVENT=]SRC:LN 644 * perf probe [EVENT=]SRC[:LN|;PTN]
85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC] 645 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
86 * 646 *
87 * TODO:Group name support 647 * TODO:Group name support
88 */ 648 */
89 649
90 ptr = strchr(arg, '='); 650 ptr = strpbrk(arg, ";=@+%");
91 if (ptr) { /* Event name */ 651 if (ptr && *ptr == '=') { /* Event name */
92 *ptr = '\0'; 652 *ptr = '\0';
93 tmp = ptr + 1; 653 tmp = ptr + 1;
94 ptr = strchr(arg, ':'); 654 if (strchr(arg, ':')) {
95 if (ptr) /* Group name is not supported yet. */ 655 semantic_error("Group name is not supported yet.\n");
96 semantic_error("Group name is not supported yet."); 656 return -ENOTSUP;
97 if (!check_event_name(arg)) 657 }
658 if (!check_event_name(arg)) {
98 semantic_error("%s is bad for event name -it must " 659 semantic_error("%s is bad for event name -it must "
99 "follow C symbol-naming rule.", arg); 660 "follow C symbol-naming rule.\n", arg);
100 pp->event = strdup(arg); 661 return -EINVAL;
662 }
663 pev->event = strdup(arg);
664 if (pev->event == NULL)
665 return -ENOMEM;
666 pev->group = NULL;
101 arg = tmp; 667 arg = tmp;
102 } 668 }
103 669
104 ptr = strpbrk(arg, ":+@%"); 670 ptr = strpbrk(arg, ";:+@%");
105 if (ptr) { 671 if (ptr) {
106 nc = *ptr; 672 nc = *ptr;
107 *ptr++ = '\0'; 673 *ptr++ = '\0';
108 } 674 }
109 675
676 tmp = strdup(arg);
677 if (tmp == NULL)
678 return -ENOMEM;
679
110 /* Check arg is function or file and copy it */ 680 /* Check arg is function or file and copy it */
111 if (strchr(arg, '.')) /* File */ 681 if (strchr(tmp, '.')) /* File */
112 pp->file = strdup(arg); 682 pp->file = tmp;
113 else /* Function */ 683 else /* Function */
114 pp->function = strdup(arg); 684 pp->function = tmp;
115 DIE_IF(pp->file == NULL && pp->function == NULL);
116 685
117 /* Parse other options */ 686 /* Parse other options */
118 while (ptr) { 687 while (ptr) {
119 arg = ptr; 688 arg = ptr;
120 c = nc; 689 c = nc;
121 ptr = strpbrk(arg, ":+@%"); 690 if (c == ';') { /* Lazy pattern must be the last part */
691 pp->lazy_line = strdup(arg);
692 if (pp->lazy_line == NULL)
693 return -ENOMEM;
694 break;
695 }
696 ptr = strpbrk(arg, ";:+@%");
122 if (ptr) { 697 if (ptr) {
123 nc = *ptr; 698 nc = *ptr;
124 *ptr++ = '\0'; 699 *ptr++ = '\0';
@@ -126,258 +701,691 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
126 switch (c) { 701 switch (c) {
127 case ':': /* Line number */ 702 case ':': /* Line number */
128 pp->line = strtoul(arg, &tmp, 0); 703 pp->line = strtoul(arg, &tmp, 0);
129 if (*tmp != '\0') 704 if (*tmp != '\0') {
130 semantic_error("There is non-digit charactor" 705 semantic_error("There is non-digit char"
131 " in line number."); 706 " in line number.\n");
707 return -EINVAL;
708 }
132 break; 709 break;
133 case '+': /* Byte offset from a symbol */ 710 case '+': /* Byte offset from a symbol */
134 pp->offset = strtoul(arg, &tmp, 0); 711 pp->offset = strtoul(arg, &tmp, 0);
135 if (*tmp != '\0') 712 if (*tmp != '\0') {
136 semantic_error("There is non-digit charactor" 713 semantic_error("There is non-digit character"
137 " in offset."); 714 " in offset.\n");
715 return -EINVAL;
716 }
138 break; 717 break;
139 case '@': /* File name */ 718 case '@': /* File name */
140 if (pp->file) 719 if (pp->file) {
141 semantic_error("SRC@SRC is not allowed."); 720 semantic_error("SRC@SRC is not allowed.\n");
721 return -EINVAL;
722 }
142 pp->file = strdup(arg); 723 pp->file = strdup(arg);
143 DIE_IF(pp->file == NULL); 724 if (pp->file == NULL)
144 if (ptr) 725 return -ENOMEM;
145 semantic_error("@SRC must be the last "
146 "option.");
147 break; 726 break;
148 case '%': /* Probe places */ 727 case '%': /* Probe places */
149 if (strcmp(arg, "return") == 0) { 728 if (strcmp(arg, "return") == 0) {
150 pp->retprobe = 1; 729 pp->retprobe = 1;
151 } else /* Others not supported yet */ 730 } else { /* Others not supported yet */
152 semantic_error("%%%s is not supported.", arg); 731 semantic_error("%%%s is not supported.\n", arg);
732 return -ENOTSUP;
733 }
153 break; 734 break;
154 default: 735 default: /* Buggy case */
155 DIE_IF("Program has a bug."); 736 pr_err("This program has a bug at %s:%d.\n",
737 __FILE__, __LINE__);
738 return -ENOTSUP;
156 break; 739 break;
157 } 740 }
158 } 741 }
159 742
160 /* Exclusion check */ 743 /* Exclusion check */
161 if (pp->line && pp->offset) 744 if (pp->lazy_line && pp->line) {
162 semantic_error("Offset can't be used with line number."); 745 semantic_error("Lazy pattern can't be used with"
746 " line number.\n");
747 return -EINVAL;
748 }
749
750 if (pp->lazy_line && pp->offset) {
751 semantic_error("Lazy pattern can't be used with offset.\n");
752 return -EINVAL;
753 }
163 754
164 if (!pp->line && pp->file && !pp->function) 755 if (pp->line && pp->offset) {
165 semantic_error("File always requires line number."); 756 semantic_error("Offset can't be used with line number.\n");
757 return -EINVAL;
758 }
166 759
167 if (pp->offset && !pp->function) 760 if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
168 semantic_error("Offset requires an entry function."); 761 semantic_error("File always requires line number or "
762 "lazy pattern.\n");
763 return -EINVAL;
764 }
765
766 if (pp->offset && !pp->function) {
767 semantic_error("Offset requires an entry function.\n");
768 return -EINVAL;
769 }
169 770
170 if (pp->retprobe && !pp->function) 771 if (pp->retprobe && !pp->function) {
171 semantic_error("Return probe requires an entry function."); 772 semantic_error("Return probe requires an entry function.\n");
773 return -EINVAL;
774 }
172 775
173 if ((pp->offset || pp->line) && pp->retprobe) 776 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
174 semantic_error("Offset/Line can't be used with return probe."); 777 semantic_error("Offset/Line/Lazy pattern can't be used with "
778 "return probe.\n");
779 return -EINVAL;
780 }
175 781
176 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", 782 pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
177 pp->function, pp->file, pp->line, pp->offset, pp->retprobe); 783 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
784 pp->lazy_line);
785 return 0;
178} 786}
179 787
180/* Parse perf-probe event definition */ 788/* Parse perf-probe event argument */
181void parse_perf_probe_event(const char *str, struct probe_point *pp, 789static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
182 bool *need_dwarf)
183{ 790{
184 char **argv; 791 char *tmp, *goodname;
185 int argc, i; 792 struct perf_probe_arg_field **fieldp;
793
794 pr_debug("parsing arg: %s into ", str);
795
796 tmp = strchr(str, '=');
797 if (tmp) {
798 arg->name = strndup(str, tmp - str);
799 if (arg->name == NULL)
800 return -ENOMEM;
801 pr_debug("name:%s ", arg->name);
802 str = tmp + 1;
803 }
804
805 tmp = strchr(str, ':');
806 if (tmp) { /* Type setting */
807 *tmp = '\0';
808 arg->type = strdup(tmp + 1);
809 if (arg->type == NULL)
810 return -ENOMEM;
811 pr_debug("type:%s ", arg->type);
812 }
813
814 tmp = strpbrk(str, "-.[");
815 if (!is_c_varname(str) || !tmp) {
816 /* A variable, register, symbol or special value */
817 arg->var = strdup(str);
818 if (arg->var == NULL)
819 return -ENOMEM;
820 pr_debug("%s\n", arg->var);
821 return 0;
822 }
186 823
187 *need_dwarf = false; 824 /* Structure fields or array element */
825 arg->var = strndup(str, tmp - str);
826 if (arg->var == NULL)
827 return -ENOMEM;
828 goodname = arg->var;
829 pr_debug("%s, ", arg->var);
830 fieldp = &arg->field;
831
832 do {
833 *fieldp = zalloc(sizeof(struct perf_probe_arg_field));
834 if (*fieldp == NULL)
835 return -ENOMEM;
836 if (*tmp == '[') { /* Array */
837 str = tmp;
838 (*fieldp)->index = strtol(str + 1, &tmp, 0);
839 (*fieldp)->ref = true;
840 if (*tmp != ']' || tmp == str + 1) {
841 semantic_error("Array index must be a"
842 " number.\n");
843 return -EINVAL;
844 }
845 tmp++;
846 if (*tmp == '\0')
847 tmp = NULL;
848 } else { /* Structure */
849 if (*tmp == '.') {
850 str = tmp + 1;
851 (*fieldp)->ref = false;
852 } else if (tmp[1] == '>') {
853 str = tmp + 2;
854 (*fieldp)->ref = true;
855 } else {
856 semantic_error("Argument parse error: %s\n",
857 str);
858 return -EINVAL;
859 }
860 tmp = strpbrk(str, "-.[");
861 }
862 if (tmp) {
863 (*fieldp)->name = strndup(str, tmp - str);
864 if ((*fieldp)->name == NULL)
865 return -ENOMEM;
866 if (*str != '[')
867 goodname = (*fieldp)->name;
868 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
869 fieldp = &(*fieldp)->next;
870 }
871 } while (tmp);
872 (*fieldp)->name = strdup(str);
873 if ((*fieldp)->name == NULL)
874 return -ENOMEM;
875 if (*str != '[')
876 goodname = (*fieldp)->name;
877 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
878
879 /* If no name is specified, set the last field name (not array index)*/
880 if (!arg->name) {
881 arg->name = strdup(goodname);
882 if (arg->name == NULL)
883 return -ENOMEM;
884 }
885 return 0;
886}
188 887
189 argv = argv_split(str, &argc); 888/* Parse perf-probe event command */
190 if (!argv) 889int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
191 die("argv_split failed."); 890{
192 if (argc > MAX_PROBE_ARGS + 1) 891 char **argv;
193 semantic_error("Too many arguments"); 892 int argc, i, ret = 0;
194 893
894 argv = argv_split(cmd, &argc);
895 if (!argv) {
896 pr_debug("Failed to split arguments.\n");
897 return -ENOMEM;
898 }
899 if (argc - 1 > MAX_PROBE_ARGS) {
900 semantic_error("Too many probe arguments (%d).\n", argc - 1);
901 ret = -ERANGE;
902 goto out;
903 }
195 /* Parse probe point */ 904 /* Parse probe point */
196 parse_perf_probe_probepoint(argv[0], pp); 905 ret = parse_perf_probe_point(argv[0], pev);
197 if (pp->file || pp->line) 906 if (ret < 0)
198 *need_dwarf = true; 907 goto out;
199 908
200 /* Copy arguments and ensure return probe has no C argument */ 909 /* Copy arguments and ensure return probe has no C argument */
201 pp->nr_args = argc - 1; 910 pev->nargs = argc - 1;
202 pp->args = zalloc(sizeof(char *) * pp->nr_args); 911 pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
203 for (i = 0; i < pp->nr_args; i++) { 912 if (pev->args == NULL) {
204 pp->args[i] = strdup(argv[i + 1]); 913 ret = -ENOMEM;
205 if (!pp->args[i]) 914 goto out;
206 die("Failed to copy argument."); 915 }
207 if (is_c_varname(pp->args[i])) { 916 for (i = 0; i < pev->nargs && ret >= 0; i++) {
208 if (pp->retprobe) 917 ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
209 semantic_error("You can't specify local" 918 if (ret >= 0 &&
210 " variable for kretprobe"); 919 is_c_varname(pev->args[i].var) && pev->point.retprobe) {
211 *need_dwarf = true; 920 semantic_error("You can't specify local variable for"
921 " kretprobe.\n");
922 ret = -EINVAL;
212 } 923 }
213 } 924 }
214 925out:
215 argv_free(argv); 926 argv_free(argv);
927
928 return ret;
929}
930
931/* Return true if this perf_probe_event requires debuginfo */
932bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
933{
934 int i;
935
936 if (pev->point.file || pev->point.line || pev->point.lazy_line)
937 return true;
938
939 for (i = 0; i < pev->nargs; i++)
940 if (is_c_varname(pev->args[i].var))
941 return true;
942
943 return false;
216} 944}
217 945
218/* Parse kprobe_events event into struct probe_point */ 946/* Parse probe_events event into struct probe_point */
219void parse_trace_kprobe_event(const char *str, struct probe_point *pp) 947static int parse_probe_trace_command(const char *cmd,
948 struct probe_trace_event *tev)
220{ 949{
950 struct probe_trace_point *tp = &tev->point;
221 char pr; 951 char pr;
222 char *p; 952 char *p;
223 int ret, i, argc; 953 int ret, i, argc;
224 char **argv; 954 char **argv;
225 955
226 pr_debug("Parsing kprobe_events: %s\n", str); 956 pr_debug("Parsing probe_events: %s\n", cmd);
227 argv = argv_split(str, &argc); 957 argv = argv_split(cmd, &argc);
228 if (!argv) 958 if (!argv) {
229 die("argv_split failed."); 959 pr_debug("Failed to split arguments.\n");
230 if (argc < 2) 960 return -ENOMEM;
231 semantic_error("Too less arguments."); 961 }
962 if (argc < 2) {
963 semantic_error("Too few probe arguments.\n");
964 ret = -ERANGE;
965 goto out;
966 }
232 967
233 /* Scan event and group name. */ 968 /* Scan event and group name. */
234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 969 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
235 &pr, (float *)(void *)&pp->group, 970 &pr, (float *)(void *)&tev->group,
236 (float *)(void *)&pp->event); 971 (float *)(void *)&tev->event);
237 if (ret != 3) 972 if (ret != 3) {
238 semantic_error("Failed to parse event name: %s", argv[0]); 973 semantic_error("Failed to parse event name: %s\n", argv[0]);
239 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); 974 ret = -EINVAL;
975 goto out;
976 }
977 pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
240 978
241 pp->retprobe = (pr == 'r'); 979 tp->retprobe = (pr == 'r');
242 980
243 /* Scan function name and offset */ 981 /* Scan function name and offset */
244 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, 982 ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
245 &pp->offset); 983 &tp->offset);
246 if (ret == 1) 984 if (ret == 1)
247 pp->offset = 0; 985 tp->offset = 0;
248
249 /* kprobe_events doesn't have this information */
250 pp->line = 0;
251 pp->file = NULL;
252 986
253 pp->nr_args = argc - 2; 987 tev->nargs = argc - 2;
254 pp->args = zalloc(sizeof(char *) * pp->nr_args); 988 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
255 for (i = 0; i < pp->nr_args; i++) { 989 if (tev->args == NULL) {
990 ret = -ENOMEM;
991 goto out;
992 }
993 for (i = 0; i < tev->nargs; i++) {
256 p = strchr(argv[i + 2], '='); 994 p = strchr(argv[i + 2], '=');
257 if (p) /* We don't need which register is assigned. */ 995 if (p) /* We don't need which register is assigned. */
258 *p = '\0'; 996 *p++ = '\0';
259 pp->args[i] = strdup(argv[i + 2]); 997 else
260 if (!pp->args[i]) 998 p = argv[i + 2];
261 die("Failed to copy argument."); 999 tev->args[i].name = strdup(argv[i + 2]);
1000 /* TODO: parse regs and offset */
1001 tev->args[i].value = strdup(p);
1002 if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
1003 ret = -ENOMEM;
1004 goto out;
1005 }
262 } 1006 }
263 1007 ret = 0;
1008out:
264 argv_free(argv); 1009 argv_free(argv);
1010 return ret;
265} 1011}
266 1012
267/* Synthesize only probe point (not argument) */ 1013/* Compose only probe arg */
268int synthesize_perf_probe_point(struct probe_point *pp) 1014int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
269{ 1015{
270 char *buf; 1016 struct perf_probe_arg_field *field = pa->field;
271 char offs[64] = "", line[64] = "";
272 int ret; 1017 int ret;
1018 char *tmp = buf;
273 1019
274 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 1020 if (pa->name && pa->var)
275 if (!buf) 1021 ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
276 die("Failed to allocate memory by zalloc."); 1022 else
1023 ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
1024 if (ret <= 0)
1025 goto error;
1026 tmp += ret;
1027 len -= ret;
1028
1029 while (field) {
1030 if (field->name[0] == '[')
1031 ret = e_snprintf(tmp, len, "%s", field->name);
1032 else
1033 ret = e_snprintf(tmp, len, "%s%s",
1034 field->ref ? "->" : ".", field->name);
1035 if (ret <= 0)
1036 goto error;
1037 tmp += ret;
1038 len -= ret;
1039 field = field->next;
1040 }
1041
1042 if (pa->type) {
1043 ret = e_snprintf(tmp, len, ":%s", pa->type);
1044 if (ret <= 0)
1045 goto error;
1046 tmp += ret;
1047 len -= ret;
1048 }
1049
1050 return tmp - buf;
1051error:
1052 pr_debug("Failed to synthesize perf probe argument: %s\n",
1053 strerror(-ret));
1054 return ret;
1055}
1056
1057/* Compose only probe point (not argument) */
1058static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
1059{
1060 char *buf, *tmp;
1061 char offs[32] = "", line[32] = "", file[32] = "";
1062 int ret, len;
1063
1064 buf = zalloc(MAX_CMDLEN);
1065 if (buf == NULL) {
1066 ret = -ENOMEM;
1067 goto error;
1068 }
277 if (pp->offset) { 1069 if (pp->offset) {
278 ret = e_snprintf(offs, 64, "+%d", pp->offset); 1070 ret = e_snprintf(offs, 32, "+%lu", pp->offset);
279 if (ret <= 0) 1071 if (ret <= 0)
280 goto error; 1072 goto error;
281 } 1073 }
282 if (pp->line) { 1074 if (pp->line) {
283 ret = e_snprintf(line, 64, ":%d", pp->line); 1075 ret = e_snprintf(line, 32, ":%d", pp->line);
1076 if (ret <= 0)
1077 goto error;
1078 }
1079 if (pp->file) {
1080 tmp = pp->file;
1081 len = strlen(tmp);
1082 if (len > 30) {
1083 tmp = strchr(pp->file + len - 30, '/');
1084 tmp = tmp ? tmp + 1 : pp->file + len - 30;
1085 }
1086 ret = e_snprintf(file, 32, "@%s", tmp);
284 if (ret <= 0) 1087 if (ret <= 0)
285 goto error; 1088 goto error;
286 } 1089 }
287 1090
288 if (pp->function) 1091 if (pp->function)
289 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 1092 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
290 offs, pp->retprobe ? "%return" : "", line); 1093 offs, pp->retprobe ? "%return" : "", line,
1094 file);
291 else 1095 else
292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 1096 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
293 if (ret <= 0) { 1097 if (ret <= 0)
1098 goto error;
1099
1100 return buf;
294error: 1101error:
295 free(pp->probes[0]); 1102 pr_debug("Failed to synthesize perf probe point: %s\n",
296 pp->probes[0] = NULL; 1103 strerror(-ret));
297 } 1104 if (buf)
298 return ret; 1105 free(buf);
1106 return NULL;
299} 1107}
300 1108
301int synthesize_perf_probe_event(struct probe_point *pp) 1109#if 0
1110char *synthesize_perf_probe_command(struct perf_probe_event *pev)
302{ 1111{
303 char *buf; 1112 char *buf;
304 int i, len, ret; 1113 int i, len, ret;
305 1114
306 len = synthesize_perf_probe_point(pp); 1115 buf = synthesize_perf_probe_point(&pev->point);
307 if (len < 0) 1116 if (!buf)
308 return 0; 1117 return NULL;
309 1118
310 buf = pp->probes[0]; 1119 len = strlen(buf);
311 for (i = 0; i < pp->nr_args; i++) { 1120 for (i = 0; i < pev->nargs; i++) {
312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 1121 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
313 pp->args[i]); 1122 pev->args[i].name);
314 if (ret <= 0) 1123 if (ret <= 0) {
315 goto error; 1124 free(buf);
1125 return NULL;
1126 }
316 len += ret; 1127 len += ret;
317 } 1128 }
318 pp->found = 1;
319 1129
320 return pp->found; 1130 return buf;
321error: 1131}
322 free(pp->probes[0]); 1132#endif
323 pp->probes[0] = NULL;
324 1133
325 return ret; 1134static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
1135 char **buf, size_t *buflen,
1136 int depth)
1137{
1138 int ret;
1139 if (ref->next) {
1140 depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
1141 buflen, depth + 1);
1142 if (depth < 0)
1143 goto out;
1144 }
1145
1146 ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
1147 if (ret < 0)
1148 depth = ret;
1149 else {
1150 *buf += ret;
1151 *buflen -= ret;
1152 }
1153out:
1154 return depth;
1155
1156}
1157
1158static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
1159 char *buf, size_t buflen)
1160{
1161 struct probe_trace_arg_ref *ref = arg->ref;
1162 int ret, depth = 0;
1163 char *tmp = buf;
1164
1165 /* Argument name or separator */
1166 if (arg->name)
1167 ret = e_snprintf(buf, buflen, " %s=", arg->name);
1168 else
1169 ret = e_snprintf(buf, buflen, " ");
1170 if (ret < 0)
1171 return ret;
1172 buf += ret;
1173 buflen -= ret;
1174
1175 /* Special case: @XXX */
1176 if (arg->value[0] == '@' && arg->ref)
1177 ref = ref->next;
1178
1179 /* Dereferencing arguments */
1180 if (ref) {
1181 depth = __synthesize_probe_trace_arg_ref(ref, &buf,
1182 &buflen, 1);
1183 if (depth < 0)
1184 return depth;
1185 }
1186
1187 /* Print argument value */
1188 if (arg->value[0] == '@' && arg->ref)
1189 ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
1190 arg->ref->offset);
1191 else
1192 ret = e_snprintf(buf, buflen, "%s", arg->value);
1193 if (ret < 0)
1194 return ret;
1195 buf += ret;
1196 buflen -= ret;
1197
1198 /* Closing */
1199 while (depth--) {
1200 ret = e_snprintf(buf, buflen, ")");
1201 if (ret < 0)
1202 return ret;
1203 buf += ret;
1204 buflen -= ret;
1205 }
1206 /* Print argument type */
1207 if (arg->type) {
1208 ret = e_snprintf(buf, buflen, ":%s", arg->type);
1209 if (ret <= 0)
1210 return ret;
1211 buf += ret;
1212 }
1213
1214 return buf - tmp;
326} 1215}
327 1216
328int synthesize_trace_kprobe_event(struct probe_point *pp) 1217char *synthesize_probe_trace_command(struct probe_trace_event *tev)
329{ 1218{
1219 struct probe_trace_point *tp = &tev->point;
330 char *buf; 1220 char *buf;
331 int i, len, ret; 1221 int i, len, ret;
332 1222
333 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 1223 buf = zalloc(MAX_CMDLEN);
334 if (!buf) 1224 if (buf == NULL)
335 die("Failed to allocate memory by zalloc."); 1225 return NULL;
336 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 1226
337 if (ret <= 0) 1227 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
1228 tp->retprobe ? 'r' : 'p',
1229 tev->group, tev->event,
1230 tp->symbol, tp->offset);
1231 if (len <= 0)
338 goto error; 1232 goto error;
339 len = ret;
340 1233
341 for (i = 0; i < pp->nr_args; i++) { 1234 for (i = 0; i < tev->nargs; i++) {
342 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 1235 ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
343 pp->args[i]); 1236 MAX_CMDLEN - len);
344 if (ret <= 0) 1237 if (ret <= 0)
345 goto error; 1238 goto error;
346 len += ret; 1239 len += ret;
347 } 1240 }
348 pp->found = 1;
349 1241
350 return pp->found; 1242 return buf;
351error: 1243error:
352 free(pp->probes[0]); 1244 free(buf);
353 pp->probes[0] = NULL; 1245 return NULL;
1246}
1247
1248static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1249 struct perf_probe_event *pev)
1250{
1251 char buf[64] = "";
1252 int i, ret;
1253
1254 /* Convert event/group name */
1255 pev->event = strdup(tev->event);
1256 pev->group = strdup(tev->group);
1257 if (pev->event == NULL || pev->group == NULL)
1258 return -ENOMEM;
1259
1260 /* Convert trace_point to probe_point */
1261 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1262 if (ret < 0)
1263 return ret;
1264
1265 /* Convert trace_arg to probe_arg */
1266 pev->nargs = tev->nargs;
1267 pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1268 if (pev->args == NULL)
1269 return -ENOMEM;
1270 for (i = 0; i < tev->nargs && ret >= 0; i++) {
1271 if (tev->args[i].name)
1272 pev->args[i].name = strdup(tev->args[i].name);
1273 else {
1274 ret = synthesize_probe_trace_arg(&tev->args[i],
1275 buf, 64);
1276 pev->args[i].name = strdup(buf);
1277 }
1278 if (pev->args[i].name == NULL && ret >= 0)
1279 ret = -ENOMEM;
1280 }
1281
1282 if (ret < 0)
1283 clear_perf_probe_event(pev);
354 1284
355 return ret; 1285 return ret;
356} 1286}
357 1287
358static int open_kprobe_events(int flags, int mode) 1288void clear_perf_probe_event(struct perf_probe_event *pev)
1289{
1290 struct perf_probe_point *pp = &pev->point;
1291 struct perf_probe_arg_field *field, *next;
1292 int i;
1293
1294 if (pev->event)
1295 free(pev->event);
1296 if (pev->group)
1297 free(pev->group);
1298 if (pp->file)
1299 free(pp->file);
1300 if (pp->function)
1301 free(pp->function);
1302 if (pp->lazy_line)
1303 free(pp->lazy_line);
1304 for (i = 0; i < pev->nargs; i++) {
1305 if (pev->args[i].name)
1306 free(pev->args[i].name);
1307 if (pev->args[i].var)
1308 free(pev->args[i].var);
1309 if (pev->args[i].type)
1310 free(pev->args[i].type);
1311 field = pev->args[i].field;
1312 while (field) {
1313 next = field->next;
1314 if (field->name)
1315 free(field->name);
1316 free(field);
1317 field = next;
1318 }
1319 }
1320 if (pev->args)
1321 free(pev->args);
1322 memset(pev, 0, sizeof(*pev));
1323}
1324
1325static void clear_probe_trace_event(struct probe_trace_event *tev)
1326{
1327 struct probe_trace_arg_ref *ref, *next;
1328 int i;
1329
1330 if (tev->event)
1331 free(tev->event);
1332 if (tev->group)
1333 free(tev->group);
1334 if (tev->point.symbol)
1335 free(tev->point.symbol);
1336 for (i = 0; i < tev->nargs; i++) {
1337 if (tev->args[i].name)
1338 free(tev->args[i].name);
1339 if (tev->args[i].value)
1340 free(tev->args[i].value);
1341 if (tev->args[i].type)
1342 free(tev->args[i].type);
1343 ref = tev->args[i].ref;
1344 while (ref) {
1345 next = ref->next;
1346 free(ref);
1347 ref = next;
1348 }
1349 }
1350 if (tev->args)
1351 free(tev->args);
1352 memset(tev, 0, sizeof(*tev));
1353}
1354
1355static int open_kprobe_events(bool readwrite)
359{ 1356{
360 char buf[PATH_MAX]; 1357 char buf[PATH_MAX];
1358 const char *__debugfs;
361 int ret; 1359 int ret;
362 1360
363 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path); 1361 __debugfs = debugfs_find_mountpoint();
364 if (ret < 0) 1362 if (__debugfs == NULL) {
365 die("Failed to make kprobe_events path."); 1363 pr_warning("Debugfs is not mounted.\n");
1364 return -ENOENT;
1365 }
1366
1367 ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
1368 if (ret >= 0) {
1369 pr_debug("Opening %s write=%d\n", buf, readwrite);
1370 if (readwrite && !probe_event_dry_run)
1371 ret = open(buf, O_RDWR, O_APPEND);
1372 else
1373 ret = open(buf, O_RDONLY, 0);
1374 }
366 1375
367 ret = open(buf, flags, mode);
368 if (ret < 0) { 1376 if (ret < 0) {
369 if (errno == ENOENT) 1377 if (errno == ENOENT)
370 die("kprobe_events file does not exist -" 1378 pr_warning("kprobe_events file does not exist - please"
371 " please rebuild with CONFIG_KPROBE_TRACER."); 1379 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
372 else 1380 else
373 die("Could not open kprobe_events file: %s", 1381 pr_warning("Failed to open kprobe_events file: %s\n",
374 strerror(errno)); 1382 strerror(errno));
375 } 1383 }
376 return ret; 1384 return ret;
377} 1385}
378 1386
379/* Get raw string list of current kprobe_events */ 1387/* Get raw string list of current kprobe_events */
380static struct strlist *get_trace_kprobe_event_rawlist(int fd) 1388static struct strlist *get_probe_trace_command_rawlist(int fd)
381{ 1389{
382 int ret, idx; 1390 int ret, idx;
383 FILE *fp; 1391 FILE *fp;
@@ -397,266 +1405,492 @@ static struct strlist *get_trace_kprobe_event_rawlist(int fd)
397 if (p[idx] == '\n') 1405 if (p[idx] == '\n')
398 p[idx] = '\0'; 1406 p[idx] = '\0';
399 ret = strlist__add(sl, buf); 1407 ret = strlist__add(sl, buf);
400 if (ret < 0) 1408 if (ret < 0) {
401 die("strlist__add failed: %s", strerror(-ret)); 1409 pr_debug("strlist__add failed: %s\n", strerror(-ret));
1410 strlist__delete(sl);
1411 return NULL;
1412 }
402 } 1413 }
403 fclose(fp); 1414 fclose(fp);
404 1415
405 return sl; 1416 return sl;
406} 1417}
407 1418
408/* Free and zero clear probe_point */
409static void clear_probe_point(struct probe_point *pp)
410{
411 int i;
412
413 if (pp->event)
414 free(pp->event);
415 if (pp->group)
416 free(pp->group);
417 if (pp->function)
418 free(pp->function);
419 if (pp->file)
420 free(pp->file);
421 for (i = 0; i < pp->nr_args; i++)
422 free(pp->args[i]);
423 if (pp->args)
424 free(pp->args);
425 for (i = 0; i < pp->found; i++)
426 free(pp->probes[i]);
427 memset(pp, 0, sizeof(*pp));
428}
429
430/* Show an event */ 1419/* Show an event */
431static void show_perf_probe_event(const char *event, const char *place, 1420static int show_perf_probe_event(struct perf_probe_event *pev)
432 struct probe_point *pp)
433{ 1421{
434 int i, ret; 1422 int i, ret;
435 char buf[128]; 1423 char buf[128];
1424 char *place;
436 1425
437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); 1426 /* Synthesize only event probe point */
1427 place = synthesize_perf_probe_point(&pev->point);
1428 if (!place)
1429 return -EINVAL;
1430
1431 ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
438 if (ret < 0) 1432 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret)); 1433 return ret;
440 printf(" %-40s (on %s", buf, place); 1434
1435 printf(" %-20s (on %s", buf, place);
441 1436
442 if (pp->nr_args > 0) { 1437 if (pev->nargs > 0) {
443 printf(" with"); 1438 printf(" with");
444 for (i = 0; i < pp->nr_args; i++) 1439 for (i = 0; i < pev->nargs; i++) {
445 printf(" %s", pp->args[i]); 1440 ret = synthesize_perf_probe_arg(&pev->args[i],
1441 buf, 128);
1442 if (ret < 0)
1443 break;
1444 printf(" %s", buf);
1445 }
446 } 1446 }
447 printf(")\n"); 1447 printf(")\n");
1448 free(place);
1449 return ret;
448} 1450}
449 1451
450/* List up current perf-probe events */ 1452/* List up current perf-probe events */
451void show_perf_probe_events(void) 1453int show_perf_probe_events(void)
452{ 1454{
453 int fd; 1455 int fd, ret;
454 struct probe_point pp; 1456 struct probe_trace_event tev;
1457 struct perf_probe_event pev;
455 struct strlist *rawlist; 1458 struct strlist *rawlist;
456 struct str_node *ent; 1459 struct str_node *ent;
457 1460
458 fd = open_kprobe_events(O_RDONLY, 0); 1461 setup_pager();
459 rawlist = get_trace_kprobe_event_rawlist(fd); 1462 ret = init_vmlinux();
1463 if (ret < 0)
1464 return ret;
1465
1466 memset(&tev, 0, sizeof(tev));
1467 memset(&pev, 0, sizeof(pev));
1468
1469 fd = open_kprobe_events(false);
1470 if (fd < 0)
1471 return fd;
1472
1473 rawlist = get_probe_trace_command_rawlist(fd);
460 close(fd); 1474 close(fd);
1475 if (!rawlist)
1476 return -ENOENT;
461 1477
462 strlist__for_each(ent, rawlist) { 1478 strlist__for_each(ent, rawlist) {
463 parse_trace_kprobe_event(ent->s, &pp); 1479 ret = parse_probe_trace_command(ent->s, &tev);
464 /* Synthesize only event probe point */ 1480 if (ret >= 0) {
465 synthesize_perf_probe_point(&pp); 1481 ret = convert_to_perf_probe_event(&tev, &pev);
466 /* Show an event */ 1482 if (ret >= 0)
467 show_perf_probe_event(pp.event, pp.probes[0], &pp); 1483 ret = show_perf_probe_event(&pev);
468 clear_probe_point(&pp); 1484 }
1485 clear_perf_probe_event(&pev);
1486 clear_probe_trace_event(&tev);
1487 if (ret < 0)
1488 break;
469 } 1489 }
470
471 strlist__delete(rawlist); 1490 strlist__delete(rawlist);
1491
1492 return ret;
472} 1493}
473 1494
474/* Get current perf-probe event names */ 1495/* Get current perf-probe event names */
475static struct strlist *get_perf_event_names(int fd, bool include_group) 1496static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
476{ 1497{
477 char buf[128]; 1498 char buf[128];
478 struct strlist *sl, *rawlist; 1499 struct strlist *sl, *rawlist;
479 struct str_node *ent; 1500 struct str_node *ent;
480 struct probe_point pp; 1501 struct probe_trace_event tev;
481 1502 int ret = 0;
482 memset(&pp, 0, sizeof(pp));
483 rawlist = get_trace_kprobe_event_rawlist(fd);
484 1503
1504 memset(&tev, 0, sizeof(tev));
1505 rawlist = get_probe_trace_command_rawlist(fd);
485 sl = strlist__new(true, NULL); 1506 sl = strlist__new(true, NULL);
486 strlist__for_each(ent, rawlist) { 1507 strlist__for_each(ent, rawlist) {
487 parse_trace_kprobe_event(ent->s, &pp); 1508 ret = parse_probe_trace_command(ent->s, &tev);
1509 if (ret < 0)
1510 break;
488 if (include_group) { 1511 if (include_group) {
489 if (e_snprintf(buf, 128, "%s:%s", pp.group, 1512 ret = e_snprintf(buf, 128, "%s:%s", tev.group,
490 pp.event) < 0) 1513 tev.event);
491 die("Failed to copy group:event name."); 1514 if (ret >= 0)
492 strlist__add(sl, buf); 1515 ret = strlist__add(sl, buf);
493 } else 1516 } else
494 strlist__add(sl, pp.event); 1517 ret = strlist__add(sl, tev.event);
495 clear_probe_point(&pp); 1518 clear_probe_trace_event(&tev);
1519 if (ret < 0)
1520 break;
496 } 1521 }
497
498 strlist__delete(rawlist); 1522 strlist__delete(rawlist);
499 1523
1524 if (ret < 0) {
1525 strlist__delete(sl);
1526 return NULL;
1527 }
500 return sl; 1528 return sl;
501} 1529}
502 1530
503static void write_trace_kprobe_event(int fd, const char *buf) 1531static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
504{ 1532{
505 int ret; 1533 int ret = 0;
1534 char *buf = synthesize_probe_trace_command(tev);
1535
1536 if (!buf) {
1537 pr_debug("Failed to synthesize probe trace event.\n");
1538 return -EINVAL;
1539 }
506 1540
507 pr_debug("Writing event: %s\n", buf); 1541 pr_debug("Writing event: %s\n", buf);
508 ret = write(fd, buf, strlen(buf)); 1542 if (!probe_event_dry_run) {
509 if (ret <= 0) 1543 ret = write(fd, buf, strlen(buf));
510 die("Failed to write event: %s", strerror(errno)); 1544 if (ret <= 0)
1545 pr_warning("Failed to write event: %s\n",
1546 strerror(errno));
1547 }
1548 free(buf);
1549 return ret;
511} 1550}
512 1551
513static void get_new_event_name(char *buf, size_t len, const char *base, 1552static int get_new_event_name(char *buf, size_t len, const char *base,
514 struct strlist *namelist, bool allow_suffix) 1553 struct strlist *namelist, bool allow_suffix)
515{ 1554{
516 int i, ret; 1555 int i, ret;
517 1556
518 /* Try no suffix */ 1557 /* Try no suffix */
519 ret = e_snprintf(buf, len, "%s", base); 1558 ret = e_snprintf(buf, len, "%s", base);
520 if (ret < 0) 1559 if (ret < 0) {
521 die("snprintf() failed: %s", strerror(-ret)); 1560 pr_debug("snprintf() failed: %s\n", strerror(-ret));
1561 return ret;
1562 }
522 if (!strlist__has_entry(namelist, buf)) 1563 if (!strlist__has_entry(namelist, buf))
523 return; 1564 return 0;
524 1565
525 if (!allow_suffix) { 1566 if (!allow_suffix) {
526 pr_warning("Error: event \"%s\" already exists. " 1567 pr_warning("Error: event \"%s\" already exists. "
527 "(Use -f to force duplicates.)\n", base); 1568 "(Use -f to force duplicates.)\n", base);
528 die("Can't add new event."); 1569 return -EEXIST;
529 } 1570 }
530 1571
531 /* Try to add suffix */ 1572 /* Try to add suffix */
532 for (i = 1; i < MAX_EVENT_INDEX; i++) { 1573 for (i = 1; i < MAX_EVENT_INDEX; i++) {
533 ret = e_snprintf(buf, len, "%s_%d", base, i); 1574 ret = e_snprintf(buf, len, "%s_%d", base, i);
534 if (ret < 0) 1575 if (ret < 0) {
535 die("snprintf() failed: %s", strerror(-ret)); 1576 pr_debug("snprintf() failed: %s\n", strerror(-ret));
1577 return ret;
1578 }
536 if (!strlist__has_entry(namelist, buf)) 1579 if (!strlist__has_entry(namelist, buf))
537 break; 1580 break;
538 } 1581 }
539 if (i == MAX_EVENT_INDEX) 1582 if (i == MAX_EVENT_INDEX) {
540 die("Too many events are on the same function."); 1583 pr_warning("Too many events are on the same function.\n");
1584 ret = -ERANGE;
1585 }
1586
1587 return ret;
541} 1588}
542 1589
543void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 1590static int __add_probe_trace_events(struct perf_probe_event *pev,
544 bool force_add) 1591 struct probe_trace_event *tevs,
1592 int ntevs, bool allow_suffix)
545{ 1593{
546 int i, j, fd; 1594 int i, fd, ret;
547 struct probe_point *pp; 1595 struct probe_trace_event *tev = NULL;
548 char buf[MAX_CMDLEN]; 1596 char buf[64];
549 char event[64]; 1597 const char *event, *group;
550 struct strlist *namelist; 1598 struct strlist *namelist;
551 bool allow_suffix;
552 1599
553 fd = open_kprobe_events(O_RDWR, O_APPEND); 1600 fd = open_kprobe_events(true);
1601 if (fd < 0)
1602 return fd;
554 /* Get current event names */ 1603 /* Get current event names */
555 namelist = get_perf_event_names(fd, false); 1604 namelist = get_probe_trace_event_names(fd, false);
556 1605 if (!namelist) {
557 for (j = 0; j < nr_probes; j++) { 1606 pr_debug("Failed to get current event list.\n");
558 pp = probes + j; 1607 return -EIO;
559 if (!pp->event) 1608 }
560 pp->event = strdup(pp->function); 1609
561 if (!pp->group) 1610 ret = 0;
562 pp->group = strdup(PERFPROBE_GROUP); 1611 printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
563 DIE_IF(!pp->event || !pp->group); 1612 for (i = 0; i < ntevs; i++) {
564 /* If force_add is true, suffix search is allowed */ 1613 tev = &tevs[i];
565 allow_suffix = force_add; 1614 if (pev->event)
566 for (i = 0; i < pp->found; i++) { 1615 event = pev->event;
567 /* Get an unused new event name */ 1616 else
568 get_new_event_name(event, 64, pp->event, namelist, 1617 if (pev->point.function)
569 allow_suffix); 1618 event = pev->point.function;
570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 1619 else
571 pp->retprobe ? 'r' : 'p', 1620 event = tev->point.symbol;
572 pp->group, event, 1621 if (pev->group)
573 pp->probes[i]); 1622 group = pev->group;
574 write_trace_kprobe_event(fd, buf); 1623 else
575 printf("Added new event:\n"); 1624 group = PERFPROBE_GROUP;
576 /* Get the first parameter (probe-point) */ 1625
577 sscanf(pp->probes[i], "%s", buf); 1626 /* Get an unused new event name */
578 show_perf_probe_event(event, buf, pp); 1627 ret = get_new_event_name(buf, 64, event,
579 /* Add added event name to namelist */ 1628 namelist, allow_suffix);
580 strlist__add(namelist, event); 1629 if (ret < 0)
581 /* 1630 break;
582 * Probes after the first probe which comes from same 1631 event = buf;
583 * user input are always allowed to add suffix, because 1632
584 * there might be several addresses corresponding to 1633 tev->event = strdup(event);
585 * one code line. 1634 tev->group = strdup(group);
586 */ 1635 if (tev->event == NULL || tev->group == NULL) {
587 allow_suffix = true; 1636 ret = -ENOMEM;
1637 break;
588 } 1638 }
1639 ret = write_probe_trace_event(fd, tev);
1640 if (ret < 0)
1641 break;
1642 /* Add added event name to namelist */
1643 strlist__add(namelist, event);
1644
1645 /* Trick here - save current event/group */
1646 event = pev->event;
1647 group = pev->group;
1648 pev->event = tev->event;
1649 pev->group = tev->group;
1650 show_perf_probe_event(pev);
1651 /* Trick here - restore current event/group */
1652 pev->event = (char *)event;
1653 pev->group = (char *)group;
1654
1655 /*
1656 * Probes after the first probe which comes from same
1657 * user input are always allowed to add suffix, because
1658 * there might be several addresses corresponding to
1659 * one code line.
1660 */
1661 allow_suffix = true;
1662 }
1663
1664 if (ret >= 0) {
1665 /* Show how to use the event. */
1666 printf("\nYou can now use it on all perf tools, such as:\n\n");
1667 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1668 tev->event);
589 } 1669 }
590 /* Show how to use the event. */
591 printf("\nYou can now use it on all perf tools, such as:\n\n");
592 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);
593 1670
594 strlist__delete(namelist); 1671 strlist__delete(namelist);
595 close(fd); 1672 close(fd);
1673 return ret;
596} 1674}
597 1675
598static void __del_trace_kprobe_event(int fd, struct str_node *ent) 1676static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1677 struct probe_trace_event **tevs,
1678 int max_tevs, const char *module)
1679{
1680 struct symbol *sym;
1681 int ret = 0, i;
1682 struct probe_trace_event *tev;
1683
1684 /* Convert perf_probe_event with debuginfo */
1685 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1686 if (ret != 0)
1687 return ret;
1688
1689 /* Allocate trace event buffer */
1690 tev = *tevs = zalloc(sizeof(struct probe_trace_event));
1691 if (tev == NULL)
1692 return -ENOMEM;
1693
1694 /* Copy parameters */
1695 tev->point.symbol = strdup(pev->point.function);
1696 if (tev->point.symbol == NULL) {
1697 ret = -ENOMEM;
1698 goto error;
1699 }
1700 tev->point.offset = pev->point.offset;
1701 tev->point.retprobe = pev->point.retprobe;
1702 tev->nargs = pev->nargs;
1703 if (tev->nargs) {
1704 tev->args = zalloc(sizeof(struct probe_trace_arg)
1705 * tev->nargs);
1706 if (tev->args == NULL) {
1707 ret = -ENOMEM;
1708 goto error;
1709 }
1710 for (i = 0; i < tev->nargs; i++) {
1711 if (pev->args[i].name) {
1712 tev->args[i].name = strdup(pev->args[i].name);
1713 if (tev->args[i].name == NULL) {
1714 ret = -ENOMEM;
1715 goto error;
1716 }
1717 }
1718 tev->args[i].value = strdup(pev->args[i].var);
1719 if (tev->args[i].value == NULL) {
1720 ret = -ENOMEM;
1721 goto error;
1722 }
1723 if (pev->args[i].type) {
1724 tev->args[i].type = strdup(pev->args[i].type);
1725 if (tev->args[i].type == NULL) {
1726 ret = -ENOMEM;
1727 goto error;
1728 }
1729 }
1730 }
1731 }
1732
1733 /* Currently just checking function name from symbol map */
1734 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1735 if (!sym) {
1736 pr_warning("Kernel symbol \'%s\' not found.\n",
1737 tev->point.symbol);
1738 ret = -ENOENT;
1739 goto error;
1740 }
1741
1742 return 1;
1743error:
1744 clear_probe_trace_event(tev);
1745 free(tev);
1746 *tevs = NULL;
1747 return ret;
1748}
1749
1750struct __event_package {
1751 struct perf_probe_event *pev;
1752 struct probe_trace_event *tevs;
1753 int ntevs;
1754};
1755
1756int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1757 int max_tevs, const char *module, bool force_add)
1758{
1759 int i, j, ret;
1760 struct __event_package *pkgs;
1761
1762 pkgs = zalloc(sizeof(struct __event_package) * npevs);
1763 if (pkgs == NULL)
1764 return -ENOMEM;
1765
1766 /* Init vmlinux path */
1767 ret = init_vmlinux();
1768 if (ret < 0) {
1769 free(pkgs);
1770 return ret;
1771 }
1772
1773 /* Loop 1: convert all events */
1774 for (i = 0; i < npevs; i++) {
1775 pkgs[i].pev = &pevs[i];
1776 /* Convert with or without debuginfo */
1777 ret = convert_to_probe_trace_events(pkgs[i].pev,
1778 &pkgs[i].tevs,
1779 max_tevs,
1780 module);
1781 if (ret < 0)
1782 goto end;
1783 pkgs[i].ntevs = ret;
1784 }
1785
1786 /* Loop 2: add all events */
1787 for (i = 0; i < npevs && ret >= 0; i++)
1788 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1789 pkgs[i].ntevs, force_add);
1790end:
1791 /* Loop 3: cleanup and free trace events */
1792 for (i = 0; i < npevs; i++) {
1793 for (j = 0; j < pkgs[i].ntevs; j++)
1794 clear_probe_trace_event(&pkgs[i].tevs[j]);
1795 free(pkgs[i].tevs);
1796 }
1797 free(pkgs);
1798
1799 return ret;
1800}
1801
1802static int __del_trace_probe_event(int fd, struct str_node *ent)
599{ 1803{
600 char *p; 1804 char *p;
601 char buf[128]; 1805 char buf[128];
1806 int ret;
1807
1808 /* Convert from perf-probe event to trace-probe event */
1809 ret = e_snprintf(buf, 128, "-:%s", ent->s);
1810 if (ret < 0)
1811 goto error;
602 1812
603 /* Convert from perf-probe event to trace-kprobe event */
604 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
605 die("Failed to copy event.");
606 p = strchr(buf + 2, ':'); 1813 p = strchr(buf + 2, ':');
607 if (!p) 1814 if (!p) {
608 die("Internal error: %s should have ':' but not.", ent->s); 1815 pr_debug("Internal error: %s should have ':' but not.\n",
1816 ent->s);
1817 ret = -ENOTSUP;
1818 goto error;
1819 }
609 *p = '/'; 1820 *p = '/';
610 1821
611 write_trace_kprobe_event(fd, buf); 1822 pr_debug("Writing event: %s\n", buf);
1823 ret = write(fd, buf, strlen(buf));
1824 if (ret < 0)
1825 goto error;
1826
612 printf("Remove event: %s\n", ent->s); 1827 printf("Remove event: %s\n", ent->s);
1828 return 0;
1829error:
1830 pr_warning("Failed to delete event: %s\n", strerror(-ret));
1831 return ret;
613} 1832}
614 1833
615static void del_trace_kprobe_event(int fd, const char *group, 1834static int del_trace_probe_event(int fd, const char *group,
616 const char *event, struct strlist *namelist) 1835 const char *event, struct strlist *namelist)
617{ 1836{
618 char buf[128]; 1837 char buf[128];
619 struct str_node *ent, *n; 1838 struct str_node *ent, *n;
620 int found = 0; 1839 int found = 0, ret = 0;
621 1840
622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 1841 ret = e_snprintf(buf, 128, "%s:%s", group, event);
623 die("Failed to copy event."); 1842 if (ret < 0) {
1843 pr_err("Failed to copy event.\n");
1844 return ret;
1845 }
624 1846
625 if (strpbrk(buf, "*?")) { /* Glob-exp */ 1847 if (strpbrk(buf, "*?")) { /* Glob-exp */
626 strlist__for_each_safe(ent, n, namelist) 1848 strlist__for_each_safe(ent, n, namelist)
627 if (strglobmatch(ent->s, buf)) { 1849 if (strglobmatch(ent->s, buf)) {
628 found++; 1850 found++;
629 __del_trace_kprobe_event(fd, ent); 1851 ret = __del_trace_probe_event(fd, ent);
1852 if (ret < 0)
1853 break;
630 strlist__remove(namelist, ent); 1854 strlist__remove(namelist, ent);
631 } 1855 }
632 } else { 1856 } else {
633 ent = strlist__find(namelist, buf); 1857 ent = strlist__find(namelist, buf);
634 if (ent) { 1858 if (ent) {
635 found++; 1859 found++;
636 __del_trace_kprobe_event(fd, ent); 1860 ret = __del_trace_probe_event(fd, ent);
637 strlist__remove(namelist, ent); 1861 if (ret >= 0)
1862 strlist__remove(namelist, ent);
638 } 1863 }
639 } 1864 }
640 if (found == 0) 1865 if (found == 0 && ret >= 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); 1866 pr_info("Info: Event \"%s\" does not exist.\n", buf);
1867
1868 return ret;
642} 1869}
643 1870
644void del_trace_kprobe_events(struct strlist *dellist) 1871int del_perf_probe_events(struct strlist *dellist)
645{ 1872{
646 int fd; 1873 int fd, ret = 0;
647 const char *group, *event; 1874 const char *group, *event;
648 char *p, *str; 1875 char *p, *str;
649 struct str_node *ent; 1876 struct str_node *ent;
650 struct strlist *namelist; 1877 struct strlist *namelist;
651 1878
652 fd = open_kprobe_events(O_RDWR, O_APPEND); 1879 fd = open_kprobe_events(true);
1880 if (fd < 0)
1881 return fd;
1882
653 /* Get current event names */ 1883 /* Get current event names */
654 namelist = get_perf_event_names(fd, true); 1884 namelist = get_probe_trace_event_names(fd, true);
1885 if (namelist == NULL)
1886 return -EINVAL;
655 1887
656 strlist__for_each(ent, dellist) { 1888 strlist__for_each(ent, dellist) {
657 str = strdup(ent->s); 1889 str = strdup(ent->s);
658 if (!str) 1890 if (str == NULL) {
659 die("Failed to copy event."); 1891 ret = -ENOMEM;
1892 break;
1893 }
660 pr_debug("Parsing: %s\n", str); 1894 pr_debug("Parsing: %s\n", str);
661 p = strchr(str, ':'); 1895 p = strchr(str, ':');
662 if (p) { 1896 if (p) {
@@ -668,10 +1902,14 @@ void del_trace_kprobe_events(struct strlist *dellist)
668 event = str; 1902 event = str;
669 } 1903 }
670 pr_debug("Group: %s, Event: %s\n", group, event); 1904 pr_debug("Group: %s, Event: %s\n", group, event);
671 del_trace_kprobe_event(fd, group, event, namelist); 1905 ret = del_trace_probe_event(fd, group, event, namelist);
672 free(str); 1906 free(str);
1907 if (ret < 0)
1908 break;
673 } 1909 }
674 strlist__delete(namelist); 1910 strlist__delete(namelist);
675 close(fd); 1911 close(fd);
1912
1913 return ret;
676} 1914}
677 1915
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 7f1d499118c0..5accbedfea37 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,19 +2,132 @@
2#define _PROBE_EVENT_H 2#define _PROBE_EVENT_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include "probe-finder.h"
6#include "strlist.h" 5#include "strlist.h"
7 6
8extern void parse_perf_probe_event(const char *str, struct probe_point *pp, 7extern bool probe_event_dry_run;
9 bool *need_dwarf); 8
10extern int synthesize_perf_probe_point(struct probe_point *pp); 9/* kprobe-tracer tracing point */
11extern int synthesize_perf_probe_event(struct probe_point *pp); 10struct probe_trace_point {
12extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp); 11 char *symbol; /* Base symbol */
13extern int synthesize_trace_kprobe_event(struct probe_point *pp); 12 unsigned long offset; /* Offset from symbol */
14extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 13 bool retprobe; /* Return probe flag */
15 bool force_add); 14};
16extern void del_trace_kprobe_events(struct strlist *dellist); 15
17extern void show_perf_probe_events(void); 16/* probe-tracer tracing argument referencing offset */
17struct probe_trace_arg_ref {
18 struct probe_trace_arg_ref *next; /* Next reference */
19 long offset; /* Offset value */
20};
21
22/* kprobe-tracer tracing argument */
23struct probe_trace_arg {
24 char *name; /* Argument name */
25 char *value; /* Base value */
26 char *type; /* Type name */
27 struct probe_trace_arg_ref *ref; /* Referencing offset */
28};
29
30/* kprobe-tracer tracing event (point + arg) */
31struct probe_trace_event {
32 char *event; /* Event name */
33 char *group; /* Group name */
34 struct probe_trace_point point; /* Trace point */
35 int nargs; /* Number of args */
36 struct probe_trace_arg *args; /* Arguments */
37};
38
39/* Perf probe probing point */
40struct perf_probe_point {
41 char *file; /* File path */
42 char *function; /* Function name */
43 int line; /* Line number */
44 bool retprobe; /* Return probe flag */
45 char *lazy_line; /* Lazy matching pattern */
46 unsigned long offset; /* Offset from function entry */
47};
48
49/* Perf probe probing argument field chain */
50struct perf_probe_arg_field {
51 struct perf_probe_arg_field *next; /* Next field */
52 char *name; /* Name of the field */
53 long index; /* Array index number */
54 bool ref; /* Referencing flag */
55};
56
57/* Perf probe probing argument */
58struct perf_probe_arg {
59 char *name; /* Argument name */
60 char *var; /* Variable name */
61 char *type; /* Type name */
62 struct perf_probe_arg_field *field; /* Structure fields */
63};
64
65/* Perf probe probing event (point + arg) */
66struct perf_probe_event {
67 char *event; /* Event name */
68 char *group; /* Group name */
69 struct perf_probe_point point; /* Probe point */
70 int nargs; /* Number of arguments */
71 struct perf_probe_arg *args; /* Arguments */
72};
73
74
75/* Line number container */
76struct line_node {
77 struct list_head list;
78 int line;
79};
80
81/* Line range */
82struct line_range {
83 char *file; /* File name */
84 char *function; /* Function name */
85 int start; /* Start line number */
86 int end; /* End line number */
87 int offset; /* Start line offset */
88 char *path; /* Real path name */
89 char *comp_dir; /* Compile directory */
90 struct list_head line_list; /* Visible lines */
91};
92
93/* List of variables */
94struct variable_list {
95 struct probe_trace_point point; /* Actual probepoint */
96 struct strlist *vars; /* Available variables */
97};
98
99/* Command string to events */
100extern int parse_perf_probe_command(const char *cmd,
101 struct perf_probe_event *pev);
102
103/* Events to command string */
104extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
105extern char *synthesize_probe_trace_command(struct probe_trace_event *tev);
106extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
107 size_t len);
108
109/* Check the perf_probe_event needs debuginfo */
110extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
111
112/* Release event contents */
113extern void clear_perf_probe_event(struct perf_probe_event *pev);
114
115/* Command string to line-range */
116extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
117
118/* Internal use: Return kernel/module path */
119extern const char *kernel_get_module_path(const char *module);
120
121extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
122 int max_probe_points, const char *module,
123 bool force_add);
124extern int del_perf_probe_events(struct strlist *dellist);
125extern int show_perf_probe_events(void);
126extern int show_line_range(struct line_range *lr, const char *module);
127extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
128 int max_probe_points, const char *module,
129 bool externs);
130
18 131
19/* Maximum index number of event-name postfix */ 132/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024 133#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4b852c0d16a5..ab83b6ac5d65 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -31,72 +31,16 @@
31#include <string.h> 31#include <string.h>
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h> 33#include <ctype.h>
34#include <dwarf-regs.h>
34 35
35#include "event.h" 36#include "event.h"
36#include "debug.h" 37#include "debug.h"
37#include "util.h" 38#include "util.h"
39#include "symbol.h"
38#include "probe-finder.h" 40#include "probe-finder.h"
39 41
40 42/* Kprobe tracer basic type is up to u64 */
41/* Dwarf_Die Linkage to parent Die */ 43#define MAX_BASIC_TYPE_BITS 64
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49
50/*
51 * Generic dwarf analysis helpers
52 */
53
54#define X86_32_MAX_REGS 8
55const char *x86_32_regs_table[X86_32_MAX_REGS] = {
56 "%ax",
57 "%cx",
58 "%dx",
59 "%bx",
60 "$stack", /* Stack address instead of %sp */
61 "%bp",
62 "%si",
63 "%di",
64};
65
66#define X86_64_MAX_REGS 16
67const char *x86_64_regs_table[X86_64_MAX_REGS] = {
68 "%ax",
69 "%dx",
70 "%cx",
71 "%bx",
72 "%si",
73 "%di",
74 "%bp",
75 "%sp",
76 "%r8",
77 "%r9",
78 "%r10",
79 "%r11",
80 "%r12",
81 "%r13",
82 "%r14",
83 "%r15",
84};
85
86/* TODO: switching by dwarf address size */
87#ifdef __x86_64__
88#define ARCH_MAX_REGS X86_64_MAX_REGS
89#define arch_regs_table x86_64_regs_table
90#else
91#define ARCH_MAX_REGS X86_32_MAX_REGS
92#define arch_regs_table x86_32_regs_table
93#endif
94
95/* Return architecture dependent register string (for kprobe-tracer) */
96static const char *get_arch_regstr(unsigned int n)
97{
98 return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
99}
100 44
101/* 45/*
102 * Compare the tail of two strings. 46 * Compare the tail of two strings.
@@ -113,618 +57,1805 @@ static int strtailcmp(const char *s1, const char *s2)
113 return 0; 57 return 0;
114} 58}
115 59
116/* Find the fileno of the target file. */ 60/* Line number list operations */
117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname) 61
62/* Add a line to line number list */
63static int line_list__add_line(struct list_head *head, int line)
64{
65 struct line_node *ln;
66 struct list_head *p;
67
68 /* Reverse search, because new line will be the last one */
69 list_for_each_entry_reverse(ln, head, list) {
70 if (ln->line < line) {
71 p = &ln->list;
72 goto found;
73 } else if (ln->line == line) /* Already exist */
74 return 1;
75 }
76 /* List is empty, or the smallest entry */
77 p = head;
78found:
79 pr_debug("line list: add a line %u\n", line);
80 ln = zalloc(sizeof(struct line_node));
81 if (ln == NULL)
82 return -ENOMEM;
83 ln->line = line;
84 INIT_LIST_HEAD(&ln->list);
85 list_add(&ln->list, p);
86 return 0;
87}
88
89/* Check if the line in line number list */
90static int line_list__has_line(struct list_head *head, int line)
91{
92 struct line_node *ln;
93
94 /* Reverse search, because new line will be the last one */
95 list_for_each_entry(ln, head, list)
96 if (ln->line == line)
97 return 1;
98
99 return 0;
100}
101
102/* Init line number list */
103static void line_list__init(struct list_head *head)
104{
105 INIT_LIST_HEAD(head);
106}
107
108/* Free line number list */
109static void line_list__free(struct list_head *head)
110{
111 struct line_node *ln;
112 while (!list_empty(head)) {
113 ln = list_first_entry(head, struct line_node, list);
114 list_del(&ln->list);
115 free(ln);
116 }
117}
118
119/* Dwarf FL wrappers */
120static char *debuginfo_path; /* Currently dummy */
121
122static const Dwfl_Callbacks offline_callbacks = {
123 .find_debuginfo = dwfl_standard_find_debuginfo,
124 .debuginfo_path = &debuginfo_path,
125
126 .section_address = dwfl_offline_section_address,
127
128 /* We use this table for core files too. */
129 .find_elf = dwfl_build_id_find_elf,
130};
131
132/* Get a Dwarf from offline image */
133static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
134{
135 Dwfl_Module *mod;
136 Dwarf *dbg = NULL;
137
138 if (!dwflp)
139 return NULL;
140
141 *dwflp = dwfl_begin(&offline_callbacks);
142 if (!*dwflp)
143 return NULL;
144
145 mod = dwfl_report_offline(*dwflp, "", "", fd);
146 if (!mod)
147 goto error;
148
149 dbg = dwfl_module_getdwarf(mod, bias);
150 if (!dbg) {
151error:
152 dwfl_end(*dwflp);
153 *dwflp = NULL;
154 }
155 return dbg;
156}
157
158#if _ELFUTILS_PREREQ(0, 148)
159/* This method is buggy if elfutils is older than 0.148 */
160static int __linux_kernel_find_elf(Dwfl_Module *mod,
161 void **userdata,
162 const char *module_name,
163 Dwarf_Addr base,
164 char **file_name, Elf **elfp)
165{
166 int fd;
167 const char *path = kernel_get_module_path(module_name);
168
169 pr_debug2("Use file %s for %s\n", path, module_name);
170 if (path) {
171 fd = open(path, O_RDONLY);
172 if (fd >= 0) {
173 *file_name = strdup(path);
174 return fd;
175 }
176 }
177 /* If failed, try to call standard method */
178 return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
179 file_name, elfp);
180}
181
182static const Dwfl_Callbacks kernel_callbacks = {
183 .find_debuginfo = dwfl_standard_find_debuginfo,
184 .debuginfo_path = &debuginfo_path,
185
186 .find_elf = __linux_kernel_find_elf,
187 .section_address = dwfl_linux_kernel_module_section_address,
188};
189
190/* Get a Dwarf from live kernel image */
191static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
192 Dwarf_Addr *bias)
118{ 193{
119 Dwarf_Signed cnt, i; 194 Dwarf *dbg;
120 Dwarf_Unsigned found = 0; 195
121 char **srcs; 196 if (!dwflp)
197 return NULL;
198
199 *dwflp = dwfl_begin(&kernel_callbacks);
200 if (!*dwflp)
201 return NULL;
202
203 /* Load the kernel dwarves: Don't care the result here */
204 dwfl_linux_kernel_report_kernel(*dwflp);
205 dwfl_linux_kernel_report_modules(*dwflp);
206
207 dbg = dwfl_addrdwarf(*dwflp, addr, bias);
208 /* Here, check whether we could get a real dwarf */
209 if (!dbg) {
210 pr_debug("Failed to find kernel dwarf at %lx\n",
211 (unsigned long)addr);
212 dwfl_end(*dwflp);
213 *dwflp = NULL;
214 }
215 return dbg;
216}
217#else
218/* With older elfutils, this just support kernel module... */
219static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp,
220 Dwarf_Addr *bias)
221{
222 int fd;
223 const char *path = kernel_get_module_path("kernel");
224
225 if (!path) {
226 pr_err("Failed to find vmlinux path\n");
227 return NULL;
228 }
229
230 pr_debug2("Use file %s for debuginfo\n", path);
231 fd = open(path, O_RDONLY);
232 if (fd < 0)
233 return NULL;
234
235 return dwfl_init_offline_dwarf(fd, dwflp, bias);
236}
237#endif
238
239/* Dwarf wrappers */
240
241/* Find the realpath of the target file. */
242static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
243{
244 Dwarf_Files *files;
245 size_t nfiles, i;
246 const char *src = NULL;
122 int ret; 247 int ret;
123 248
124 if (!fname) 249 if (!fname)
125 return 0; 250 return NULL;
126 251
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 252 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
128 if (ret == DW_DLV_OK) { 253 if (ret != 0)
129 for (i = 0; i < cnt && !found; i++) { 254 return NULL;
130 if (strtailcmp(srcs[i], fname) == 0) 255
131 found = i + 1; 256 for (i = 0; i < nfiles; i++) {
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 257 src = dwarf_filesrc(files, i, NULL, NULL);
133 } 258 if (strtailcmp(src, fname) == 0)
134 for (; i < cnt; i++) 259 break;
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
137 } 260 }
138 if (found) 261 if (i == nfiles)
139 pr_debug("found fno: %d\n", (int)found); 262 return NULL;
140 return found; 263 return src;
264}
265
266/* Get DW_AT_comp_dir (should be NULL with older gcc) */
267static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
268{
269 Dwarf_Attribute attr;
270 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
271 return NULL;
272 return dwarf_formstring(&attr);
141} 273}
142 274
143/* Compare diename and tname */ 275/* Compare diename and tname */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname) 276static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
145{ 277{
146 char *name; 278 const char *name;
147 int ret; 279 name = dwarf_diename(dw_die);
148 ret = dwarf_diename(dw_die, &name, &__dw_error); 280 return name ? (strcmp(tname, name) == 0) : false;
149 DIE_IF(ret == DW_DLV_ERROR);
150 if (ret == DW_DLV_OK) {
151 ret = strcmp(tname, name);
152 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
153 } else
154 ret = -1;
155 return ret;
156} 281}
157 282
158/* Check the address is in the subprogram(function). */ 283/* Get type die */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 284static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
160 Dwarf_Signed *offs)
161{ 285{
162 Dwarf_Addr lopc, hipc; 286 Dwarf_Attribute attr;
163 int ret;
164 287
165 /* TODO: check ranges */ 288 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
166 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error); 289 dwarf_formref_die(&attr, die_mem))
167 DIE_IF(ret == DW_DLV_ERROR); 290 return die_mem;
168 if (ret == DW_DLV_NO_ENTRY) 291 else
169 return 0; 292 return NULL;
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
171 DIE_IF(ret != DW_DLV_OK);
172 if (lopc <= addr && addr < hipc) {
173 *offs = addr - lopc;
174 return 1;
175 } else
176 return 0;
177} 293}
178 294
179/* Check the die is inlined function */ 295/* Get a type die, but skip qualifiers */
180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) 296static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
181{ 297{
182 /* TODO: check strictly */ 298 int tag;
183 Dwarf_Bool inl; 299
184 int ret; 300 do {
301 vr_die = die_get_type(vr_die, die_mem);
302 if (!vr_die)
303 break;
304 tag = dwarf_tag(vr_die);
305 } while (tag == DW_TAG_const_type ||
306 tag == DW_TAG_restrict_type ||
307 tag == DW_TAG_volatile_type ||
308 tag == DW_TAG_shared_type);
309
310 return vr_die;
311}
312
313/* Get a type die, but skip qualifiers and typedef */
314static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
315{
316 do {
317 vr_die = __die_get_real_type(vr_die, die_mem);
318 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
185 319
186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 320 return vr_die;
187 DIE_IF(ret == DW_DLV_ERROR);
188 return inl;
189} 321}
190 322
191/* Get the offset of abstruct_origin */ 323static bool die_is_signed_type(Dwarf_Die *tp_die)
192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
193{ 324{
194 Dwarf_Attribute attr; 325 Dwarf_Attribute attr;
195 Dwarf_Off cu_offs; 326 Dwarf_Word ret;
196 int ret; 327
328 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL ||
329 dwarf_formudata(&attr, &ret) != 0)
330 return false;
197 331
198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 332 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
199 DIE_IF(ret != DW_DLV_OK); 333 ret == DW_ATE_signed_fixed);
200 ret = dwarf_formref(attr, &cu_offs, &__dw_error);
201 DIE_IF(ret != DW_DLV_OK);
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
203 return cu_offs;
204} 334}
205 335
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 336static int die_get_byte_size(Dwarf_Die *tp_die)
207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die)
208{ 337{
209 Dwarf_Attribute attr; 338 Dwarf_Attribute attr;
210 Dwarf_Addr addr; 339 Dwarf_Word ret;
211 Dwarf_Off offs;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret;
215 340
216 /* Try to get entry pc */ 341 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL ||
217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 342 dwarf_formudata(&attr, &ret) != 0)
218 DIE_IF(ret == DW_DLV_ERROR); 343 return 0;
219 if (ret == DW_DLV_OK) { 344
220 ret = dwarf_formaddr(attr, &addr, &__dw_error); 345 return (int)ret;
221 DIE_IF(ret != DW_DLV_OK);
222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
223 return addr;
224 }
225
226 /* Try to get low pc */
227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error);
228 DIE_IF(ret == DW_DLV_ERROR);
229 if (ret == DW_DLV_OK)
230 return addr;
231
232 /* Try to get ranges */
233 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error);
234 DIE_IF(ret != DW_DLV_OK);
235 ret = dwarf_formref(attr, &offs, &__dw_error);
236 DIE_IF(ret != DW_DLV_OK);
237 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL,
238 &__dw_error);
239 DIE_IF(ret != DW_DLV_OK);
240 addr = ranges[0].dwr_addr1;
241 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
242 return addr;
243} 346}
244 347
245/* 348/* Get data_member_location offset */
246 * Search a Die from Die tree. 349static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
247 * Note: cur_link->die should be deallocated in this function.
248 */
249static int __search_die_tree(struct die_link *cur_link,
250 int (*die_cb)(struct die_link *, void *),
251 void *data)
252{ 350{
253 Dwarf_Die new_die; 351 Dwarf_Attribute attr;
254 struct die_link new_link; 352 Dwarf_Op *expr;
353 size_t nexpr;
255 int ret; 354 int ret;
256 355
257 if (!die_cb) 356 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
258 return 0; 357 return -ENOENT;
259 358
260 /* Check current die */ 359 if (dwarf_formudata(&attr, offs) != 0) {
261 while (!(ret = die_cb(cur_link, data))) { 360 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
262 /* Check child die */ 361 ret = dwarf_getlocation(&attr, &expr, &nexpr);
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error); 362 if (ret < 0 || nexpr == 0)
264 DIE_IF(ret == DW_DLV_ERROR); 363 return -ENOENT;
265 if (ret == DW_DLV_OK) { 364
266 new_link.parent = cur_link; 365 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
267 new_link.die = new_die; 366 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
268 ret = __search_die_tree(&new_link, die_cb, data); 367 expr[0].atom, nexpr);
269 if (ret) 368 return -ENOTSUP;
270 break; 369 }
271 } 370 *offs = (Dwarf_Word)expr[0].number;
272
273 /* Move to next sibling */
274 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die,
275 &__dw_error);
276 DIE_IF(ret == DW_DLV_ERROR);
277 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
278 cur_link->die = new_die;
279 if (ret == DW_DLV_NO_ENTRY)
280 return 0;
281 } 371 }
282 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE); 372 return 0;
283 return ret;
284} 373}
285 374
286/* Search a die in its children's die tree */ 375/* Return values for die_find callbacks */
287static int search_die_from_children(Dwarf_Die parent_die, 376enum {
288 int (*die_cb)(struct die_link *, void *), 377 DIE_FIND_CB_FOUND = 0, /* End of Search */
289 void *data) 378 DIE_FIND_CB_CHILD = 1, /* Search only children */
379 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
380 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
381};
382
383/* Search a child die */
384static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
385 int (*callback)(Dwarf_Die *, void *),
386 void *data, Dwarf_Die *die_mem)
290{ 387{
291 struct die_link new_link; 388 Dwarf_Die child_die;
292 int ret; 389 int ret;
293 390
294 new_link.parent = NULL; 391 ret = dwarf_child(rt_die, die_mem);
295 ret = dwarf_child(parent_die, &new_link.die, &__dw_error); 392 if (ret != 0)
296 DIE_IF(ret == DW_DLV_ERROR); 393 return NULL;
297 if (ret == DW_DLV_OK) 394
298 return __search_die_tree(&new_link, die_cb, data); 395 do {
299 else 396 ret = callback(die_mem, data);
300 return 0; 397 if (ret == DIE_FIND_CB_FOUND)
398 return die_mem;
399
400 if ((ret & DIE_FIND_CB_CHILD) &&
401 die_find_child(die_mem, callback, data, &child_die)) {
402 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
403 return die_mem;
404 }
405 } while ((ret & DIE_FIND_CB_SIBLING) &&
406 dwarf_siblingof(die_mem, die_mem) == 0);
407
408 return NULL;
301} 409}
302 410
303/* Find a locdesc corresponding to the address */ 411struct __addr_die_search_param {
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, 412 Dwarf_Addr addr;
305 Dwarf_Addr addr) 413 Dwarf_Die *die_mem;
414};
415
416static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
306{ 417{
307 Dwarf_Signed lcnt; 418 struct __addr_die_search_param *ad = data;
308 Dwarf_Locdesc **llbuf;
309 int ret, i;
310 419
311 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error); 420 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
312 DIE_IF(ret != DW_DLV_OK); 421 dwarf_haspc(fn_die, ad->addr)) {
313 ret = DW_DLV_NO_ENTRY; 422 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
314 for (i = 0; i < lcnt; ++i) { 423 return DWARF_CB_ABORT;
315 if (llbuf[i]->ld_lopc <= addr &&
316 llbuf[i]->ld_hipc > addr) {
317 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
318 desc->ld_s =
319 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
320 DIE_IF(desc->ld_s == NULL);
321 memcpy(desc->ld_s, llbuf[i]->ld_s,
322 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
323 ret = DW_DLV_OK;
324 break;
325 }
326 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
327 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
328 } 424 }
329 /* Releasing loop */ 425 return DWARF_CB_OK;
330 for (; i < lcnt; ++i) {
331 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
332 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
333 }
334 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
335 return ret;
336} 426}
337 427
338/* Get decl_file attribute value (file number) */ 428/* Search a real subprogram including this line, */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) 429static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
430 Dwarf_Die *die_mem)
340{ 431{
341 Dwarf_Attribute attr; 432 struct __addr_die_search_param ad;
342 Dwarf_Unsigned fno; 433 ad.addr = addr;
343 int ret; 434 ad.die_mem = die_mem;
435 /* dwarf_getscopes can't find subprogram. */
436 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
437 return NULL;
438 else
439 return die_mem;
440}
344 441
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); 442/* die_find callback for inline function search */
346 DIE_IF(ret != DW_DLV_OK); 443static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
347 dwarf_formudata(attr, &fno, &__dw_error); 444{
348 DIE_IF(ret != DW_DLV_OK); 445 Dwarf_Addr *addr = data;
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 446
350 return fno; 447 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
448 dwarf_haspc(die_mem, *addr))
449 return DIE_FIND_CB_FOUND;
450
451 return DIE_FIND_CB_CONTINUE;
351} 452}
352 453
353/* Get decl_line attribute value (line number) */ 454/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) 455static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
456 Dwarf_Die *die_mem)
355{ 457{
356 Dwarf_Attribute attr; 458 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
357 Dwarf_Unsigned lno; 459}
358 int ret; 460
461struct __find_variable_param {
462 const char *name;
463 Dwarf_Addr addr;
464};
465
466static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
467{
468 struct __find_variable_param *fvp = data;
469 int tag;
470
471 tag = dwarf_tag(die_mem);
472 if ((tag == DW_TAG_formal_parameter ||
473 tag == DW_TAG_variable) &&
474 die_compare_name(die_mem, fvp->name))
475 return DIE_FIND_CB_FOUND;
476
477 if (dwarf_haspc(die_mem, fvp->addr))
478 return DIE_FIND_CB_CONTINUE;
479 else
480 return DIE_FIND_CB_SIBLING;
481}
482
483/* Find a variable called 'name' at given address */
484static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
485 Dwarf_Addr addr, Dwarf_Die *die_mem)
486{
487 struct __find_variable_param fvp = { .name = name, .addr = addr};
488
489 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
490 die_mem);
491}
492
493static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
494{
495 const char *name = data;
359 496
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); 497 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
361 DIE_IF(ret != DW_DLV_OK); 498 die_compare_name(die_mem, name))
362 dwarf_formudata(attr, &lno, &__dw_error); 499 return DIE_FIND_CB_FOUND;
363 DIE_IF(ret != DW_DLV_OK); 500
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 501 return DIE_FIND_CB_SIBLING;
365 return lno; 502}
503
504/* Find a member called 'name' */
505static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
506 Dwarf_Die *die_mem)
507{
508 return die_find_child(st_die, __die_find_member_cb, (void *)name,
509 die_mem);
510}
511
512/* Get the name of given variable DIE */
513static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
514{
515 Dwarf_Die type;
516 int tag, ret, ret2;
517 const char *tmp = "";
518
519 if (__die_get_real_type(vr_die, &type) == NULL)
520 return -ENOENT;
521
522 tag = dwarf_tag(&type);
523 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
524 tmp = "*";
525 else if (tag == DW_TAG_subroutine_type) {
526 /* Function pointer */
527 ret = snprintf(buf, len, "(function_type)");
528 return (ret >= len) ? -E2BIG : ret;
529 } else {
530 if (!dwarf_diename(&type))
531 return -ENOENT;
532 if (tag == DW_TAG_union_type)
533 tmp = "union ";
534 else if (tag == DW_TAG_structure_type)
535 tmp = "struct ";
536 /* Write a base name */
537 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
538 return (ret >= len) ? -E2BIG : ret;
539 }
540 ret = die_get_typename(&type, buf, len);
541 if (ret > 0) {
542 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
543 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
544 }
545 return ret;
546}
547
548/* Get the name and type of given variable DIE, stored as "type\tname" */
549static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
550{
551 int ret, ret2;
552
553 ret = die_get_typename(vr_die, buf, len);
554 if (ret < 0) {
555 pr_debug("Failed to get type, make it unknown.\n");
556 ret = snprintf(buf, len, "(unknown_type)");
557 }
558 if (ret > 0) {
559 ret2 = snprintf(buf + ret, len - ret, "\t%s",
560 dwarf_diename(vr_die));
561 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
562 }
563 return ret;
366} 564}
367 565
368/* 566/*
369 * Probe finder related functions 567 * Probe finder related functions
370 */ 568 */
371 569
372/* Show a location */ 570static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
374{ 571{
375 Dwarf_Small op; 572 struct probe_trace_arg_ref *ref;
376 Dwarf_Unsigned regn; 573 ref = zalloc(sizeof(struct probe_trace_arg_ref));
377 Dwarf_Signed offs; 574 if (ref != NULL)
378 int deref = 0, ret; 575 ref->offset = offs;
576 return ref;
577}
578
579/*
580 * Convert a location into trace_arg.
581 * If tvar == NULL, this just checks variable can be converted.
582 */
583static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
584 Dwarf_Op *fb_ops,
585 struct probe_trace_arg *tvar)
586{
587 Dwarf_Attribute attr;
588 Dwarf_Op *op;
589 size_t nops;
590 unsigned int regn;
591 Dwarf_Word offs = 0;
592 bool ref = false;
379 const char *regs; 593 const char *regs;
594 int ret;
380 595
381 op = loc->lr_atom; 596 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
597 goto static_var;
598
599 /* TODO: handle more than 1 exprs */
600 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
601 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
602 nops == 0) {
603 /* TODO: Support const_value */
604 return -ENOENT;
605 }
606
607 if (op->atom == DW_OP_addr) {
608static_var:
609 if (!tvar)
610 return 0;
611 /* Static variables on memory (not stack), make @varname */
612 ret = strlen(dwarf_diename(vr_die));
613 tvar->value = zalloc(ret + 2);
614 if (tvar->value == NULL)
615 return -ENOMEM;
616 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
617 tvar->ref = alloc_trace_arg_ref((long)offs);
618 if (tvar->ref == NULL)
619 return -ENOMEM;
620 return 0;
621 }
382 622
383 /* If this is based on frame buffer, set the offset */ 623 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) { 624 if (op->atom == DW_OP_fbreg) {
385 deref = 1; 625 if (fb_ops == NULL)
386 offs = (Dwarf_Signed)loc->lr_number; 626 return -ENOTSUP;
387 op = pf->fbloc.ld_s[0].lr_atom; 627 ref = true;
388 loc = &pf->fbloc.ld_s[0]; 628 offs = op->number;
389 } else 629 op = &fb_ops[0];
390 offs = 0; 630 }
391 631
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 632 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
393 regn = op - DW_OP_breg0; 633 regn = op->atom - DW_OP_breg0;
394 offs += (Dwarf_Signed)loc->lr_number; 634 offs += op->number;
395 deref = 1; 635 ref = true;
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 636 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
397 regn = op - DW_OP_reg0; 637 regn = op->atom - DW_OP_reg0;
398 } else if (op == DW_OP_bregx) { 638 } else if (op->atom == DW_OP_bregx) {
399 regn = loc->lr_number; 639 regn = op->number;
400 offs += (Dwarf_Signed)loc->lr_number2; 640 offs += op->number2;
401 deref = 1; 641 ref = true;
402 } else if (op == DW_OP_regx) { 642 } else if (op->atom == DW_OP_regx) {
403 regn = loc->lr_number; 643 regn = op->number;
404 } else 644 } else {
405 die("Dwarf_OP %d is not supported.\n", op); 645 pr_debug("DW_OP %x is not supported.\n", op->atom);
646 return -ENOTSUP;
647 }
648
649 if (!tvar)
650 return 0;
406 651
407 regs = get_arch_regstr(regn); 652 regs = get_arch_regstr(regn);
408 if (!regs) 653 if (!regs) {
409 die("%lld exceeds max register number.\n", regn); 654 /* This should be a bug in DWARF or this tool */
655 pr_warning("Mapping for the register number %u "
656 "missing on this architecture.\n", regn);
657 return -ERANGE;
658 }
410 659
411 if (deref) 660 tvar->value = strdup(regs);
412 ret = snprintf(pf->buf, pf->len, 661 if (tvar->value == NULL)
413 " %s=%+lld(%s)", pf->var, offs, regs); 662 return -ENOMEM;
414 else 663
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 664 if (ref) {
416 DIE_IF(ret < 0); 665 tvar->ref = alloc_trace_arg_ref((long)offs);
417 DIE_IF(ret >= pf->len); 666 if (tvar->ref == NULL)
667 return -ENOMEM;
668 }
669 return 0;
418} 670}
419 671
420/* Show a variables in kprobe event format */ 672static int convert_variable_type(Dwarf_Die *vr_die,
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 673 struct probe_trace_arg *tvar,
674 const char *cast)
422{ 675{
423 Dwarf_Attribute attr; 676 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
424 Dwarf_Locdesc ld; 677 Dwarf_Die type;
678 char buf[16];
425 int ret; 679 int ret;
426 680
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 681 /* TODO: check all types */
428 if (ret != DW_DLV_OK) 682 if (cast && strcmp(cast, "string") != 0) {
429 goto error; 683 /* Non string type is OK */
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 684 tvar->type = strdup(cast);
431 if (ret != DW_DLV_OK) 685 return (tvar->type == NULL) ? -ENOMEM : 0;
432 goto error; 686 }
433 /* TODO? */
434 DIE_IF(ld.ld_cents != 1);
435 show_location(&ld.ld_s[0], pf);
436 free(ld.ld_s);
437 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
438 return ;
439error:
440 die("Failed to find the location of %s at this address.\n"
441 " Perhaps, it has been optimized out.\n", pf->var);
442}
443 687
444static int variable_callback(struct die_link *dlink, void *data) 688 if (die_get_real_type(vr_die, &type) == NULL) {
445{ 689 pr_warning("Failed to get a type information of %s.\n",
446 struct probe_finder *pf = (struct probe_finder *)data; 690 dwarf_diename(vr_die));
447 Dwarf_Half tag; 691 return -ENOENT;
448 int ret; 692 }
449 693
450 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 694 pr_debug("%s type is %s.\n",
451 DIE_IF(ret == DW_DLV_ERROR); 695 dwarf_diename(vr_die), dwarf_diename(&type));
452 if ((tag == DW_TAG_formal_parameter || 696
453 tag == DW_TAG_variable) && 697 if (cast && strcmp(cast, "string") == 0) { /* String type */
454 (die_compare_name(dlink->die, pf->var) == 0)) { 698 ret = dwarf_tag(&type);
455 show_variable(dlink->die, pf); 699 if (ret != DW_TAG_pointer_type &&
456 return 1; 700 ret != DW_TAG_array_type) {
701 pr_warning("Failed to cast into string: "
702 "%s(%s) is not a pointer nor array.\n",
703 dwarf_diename(vr_die), dwarf_diename(&type));
704 return -EINVAL;
705 }
706 if (ret == DW_TAG_pointer_type) {
707 if (die_get_real_type(&type, &type) == NULL) {
708 pr_warning("Failed to get a type"
709 " information.\n");
710 return -ENOENT;
711 }
712 while (*ref_ptr)
713 ref_ptr = &(*ref_ptr)->next;
714 /* Add new reference with offset +0 */
715 *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
716 if (*ref_ptr == NULL) {
717 pr_warning("Out of memory error\n");
718 return -ENOMEM;
719 }
720 }
721 if (!die_compare_name(&type, "char") &&
722 !die_compare_name(&type, "unsigned char")) {
723 pr_warning("Failed to cast into string: "
724 "%s is not (unsigned) char *.\n",
725 dwarf_diename(vr_die));
726 return -EINVAL;
727 }
728 tvar->type = strdup(cast);
729 return (tvar->type == NULL) ? -ENOMEM : 0;
730 }
731
732 ret = die_get_byte_size(&type) * 8;
733 if (ret) {
734 /* Check the bitwidth */
735 if (ret > MAX_BASIC_TYPE_BITS) {
736 pr_info("%s exceeds max-bitwidth."
737 " Cut down to %d bits.\n",
738 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
739 ret = MAX_BASIC_TYPE_BITS;
740 }
741
742 ret = snprintf(buf, 16, "%c%d",
743 die_is_signed_type(&type) ? 's' : 'u', ret);
744 if (ret < 0 || ret >= 16) {
745 if (ret >= 16)
746 ret = -E2BIG;
747 pr_warning("Failed to convert variable type: %s\n",
748 strerror(-ret));
749 return ret;
750 }
751 tvar->type = strdup(buf);
752 if (tvar->type == NULL)
753 return -ENOMEM;
457 } 754 }
458 /* TODO: Support struct members and arrays */
459 return 0; 755 return 0;
460} 756}
461 757
462/* Find a variable in a subprogram die */ 758static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 759 struct perf_probe_arg_field *field,
760 struct probe_trace_arg_ref **ref_ptr,
761 Dwarf_Die *die_mem)
464{ 762{
465 int ret; 763 struct probe_trace_arg_ref *ref = *ref_ptr;
764 Dwarf_Die type;
765 Dwarf_Word offs;
766 int ret, tag;
767
768 pr_debug("converting %s in %s\n", field->name, varname);
769 if (die_get_real_type(vr_die, &type) == NULL) {
770 pr_warning("Failed to get the type of %s.\n", varname);
771 return -ENOENT;
772 }
773 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
774 tag = dwarf_tag(&type);
775
776 if (field->name[0] == '[' &&
777 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
778 if (field->next)
779 /* Save original type for next field */
780 memcpy(die_mem, &type, sizeof(*die_mem));
781 /* Get the type of this array */
782 if (die_get_real_type(&type, &type) == NULL) {
783 pr_warning("Failed to get the type of %s.\n", varname);
784 return -ENOENT;
785 }
786 pr_debug2("Array real type: (%x)\n",
787 (unsigned)dwarf_dieoffset(&type));
788 if (tag == DW_TAG_pointer_type) {
789 ref = zalloc(sizeof(struct probe_trace_arg_ref));
790 if (ref == NULL)
791 return -ENOMEM;
792 if (*ref_ptr)
793 (*ref_ptr)->next = ref;
794 else
795 *ref_ptr = ref;
796 }
797 ref->offset += die_get_byte_size(&type) * field->index;
798 if (!field->next)
799 /* Save vr_die for converting types */
800 memcpy(die_mem, vr_die, sizeof(*die_mem));
801 goto next;
802 } else if (tag == DW_TAG_pointer_type) {
803 /* Check the pointer and dereference */
804 if (!field->ref) {
805 pr_err("Semantic error: %s must be referred by '->'\n",
806 field->name);
807 return -EINVAL;
808 }
809 /* Get the type pointed by this pointer */
810 if (die_get_real_type(&type, &type) == NULL) {
811 pr_warning("Failed to get the type of %s.\n", varname);
812 return -ENOENT;
813 }
814 /* Verify it is a data structure */
815 if (dwarf_tag(&type) != DW_TAG_structure_type) {
816 pr_warning("%s is not a data structure.\n", varname);
817 return -EINVAL;
818 }
466 819
467 if (!is_c_varname(pf->var)) { 820 ref = zalloc(sizeof(struct probe_trace_arg_ref));
468 /* Output raw parameters */ 821 if (ref == NULL)
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 822 return -ENOMEM;
470 DIE_IF(ret < 0); 823 if (*ref_ptr)
471 DIE_IF(ret >= pf->len); 824 (*ref_ptr)->next = ref;
472 return ; 825 else
826 *ref_ptr = ref;
827 } else {
828 /* Verify it is a data structure */
829 if (tag != DW_TAG_structure_type) {
830 pr_warning("%s is not a data structure.\n", varname);
831 return -EINVAL;
832 }
833 if (field->name[0] == '[') {
834 pr_err("Semantic error: %s is not a pointor"
835 " nor array.\n", varname);
836 return -EINVAL;
837 }
838 if (field->ref) {
839 pr_err("Semantic error: %s must be referred by '.'\n",
840 field->name);
841 return -EINVAL;
842 }
843 if (!ref) {
844 pr_warning("Structure on a register is not "
845 "supported yet.\n");
846 return -ENOTSUP;
847 }
473 } 848 }
474 849
475 pr_debug("Searching '%s' variable in context.\n", pf->var); 850 if (die_find_member(&type, field->name, die_mem) == NULL) {
476 /* Search child die for local variables and parameters. */ 851 pr_warning("%s(tyep:%s) has no member %s.\n", varname,
477 ret = search_die_from_children(sp_die, variable_callback, pf); 852 dwarf_diename(&type), field->name);
478 if (!ret) 853 return -EINVAL;
479 die("Failed to find '%s' in this function.\n", pf->var); 854 }
855
856 /* Get the offset of the field */
857 ret = die_get_data_member_location(die_mem, &offs);
858 if (ret < 0) {
859 pr_warning("Failed to get the offset of %s.\n", field->name);
860 return ret;
861 }
862 ref->offset += (long)offs;
863
864next:
865 /* Converting next field */
866 if (field->next)
867 return convert_variable_fields(die_mem, field->name,
868 field->next, &ref, die_mem);
869 else
870 return 0;
480} 871}
481 872
482/* Get a frame base on the address */ 873/* Show a variables in kprobe event format */
483static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf) 874static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
484{ 875{
485 Dwarf_Attribute attr; 876 Dwarf_Die die_mem;
486 int ret; 877 int ret;
487 878
488 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error); 879 pr_debug("Converting variable %s into trace event.\n",
489 DIE_IF(ret != DW_DLV_OK); 880 dwarf_diename(vr_die));
490 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base)); 881
491 DIE_IF(ret != DW_DLV_OK); 882 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
492 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 883 pf->tvar);
884 if (ret == -ENOENT)
885 pr_err("Failed to find the location of %s at this address.\n"
886 " Perhaps, it has been optimized out.\n", pf->pvar->var);
887 else if (ret == -ENOTSUP)
888 pr_err("Sorry, we don't support this variable location yet.\n");
889 else if (pf->pvar->field) {
890 ret = convert_variable_fields(vr_die, pf->pvar->var,
891 pf->pvar->field, &pf->tvar->ref,
892 &die_mem);
893 vr_die = &die_mem;
894 }
895 if (ret == 0)
896 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
897 /* *expr will be cached in libdw. Don't free it. */
898 return ret;
493} 899}
494 900
495static void free_current_frame_base(struct probe_finder *pf) 901/* Find a variable in a subprogram die */
902static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
496{ 903{
497 free(pf->fbloc.ld_s); 904 Dwarf_Die vr_die, *scopes;
498 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc)); 905 char buf[32], *ptr;
906 int ret, nscopes;
907
908 if (!is_c_varname(pf->pvar->var)) {
909 /* Copy raw parameters */
910 pf->tvar->value = strdup(pf->pvar->var);
911 if (pf->tvar->value == NULL)
912 return -ENOMEM;
913 if (pf->pvar->type) {
914 pf->tvar->type = strdup(pf->pvar->type);
915 if (pf->tvar->type == NULL)
916 return -ENOMEM;
917 }
918 if (pf->pvar->name) {
919 pf->tvar->name = strdup(pf->pvar->name);
920 if (pf->tvar->name == NULL)
921 return -ENOMEM;
922 } else
923 pf->tvar->name = NULL;
924 return 0;
925 }
926
927 if (pf->pvar->name)
928 pf->tvar->name = strdup(pf->pvar->name);
929 else {
930 ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
931 if (ret < 0)
932 return ret;
933 ptr = strchr(buf, ':'); /* Change type separator to _ */
934 if (ptr)
935 *ptr = '_';
936 pf->tvar->name = strdup(buf);
937 }
938 if (pf->tvar->name == NULL)
939 return -ENOMEM;
940
941 pr_debug("Searching '%s' variable in context.\n",
942 pf->pvar->var);
943 /* Search child die for local variables and parameters. */
944 if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
945 ret = convert_variable(&vr_die, pf);
946 else {
947 /* Search upper class */
948 nscopes = dwarf_getscopes_die(sp_die, &scopes);
949 while (nscopes-- > 1) {
950 pr_debug("Searching variables in %s\n",
951 dwarf_diename(&scopes[nscopes]));
952 /* We should check this scope, so give dummy address */
953 if (die_find_variable_at(&scopes[nscopes],
954 pf->pvar->var, 0,
955 &vr_die)) {
956 ret = convert_variable(&vr_die, pf);
957 goto found;
958 }
959 }
960 if (scopes)
961 free(scopes);
962 ret = -ENOENT;
963 }
964found:
965 if (ret < 0)
966 pr_warning("Failed to find '%s' in this function.\n",
967 pf->pvar->var);
968 return ret;
499} 969}
500 970
501/* Show a probe point to output buffer */ 971/* Convert subprogram DIE to trace point */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, 972static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
503 struct probe_finder *pf) 973 bool retprobe, struct probe_trace_point *tp)
504{ 974{
505 struct probe_point *pp = pf->pp; 975 Dwarf_Addr eaddr;
506 char *name; 976 const char *name;
507 char tmp[MAX_PROBE_BUFFER]; 977
508 int ret, i, len; 978 /* Copy the name of probe point */
509 979 name = dwarf_diename(sp_die);
510 /* Output name of probe point */ 980 if (name) {
511 ret = dwarf_diename(sp_die, &name, &__dw_error); 981 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
512 DIE_IF(ret == DW_DLV_ERROR); 982 pr_warning("Failed to get entry address of %s\n",
513 if (ret == DW_DLV_OK) { 983 dwarf_diename(sp_die));
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 984 return -ENOENT;
515 (unsigned int)offs);
516 /* Copy the function name if possible */
517 if (!pp->function) {
518 pp->function = strdup(name);
519 pp->offset = offs;
520 } 985 }
521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING); 986 tp->symbol = strdup(name);
522 } else { 987 if (tp->symbol == NULL)
988 return -ENOMEM;
989 tp->offset = (unsigned long)(paddr - eaddr);
990 } else
523 /* This function has no name. */ 991 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 992 tp->offset = (unsigned long)paddr;
525 if (!pp->function) { 993
526 /* TODO: Use _stext */ 994 /* Return probe must be on the head of a subprogram */
527 pp->function = strdup(""); 995 if (retprobe) {
528 pp->offset = (int)pf->addr; 996 if (eaddr != paddr) {
997 pr_warning("Return probe must be on the head of"
998 " a real function.\n");
999 return -EINVAL;
529 } 1000 }
1001 tp->retprobe = true;
530 } 1002 }
531 DIE_IF(ret < 0);
532 DIE_IF(ret >= MAX_PROBE_BUFFER);
533 len = ret;
534 pr_debug("Probe point found: %s\n", tmp);
535
536 /* Find each argument */
537 get_current_frame_base(sp_die, pf);
538 for (i = 0; i < pp->nr_args; i++) {
539 pf->var = pp->args[i];
540 pf->buf = &tmp[len];
541 pf->len = MAX_PROBE_BUFFER - len;
542 find_variable(sp_die, pf);
543 len += strlen(pf->buf);
544 }
545 free_current_frame_base(pf);
546 1003
547 pp->probes[pp->found] = strdup(tmp); 1004 return 0;
548 pp->found++;
549} 1005}
550 1006
551static int probeaddr_callback(struct die_link *dlink, void *data) 1007/* Call probe_finder callback with real subprogram DIE */
1008static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
552{ 1009{
553 struct probe_finder *pf = (struct probe_finder *)data; 1010 Dwarf_Die die_mem;
554 Dwarf_Half tag; 1011 Dwarf_Attribute fb_attr;
555 Dwarf_Signed offs; 1012 size_t nops;
556 int ret; 1013 int ret;
557 1014
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 1015 /* If no real subprogram, find a real one */
559 DIE_IF(ret == DW_DLV_ERROR); 1016 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
560 /* Check the address is in this subprogram */ 1017 sp_die = die_find_real_subprogram(&pf->cu_die,
561 if (tag == DW_TAG_subprogram && 1018 pf->addr, &die_mem);
562 die_within_subprogram(dlink->die, pf->addr, &offs)) { 1019 if (!sp_die) {
563 show_probepoint(dlink->die, offs, pf); 1020 pr_warning("Failed to find probe point in any "
564 return 1; 1021 "functions.\n");
1022 return -ENOENT;
1023 }
565 } 1024 }
566 return 0; 1025
1026 /* Get the frame base attribute/ops */
1027 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
1028 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
1029 if (ret <= 0 || nops == 0) {
1030 pf->fb_ops = NULL;
1031#if _ELFUTILS_PREREQ(0, 142)
1032 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
1033 pf->cfi != NULL) {
1034 Dwarf_Frame *frame;
1035 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
1036 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
1037 pr_warning("Failed to get call frame on 0x%jx\n",
1038 (uintmax_t)pf->addr);
1039 return -ENOENT;
1040 }
1041#endif
1042 }
1043
1044 /* Call finder's callback handler */
1045 ret = pf->callback(sp_die, pf);
1046
1047 /* *pf->fb_ops will be cached in libdw. Don't free it. */
1048 pf->fb_ops = NULL;
1049
1050 return ret;
567} 1051}
568 1052
569/* Find probe point from its line number */ 1053/* Find probe point from its line number */
570static void find_by_line(struct probe_finder *pf) 1054static int find_probe_point_by_line(struct probe_finder *pf)
571{ 1055{
572 Dwarf_Signed cnt, i, clm; 1056 Dwarf_Lines *lines;
573 Dwarf_Line *lines; 1057 Dwarf_Line *line;
574 Dwarf_Unsigned lineno = 0; 1058 size_t nlines, i;
575 Dwarf_Addr addr; 1059 Dwarf_Addr addr;
576 Dwarf_Unsigned fno; 1060 int lineno;
577 int ret; 1061 int ret = 0;
578 1062
579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 1063 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
580 DIE_IF(ret != DW_DLV_OK); 1064 pr_warning("No source lines found.\n");
1065 return -ENOENT;
1066 }
581 1067
582 for (i = 0; i < cnt; i++) { 1068 for (i = 0; i < nlines && ret == 0; i++) {
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 1069 line = dwarf_onesrcline(lines, i);
584 DIE_IF(ret != DW_DLV_OK); 1070 if (dwarf_lineno(line, &lineno) != 0 ||
585 if (fno != pf->fno) 1071 lineno != pf->lno)
586 continue; 1072 continue;
587 1073
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 1074 /* TODO: Get fileno from line, but how? */
589 DIE_IF(ret != DW_DLV_OK); 1075 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
590 if (lineno != pf->lno)
591 continue; 1076 continue;
592 1077
593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 1078 if (dwarf_lineaddr(line, &addr) != 0) {
594 DIE_IF(ret != DW_DLV_OK); 1079 pr_warning("Failed to get the address of the line.\n");
1080 return -ENOENT;
1081 }
1082 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
1083 (int)i, lineno, (uintmax_t)addr);
1084 pf->addr = addr;
1085
1086 ret = call_probe_finder(NULL, pf);
1087 /* Continuing, because target line might be inlined. */
1088 }
1089 return ret;
1090}
595 1091
596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 1092/* Find lines which match lazy pattern */
597 DIE_IF(ret != DW_DLV_OK); 1093static int find_lazy_match_lines(struct list_head *head,
598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n", 1094 const char *fname, const char *pat)
599 (int)i, (unsigned)lineno, (int)clm, addr); 1095{
1096 char *fbuf, *p1, *p2;
1097 int fd, line, nlines = -1;
1098 struct stat st;
1099
1100 fd = open(fname, O_RDONLY);
1101 if (fd < 0) {
1102 pr_warning("Failed to open %s: %s\n", fname, strerror(-fd));
1103 return -errno;
1104 }
1105
1106 if (fstat(fd, &st) < 0) {
1107 pr_warning("Failed to get the size of %s: %s\n",
1108 fname, strerror(errno));
1109 nlines = -errno;
1110 goto out_close;
1111 }
1112
1113 nlines = -ENOMEM;
1114 fbuf = malloc(st.st_size + 2);
1115 if (fbuf == NULL)
1116 goto out_close;
1117 if (read(fd, fbuf, st.st_size) < 0) {
1118 pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
1119 nlines = -errno;
1120 goto out_free_fbuf;
1121 }
1122 fbuf[st.st_size] = '\n'; /* Dummy line */
1123 fbuf[st.st_size + 1] = '\0';
1124 p1 = fbuf;
1125 line = 1;
1126 nlines = 0;
1127 while ((p2 = strchr(p1, '\n')) != NULL) {
1128 *p2 = '\0';
1129 if (strlazymatch(p1, pat)) {
1130 line_list__add_line(head, line);
1131 nlines++;
1132 }
1133 line++;
1134 p1 = p2 + 1;
1135 }
1136out_free_fbuf:
1137 free(fbuf);
1138out_close:
1139 close(fd);
1140 return nlines;
1141}
1142
1143/* Find probe points from lazy pattern */
1144static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1145{
1146 Dwarf_Lines *lines;
1147 Dwarf_Line *line;
1148 size_t nlines, i;
1149 Dwarf_Addr addr;
1150 Dwarf_Die die_mem;
1151 int lineno;
1152 int ret = 0;
1153
1154 if (list_empty(&pf->lcache)) {
1155 /* Matching lazy line pattern */
1156 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
1157 pf->pev->point.lazy_line);
1158 if (ret == 0) {
1159 pr_debug("No matched lines found in %s.\n", pf->fname);
1160 return 0;
1161 } else if (ret < 0)
1162 return ret;
1163 }
1164
1165 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
1166 pr_warning("No source lines found.\n");
1167 return -ENOENT;
1168 }
1169
1170 for (i = 0; i < nlines && ret >= 0; i++) {
1171 line = dwarf_onesrcline(lines, i);
1172
1173 if (dwarf_lineno(line, &lineno) != 0 ||
1174 !line_list__has_line(&pf->lcache, lineno))
1175 continue;
1176
1177 /* TODO: Get fileno from line, but how? */
1178 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
1179 continue;
1180
1181 if (dwarf_lineaddr(line, &addr) != 0) {
1182 pr_debug("Failed to get the address of line %d.\n",
1183 lineno);
1184 continue;
1185 }
1186 if (sp_die) {
1187 /* Address filtering 1: does sp_die include addr? */
1188 if (!dwarf_haspc(sp_die, addr))
1189 continue;
1190 /* Address filtering 2: No child include addr? */
1191 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1192 continue;
1193 }
1194
1195 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
1196 (int)i, lineno, (unsigned long long)addr);
600 pf->addr = addr; 1197 pf->addr = addr;
601 /* Search a real subprogram including this line, */ 1198
602 ret = search_die_from_children(pf->cu_die, 1199 ret = call_probe_finder(sp_die, pf);
603 probeaddr_callback, pf);
604 if (ret == 0)
605 die("Probe point is not found in subprograms.\n");
606 /* Continuing, because target line might be inlined. */ 1200 /* Continuing, because target line might be inlined. */
607 } 1201 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 1202 /* TODO: deallocate lines, but how? */
1203 return ret;
609} 1204}
610 1205
611/* Search function from function name */ 1206/* Callback parameter with return value */
612static int probefunc_callback(struct die_link *dlink, void *data) 1207struct dwarf_callback_param {
1208 void *data;
1209 int retval;
1210};
1211
1212static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
613{ 1213{
614 struct probe_finder *pf = (struct probe_finder *)data; 1214 struct dwarf_callback_param *param = data;
615 struct probe_point *pp = pf->pp; 1215 struct probe_finder *pf = param->data;
616 struct die_link *lk; 1216 struct perf_probe_point *pp = &pf->pev->point;
617 Dwarf_Signed offs; 1217 Dwarf_Addr addr;
618 Dwarf_Half tag;
619 int ret;
620 1218
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 1219 if (pp->lazy_line)
622 DIE_IF(ret == DW_DLV_ERROR); 1220 param->retval = find_probe_point_lazy(in_die, pf);
623 if (tag == DW_TAG_subprogram) { 1221 else {
624 if (die_compare_name(dlink->die, pp->function) == 0) { 1222 /* Get probe address */
625 if (pp->line) { /* Function relative line */ 1223 if (dwarf_entrypc(in_die, &addr) != 0) {
626 pf->fno = die_get_decl_file(dlink->die); 1224 pr_warning("Failed to get entry address of %s.\n",
627 pf->lno = die_get_decl_line(dlink->die) 1225 dwarf_diename(in_die));
628 + pp->line; 1226 param->retval = -ENOENT;
629 find_by_line(pf); 1227 return DWARF_CB_ABORT;
630 return 1; 1228 }
631 } 1229 pf->addr = addr;
632 if (die_inlined_subprogram(dlink->die)) { 1230 pf->addr += pp->offset;
633 /* Inlined function, save it. */ 1231 pr_debug("found inline addr: 0x%jx\n",
634 ret = dwarf_die_CU_offset(dlink->die, 1232 (uintmax_t)pf->addr);
635 &pf->inl_offs, 1233
636 &__dw_error); 1234 param->retval = call_probe_finder(in_die, pf);
637 DIE_IF(ret != DW_DLV_OK); 1235 if (param->retval < 0)
638 pr_debug("inline definition offset %lld\n", 1236 return DWARF_CB_ABORT;
639 pf->inl_offs); 1237 }
640 return 0; /* Continue to search */ 1238
1239 return DWARF_CB_OK;
1240}
1241
1242/* Search function from function name */
1243static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1244{
1245 struct dwarf_callback_param *param = data;
1246 struct probe_finder *pf = param->data;
1247 struct perf_probe_point *pp = &pf->pev->point;
1248
1249 /* Check tag and diename */
1250 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
1251 !die_compare_name(sp_die, pp->function))
1252 return DWARF_CB_OK;
1253
1254 pf->fname = dwarf_decl_file(sp_die);
1255 if (pp->line) { /* Function relative line */
1256 dwarf_decl_line(sp_die, &pf->lno);
1257 pf->lno += pp->line;
1258 param->retval = find_probe_point_by_line(pf);
1259 } else if (!dwarf_func_inline(sp_die)) {
1260 /* Real function */
1261 if (pp->lazy_line)
1262 param->retval = find_probe_point_lazy(sp_die, pf);
1263 else {
1264 if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
1265 pr_warning("Failed to get entry address of "
1266 "%s.\n", dwarf_diename(sp_die));
1267 param->retval = -ENOENT;
1268 return DWARF_CB_ABORT;
641 } 1269 }
642 /* Get probe address */
643 pf->addr = die_get_entrypc(dlink->die);
644 pf->addr += pp->offset; 1270 pf->addr += pp->offset;
645 /* TODO: Check the address in this function */ 1271 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, pf); 1272 param->retval = call_probe_finder(sp_die, pf);
647 return 1; /* Exit; no same symbol in this CU. */
648 } 1273 }
649 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) { 1274 } else {
650 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) { 1275 struct dwarf_callback_param _param = {.data = (void *)pf,
651 /* Get probe address */ 1276 .retval = 0};
652 pf->addr = die_get_entrypc(dlink->die); 1277 /* Inlined function: search instances */
653 pf->addr += pp->offset; 1278 dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
654 pr_debug("found inline addr: 0x%llx\n", pf->addr); 1279 &_param);
655 /* Inlined function. Get a real subprogram */ 1280 param->retval = _param.retval;
656 for (lk = dlink->parent; lk != NULL; lk = lk->parent) { 1281 }
657 tag = 0; 1282
658 dwarf_tag(lk->die, &tag, &__dw_error); 1283 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
659 DIE_IF(ret == DW_DLV_ERROR); 1284}
660 if (tag == DW_TAG_subprogram && 1285
661 !die_inlined_subprogram(lk->die)) 1286static int find_probe_point_by_func(struct probe_finder *pf)
662 goto found; 1287{
1288 struct dwarf_callback_param _param = {.data = (void *)pf,
1289 .retval = 0};
1290 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
1291 return _param.retval;
1292}
1293
1294/* Find probe points from debuginfo */
1295static int find_probes(int fd, struct probe_finder *pf)
1296{
1297 struct perf_probe_point *pp = &pf->pev->point;
1298 Dwarf_Off off, noff;
1299 size_t cuhl;
1300 Dwarf_Die *diep;
1301 Dwarf *dbg = NULL;
1302 Dwfl *dwfl;
1303 Dwarf_Addr bias; /* Currently ignored */
1304 int ret = 0;
1305
1306 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1307 if (!dbg) {
1308 pr_warning("No debug information found in the vmlinux - "
1309 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1310 return -EBADF;
1311 }
1312
1313#if _ELFUTILS_PREREQ(0, 142)
1314 /* Get the call frame information from this dwarf */
1315 pf->cfi = dwarf_getcfi(dbg);
1316#endif
1317
1318 off = 0;
1319 line_list__init(&pf->lcache);
1320 /* Loop on CUs (Compilation Unit) */
1321 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
1322 ret >= 0) {
1323 /* Get the DIE(Debugging Information Entry) of this CU */
1324 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
1325 if (!diep)
1326 continue;
1327
1328 /* Check if target file is included. */
1329 if (pp->file)
1330 pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
1331 else
1332 pf->fname = NULL;
1333
1334 if (!pp->file || pf->fname) {
1335 if (pp->function)
1336 ret = find_probe_point_by_func(pf);
1337 else if (pp->lazy_line)
1338 ret = find_probe_point_lazy(NULL, pf);
1339 else {
1340 pf->lno = pp->line;
1341 ret = find_probe_point_by_line(pf);
663 } 1342 }
664 die("Failed to find real subprogram.\n");
665found:
666 /* Get offset from subprogram */
667 ret = die_within_subprogram(lk->die, pf->addr, &offs);
668 DIE_IF(!ret);
669 show_probepoint(lk->die, offs, pf);
670 /* Continue to search */
671 } 1343 }
1344 off = noff;
1345 }
1346 line_list__free(&pf->lcache);
1347 if (dwfl)
1348 dwfl_end(dwfl);
1349
1350 return ret;
1351}
1352
1353/* Add a found probe point into trace event list */
1354static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1355{
1356 struct trace_event_finder *tf =
1357 container_of(pf, struct trace_event_finder, pf);
1358 struct probe_trace_event *tev;
1359 int ret, i;
1360
1361 /* Check number of tevs */
1362 if (tf->ntevs == tf->max_tevs) {
1363 pr_warning("Too many( > %d) probe point found.\n",
1364 tf->max_tevs);
1365 return -ERANGE;
672 } 1366 }
1367 tev = &tf->tevs[tf->ntevs++];
1368
1369 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
1370 &tev->point);
1371 if (ret < 0)
1372 return ret;
1373
1374 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1375 tev->point.offset);
1376
1377 /* Find each argument */
1378 tev->nargs = pf->pev->nargs;
1379 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1380 if (tev->args == NULL)
1381 return -ENOMEM;
1382 for (i = 0; i < pf->pev->nargs; i++) {
1383 pf->pvar = &pf->pev->args[i];
1384 pf->tvar = &tev->args[i];
1385 ret = find_variable(sp_die, pf);
1386 if (ret != 0)
1387 return ret;
1388 }
1389
673 return 0; 1390 return 0;
674} 1391}
675 1392
676static void find_by_func(struct probe_finder *pf) 1393/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1394int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1395 struct probe_trace_event **tevs, int max_tevs)
1396{
1397 struct trace_event_finder tf = {
1398 .pf = {.pev = pev, .callback = add_probe_trace_event},
1399 .max_tevs = max_tevs};
1400 int ret;
1401
1402 /* Allocate result tevs array */
1403 *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1404 if (*tevs == NULL)
1405 return -ENOMEM;
1406
1407 tf.tevs = *tevs;
1408 tf.ntevs = 0;
1409
1410 ret = find_probes(fd, &tf.pf);
1411 if (ret < 0) {
1412 free(*tevs);
1413 *tevs = NULL;
1414 return ret;
1415 }
1416
1417 return (ret < 0) ? ret : tf.ntevs;
1418}
1419
1420#define MAX_VAR_LEN 64
1421
1422/* Collect available variables in this scope */
1423static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1424{
1425 struct available_var_finder *af = data;
1426 struct variable_list *vl;
1427 char buf[MAX_VAR_LEN];
1428 int tag, ret;
1429
1430 vl = &af->vls[af->nvls - 1];
1431
1432 tag = dwarf_tag(die_mem);
1433 if (tag == DW_TAG_formal_parameter ||
1434 tag == DW_TAG_variable) {
1435 ret = convert_variable_location(die_mem, af->pf.addr,
1436 af->pf.fb_ops, NULL);
1437 if (ret == 0) {
1438 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1439 pr_debug2("Add new var: %s\n", buf);
1440 if (ret > 0)
1441 strlist__add(vl->vars, buf);
1442 }
1443 }
1444
1445 if (af->child && dwarf_haspc(die_mem, af->pf.addr))
1446 return DIE_FIND_CB_CONTINUE;
1447 else
1448 return DIE_FIND_CB_SIBLING;
1449}
1450
1451/* Add a found vars into available variables list */
1452static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1453{
1454 struct available_var_finder *af =
1455 container_of(pf, struct available_var_finder, pf);
1456 struct variable_list *vl;
1457 Dwarf_Die die_mem, *scopes = NULL;
1458 int ret, nscopes;
1459
1460 /* Check number of tevs */
1461 if (af->nvls == af->max_vls) {
1462 pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
1463 return -ERANGE;
1464 }
1465 vl = &af->vls[af->nvls++];
1466
1467 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
1468 &vl->point);
1469 if (ret < 0)
1470 return ret;
1471
1472 pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
1473 vl->point.offset);
1474
1475 /* Find local variables */
1476 vl->vars = strlist__new(true, NULL);
1477 if (vl->vars == NULL)
1478 return -ENOMEM;
1479 af->child = true;
1480 die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
1481
1482 /* Find external variables */
1483 if (!af->externs)
1484 goto out;
1485 /* Don't need to search child DIE for externs. */
1486 af->child = false;
1487 nscopes = dwarf_getscopes_die(sp_die, &scopes);
1488 while (nscopes-- > 1)
1489 die_find_child(&scopes[nscopes], collect_variables_cb,
1490 (void *)af, &die_mem);
1491 if (scopes)
1492 free(scopes);
1493
1494out:
1495 if (strlist__empty(vl->vars)) {
1496 strlist__delete(vl->vars);
1497 vl->vars = NULL;
1498 }
1499
1500 return ret;
1501}
1502
1503/* Find available variables at given probe point */
1504int find_available_vars_at(int fd, struct perf_probe_event *pev,
1505 struct variable_list **vls, int max_vls,
1506 bool externs)
1507{
1508 struct available_var_finder af = {
1509 .pf = {.pev = pev, .callback = add_available_vars},
1510 .max_vls = max_vls, .externs = externs};
1511 int ret;
1512
1513 /* Allocate result vls array */
1514 *vls = zalloc(sizeof(struct variable_list) * max_vls);
1515 if (*vls == NULL)
1516 return -ENOMEM;
1517
1518 af.vls = *vls;
1519 af.nvls = 0;
1520
1521 ret = find_probes(fd, &af.pf);
1522 if (ret < 0) {
1523 /* Free vlist for error */
1524 while (af.nvls--) {
1525 if (af.vls[af.nvls].point.symbol)
1526 free(af.vls[af.nvls].point.symbol);
1527 if (af.vls[af.nvls].vars)
1528 strlist__delete(af.vls[af.nvls].vars);
1529 }
1530 free(af.vls);
1531 *vls = NULL;
1532 return ret;
1533 }
1534
1535 return (ret < 0) ? ret : af.nvls;
1536}
1537
1538/* Reverse search */
1539int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1540{
1541 Dwarf_Die cudie, spdie, indie;
1542 Dwarf *dbg = NULL;
1543 Dwfl *dwfl = NULL;
1544 Dwarf_Line *line;
1545 Dwarf_Addr laddr, eaddr, bias = 0;
1546 const char *tmp;
1547 int lineno, ret = 0;
1548 bool found = false;
1549
1550 /* Open the live linux kernel */
1551 dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
1552 if (!dbg) {
1553 pr_warning("No debug information found in the vmlinux - "
1554 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1555 ret = -EINVAL;
1556 goto end;
1557 }
1558
1559 /* Adjust address with bias */
1560 addr += bias;
1561 /* Find cu die */
1562 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
1563 pr_warning("Failed to find debug information for address %lx\n",
1564 addr);
1565 ret = -EINVAL;
1566 goto end;
1567 }
1568
1569 /* Find a corresponding line */
1570 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
1571 if (line) {
1572 if (dwarf_lineaddr(line, &laddr) == 0 &&
1573 (Dwarf_Addr)addr == laddr &&
1574 dwarf_lineno(line, &lineno) == 0) {
1575 tmp = dwarf_linesrc(line, NULL, NULL);
1576 if (tmp) {
1577 ppt->line = lineno;
1578 ppt->file = strdup(tmp);
1579 if (ppt->file == NULL) {
1580 ret = -ENOMEM;
1581 goto end;
1582 }
1583 found = true;
1584 }
1585 }
1586 }
1587
1588 /* Find a corresponding function */
1589 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
1590 tmp = dwarf_diename(&spdie);
1591 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0)
1592 goto end;
1593
1594 if (ppt->line) {
1595 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1596 &indie)) {
1597 /* addr in an inline function */
1598 tmp = dwarf_diename(&indie);
1599 if (!tmp)
1600 goto end;
1601 ret = dwarf_decl_line(&indie, &lineno);
1602 } else {
1603 if (eaddr == addr) { /* Function entry */
1604 lineno = ppt->line;
1605 ret = 0;
1606 } else
1607 ret = dwarf_decl_line(&spdie, &lineno);
1608 }
1609 if (ret == 0) {
1610 /* Make a relative line number */
1611 ppt->line -= lineno;
1612 goto found;
1613 }
1614 }
1615 /* We don't have a line number, let's use offset */
1616 ppt->offset = addr - (unsigned long)eaddr;
1617found:
1618 ppt->function = strdup(tmp);
1619 if (ppt->function == NULL) {
1620 ret = -ENOMEM;
1621 goto end;
1622 }
1623 found = true;
1624 }
1625
1626end:
1627 if (dwfl)
1628 dwfl_end(dwfl);
1629 if (ret >= 0)
1630 ret = found ? 1 : 0;
1631 return ret;
1632}
1633
1634/* Add a line and store the src path */
1635static int line_range_add_line(const char *src, unsigned int lineno,
1636 struct line_range *lr)
677{ 1637{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf); 1638 /* Copy source path */
1639 if (!lr->path) {
1640 lr->path = strdup(src);
1641 if (lr->path == NULL)
1642 return -ENOMEM;
1643 }
1644 return line_list__add_line(&lr->line_list, lineno);
679} 1645}
680 1646
681/* Find a probe point */ 1647/* Search function declaration lines */
682int find_probepoint(int fd, struct probe_point *pp) 1648static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
683{ 1649{
684 Dwarf_Half addr_size = 0; 1650 struct dwarf_callback_param *param = data;
685 Dwarf_Unsigned next_cuh = 0; 1651 struct line_finder *lf = param->data;
686 int cu_number = 0, ret; 1652 const char *src;
687 struct probe_finder pf = {.pp = pp}; 1653 int lineno;
1654
1655 src = dwarf_decl_file(sp_die);
1656 if (src && strtailcmp(src, lf->fname) != 0)
1657 return DWARF_CB_OK;
1658
1659 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1660 (lf->lno_s > lineno || lf->lno_e < lineno))
1661 return DWARF_CB_OK;
1662
1663 param->retval = line_range_add_line(src, lineno, lf->lr);
1664 if (param->retval < 0)
1665 return DWARF_CB_ABORT;
1666 return DWARF_CB_OK;
1667}
1668
1669static int find_line_range_func_decl_lines(struct line_finder *lf)
1670{
1671 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1672 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
1673 return param.retval;
1674}
1675
1676/* Find line range from its line number */
1677static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1678{
1679 Dwarf_Lines *lines;
1680 Dwarf_Line *line;
1681 size_t nlines, i;
1682 Dwarf_Addr addr;
1683 int lineno, ret = 0;
1684 const char *src;
1685 Dwarf_Die die_mem;
688 1686
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 1687 line_list__init(&lf->lr->line_list);
690 if (ret != DW_DLV_OK) 1688 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1689 pr_warning("No source lines found.\n");
691 return -ENOENT; 1690 return -ENOENT;
1691 }
1692
1693 /* Search probable lines on lines list */
1694 for (i = 0; i < nlines; i++) {
1695 line = dwarf_onesrcline(lines, i);
1696 if (dwarf_lineno(line, &lineno) != 0 ||
1697 (lf->lno_s > lineno || lf->lno_e < lineno))
1698 continue;
1699
1700 if (sp_die) {
1701 /* Address filtering 1: does sp_die include addr? */
1702 if (dwarf_lineaddr(line, &addr) != 0 ||
1703 !dwarf_haspc(sp_die, addr))
1704 continue;
1705
1706 /* Address filtering 2: No child include addr? */
1707 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1708 continue;
1709 }
1710
1711 /* TODO: Get fileno from line, but how? */
1712 src = dwarf_linesrc(line, NULL, NULL);
1713 if (strtailcmp(src, lf->fname) != 0)
1714 continue;
1715
1716 ret = line_range_add_line(src, lineno, lf->lr);
1717 if (ret < 0)
1718 return ret;
1719 }
1720
1721 /*
1722 * Dwarf lines doesn't include function declarations. We have to
1723 * check functions list or given function.
1724 */
1725 if (sp_die) {
1726 src = dwarf_decl_file(sp_die);
1727 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1728 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1729 ret = line_range_add_line(src, lineno, lf->lr);
1730 } else
1731 ret = find_line_range_func_decl_lines(lf);
1732
1733 /* Update status */
1734 if (ret >= 0)
1735 if (!list_empty(&lf->lr->line_list))
1736 ret = lf->found = 1;
1737 else
1738 ret = 0; /* Lines are not found */
1739 else {
1740 free(lf->lr->path);
1741 lf->lr->path = NULL;
1742 }
1743 return ret;
1744}
692 1745
693 pp->found = 0; 1746static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
694 while (++cu_number) { 1747{
695 /* Search CU (Compilation Unit) */ 1748 struct dwarf_callback_param *param = data;
696 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 1749
697 &addr_size, &next_cuh, &__dw_error); 1750 param->retval = find_line_range_by_line(in_die, param->data);
698 DIE_IF(ret == DW_DLV_ERROR); 1751 return DWARF_CB_ABORT; /* No need to find other instances */
699 if (ret == DW_DLV_NO_ENTRY) 1752}
1753
1754/* Search function from function name */
1755static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
1756{
1757 struct dwarf_callback_param *param = data;
1758 struct line_finder *lf = param->data;
1759 struct line_range *lr = lf->lr;
1760
1761 pr_debug("find (%llx) %s\n",
1762 (unsigned long long)dwarf_dieoffset(sp_die),
1763 dwarf_diename(sp_die));
1764 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1765 die_compare_name(sp_die, lr->function)) {
1766 lf->fname = dwarf_decl_file(sp_die);
1767 dwarf_decl_line(sp_die, &lr->offset);
1768 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
1769 lf->lno_s = lr->offset + lr->start;
1770 if (lf->lno_s < 0) /* Overflow */
1771 lf->lno_s = INT_MAX;
1772 lf->lno_e = lr->offset + lr->end;
1773 if (lf->lno_e < 0) /* Overflow */
1774 lf->lno_e = INT_MAX;
1775 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
1776 lr->start = lf->lno_s;
1777 lr->end = lf->lno_e;
1778 if (dwarf_func_inline(sp_die)) {
1779 struct dwarf_callback_param _param;
1780 _param.data = (void *)lf;
1781 _param.retval = 0;
1782 dwarf_func_inline_instances(sp_die,
1783 line_range_inline_cb,
1784 &_param);
1785 param->retval = _param.retval;
1786 } else
1787 param->retval = find_line_range_by_line(sp_die, lf);
1788 return DWARF_CB_ABORT;
1789 }
1790 return DWARF_CB_OK;
1791}
1792
1793static int find_line_range_by_func(struct line_finder *lf)
1794{
1795 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1796 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, &param, 0);
1797 return param.retval;
1798}
1799
1800int find_line_range(int fd, struct line_range *lr)
1801{
1802 struct line_finder lf = {.lr = lr, .found = 0};
1803 int ret = 0;
1804 Dwarf_Off off = 0, noff;
1805 size_t cuhl;
1806 Dwarf_Die *diep;
1807 Dwarf *dbg = NULL;
1808 Dwfl *dwfl;
1809 Dwarf_Addr bias; /* Currently ignored */
1810 const char *comp_dir;
1811
1812 dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
1813 if (!dbg) {
1814 pr_warning("No debug information found in the vmlinux - "
1815 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1816 return -EBADF;
1817 }
1818
1819 /* Loop on CUs (Compilation Unit) */
1820 while (!lf.found && ret >= 0) {
1821 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
700 break; 1822 break;
701 1823
702 /* Get the DIE(Debugging Information Entry) of this CU */ 1824 /* Get the DIE(Debugging Information Entry) of this CU */
703 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 1825 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
704 DIE_IF(ret != DW_DLV_OK); 1826 if (!diep)
1827 continue;
705 1828
706 /* Check if target file is included. */ 1829 /* Check if target file is included. */
707 if (pp->file) 1830 if (lr->file)
708 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 1831 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
709 1832 else
710 if (!pp->file || pf.fno) { 1833 lf.fname = 0;
711 /* Save CU base address (for frame_base) */ 1834
712 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 1835 if (!lr->file || lf.fname) {
713 DIE_IF(ret == DW_DLV_ERROR); 1836 if (lr->function)
714 if (ret == DW_DLV_NO_ENTRY) 1837 ret = find_line_range_by_func(&lf);
715 pf.cu_base = 0;
716 if (pp->function)
717 find_by_func(&pf);
718 else { 1838 else {
719 pf.lno = pp->line; 1839 lf.lno_s = lr->start;
720 find_by_line(&pf); 1840 lf.lno_e = lr->end;
1841 ret = find_line_range_by_line(NULL, &lf);
721 } 1842 }
722 } 1843 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 1844 off = noff;
1845 }
1846
1847 /* Store comp_dir */
1848 if (lf.found) {
1849 comp_dir = cu_get_comp_dir(&lf.cu_die);
1850 if (comp_dir) {
1851 lr->comp_dir = strdup(comp_dir);
1852 if (!lr->comp_dir)
1853 ret = -ENOMEM;
1854 }
724 } 1855 }
725 ret = dwarf_finish(__dw_debug, &__dw_error);
726 DIE_IF(ret != DW_DLV_OK);
727 1856
728 return pp->found; 1857 pr_debug("path: %s\n", lr->path);
1858 dwfl_end(dwfl);
1859 return (ret < 0) ? ret : lf.found;
729} 1860}
730 1861
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index a4086aaddb73..beaefc3c1223 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,6 +1,10 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#include <stdbool.h>
5#include "util.h"
6#include "probe-event.h"
7
4#define MAX_PATH_LEN 256 8#define MAX_PATH_LEN 256
5#define MAX_PROBE_BUFFER 1024 9#define MAX_PROBE_BUFFER 1024
6#define MAX_PROBES 128 10#define MAX_PROBES 128
@@ -11,55 +15,77 @@ static inline int is_c_varname(const char *name)
11 return isalpha(name[0]) || name[0] == '_'; 15 return isalpha(name[0]) || name[0] == '_';
12} 16}
13 17
14struct probe_point { 18#ifdef DWARF_SUPPORT
15 char *event; /* Event name */ 19/* Find probe_trace_events specified by perf_probe_event from debuginfo */
16 char *group; /* Event group */ 20extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
21 struct probe_trace_event **tevs,
22 int max_tevs);
17 23
18 /* Inputs */ 24/* Find a perf_probe_point from debuginfo */
19 char *file; /* File name */ 25extern int find_perf_probe_point(unsigned long addr,
20 int line; /* Line number */ 26 struct perf_probe_point *ppt);
21 27
22 char *function; /* Function name */ 28/* Find a line range */
23 int offset; /* Offset bytes */ 29extern int find_line_range(int fd, struct line_range *lr);
24 30
25 int nr_args; /* Number of arguments */ 31/* Find available variables */
26 char **args; /* Arguments */ 32extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
33 struct variable_list **vls, int max_points,
34 bool externs);
27 35
28 int retprobe; /* Return probe */ 36#include <dwarf.h>
37#include <elfutils/libdw.h>
38#include <elfutils/libdwfl.h>
39#include <elfutils/version.h>
29 40
30 /* Output */ 41struct probe_finder {
31 int found; /* Number of found probe points */ 42 struct perf_probe_event *pev; /* Target probe event */
32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
33};
34 43
35#ifndef NO_LIBDWARF 44 /* Callback when a probe point is found */
36extern int find_probepoint(int fd, struct probe_point *pp); 45 int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
37 46
38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */ 47 /* For function searching */
39#ifndef _MIPS_SZLONG 48 int lno; /* Line number */
40# define _MIPS_SZLONG 0 49 Dwarf_Addr addr; /* Address */
50 const char *fname; /* Real file name */
51 Dwarf_Die cu_die; /* Current CU */
52 struct list_head lcache; /* Line cache for lazy match */
53
54 /* For variable searching */
55#if _ELFUTILS_PREREQ(0, 142)
56 Dwarf_CFI *cfi; /* Call Frame Information */
41#endif 57#endif
58 Dwarf_Op *fb_ops; /* Frame base attribute */
59 struct perf_probe_arg *pvar; /* Current target variable */
60 struct probe_trace_arg *tvar; /* Current result variable */
61};
42 62
43#include <dwarf.h> 63struct trace_event_finder {
44#include <libdwarf.h> 64 struct probe_finder pf;
65 struct probe_trace_event *tevs; /* Found trace events */
66 int ntevs; /* Number of trace events */
67 int max_tevs; /* Max number of trace events */
68};
45 69
46struct probe_finder { 70struct available_var_finder {
47 struct probe_point *pp; /* Target probe point */ 71 struct probe_finder pf;
72 struct variable_list *vls; /* Found variable lists */
73 int nvls; /* Number of variable lists */
74 int max_vls; /* Max no. of variable lists */
75 bool externs; /* Find external vars too */
76 bool child; /* Search child scopes */
77};
48 78
49 /* For function searching */ 79struct line_finder {
50 Dwarf_Addr addr; /* Address */ 80 struct line_range *lr; /* Target line range */
51 Dwarf_Unsigned fno; /* File number */
52 Dwarf_Unsigned lno; /* Line number */
53 Dwarf_Off inl_offs; /* Inline offset */
54 Dwarf_Die cu_die; /* Current CU */
55 81
56 /* For variable searching */ 82 const char *fname; /* File name */
57 Dwarf_Addr cu_base; /* Current CU base address */ 83 int lno_s; /* Start line number */
58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 84 int lno_e; /* End line number */
59 const char *var; /* Current variable name */ 85 Dwarf_Die cu_die; /* Current CU */
60 char *buf; /* Current output buffer */ 86 int found;
61 int len; /* Length of output buffer */
62}; 87};
63#endif /* NO_LIBDWARF */ 88
89#endif /* DWARF_SUPPORT */
64 90
65#endif /*_PROBE_FINDER_H */ 91#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
new file mode 100644
index 000000000000..13d36faf64eb
--- /dev/null
+++ b/tools/perf/util/pstack.c
@@ -0,0 +1,75 @@
1/*
2 * Simple pointer stack
3 *
4 * (c) 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
5 */
6
7#include "util.h"
8#include "pstack.h"
9#include <linux/kernel.h>
10#include <stdlib.h>
11
12struct pstack {
13 unsigned short top;
14 unsigned short max_nr_entries;
15 void *entries[0];
16};
17
18struct pstack *pstack__new(unsigned short max_nr_entries)
19{
20 struct pstack *self = zalloc((sizeof(*self) +
21 max_nr_entries * sizeof(void *)));
22 if (self != NULL)
23 self->max_nr_entries = max_nr_entries;
24 return self;
25}
26
27void pstack__delete(struct pstack *self)
28{
29 free(self);
30}
31
32bool pstack__empty(const struct pstack *self)
33{
34 return self->top == 0;
35}
36
37void pstack__remove(struct pstack *self, void *key)
38{
39 unsigned short i = self->top, last_index = self->top - 1;
40
41 while (i-- != 0) {
42 if (self->entries[i] == key) {
43 if (i < last_index)
44 memmove(self->entries + i,
45 self->entries + i + 1,
46 (last_index - i) * sizeof(void *));
47 --self->top;
48 return;
49 }
50 }
51 pr_err("%s: %p not on the pstack!\n", __func__, key);
52}
53
54void pstack__push(struct pstack *self, void *key)
55{
56 if (self->top == self->max_nr_entries) {
57 pr_err("%s: top=%d, overflow!\n", __func__, self->top);
58 return;
59 }
60 self->entries[self->top++] = key;
61}
62
63void *pstack__pop(struct pstack *self)
64{
65 void *ret;
66
67 if (self->top == 0) {
68 pr_err("%s: underflow!\n", __func__);
69 return NULL;
70 }
71
72 ret = self->entries[--self->top];
73 self->entries[self->top] = NULL;
74 return ret;
75}
diff --git a/tools/perf/util/pstack.h b/tools/perf/util/pstack.h
new file mode 100644
index 000000000000..4cedea59f518
--- /dev/null
+++ b/tools/perf/util/pstack.h
@@ -0,0 +1,14 @@
1#ifndef _PERF_PSTACK_
2#define _PERF_PSTACK_
3
4#include <stdbool.h>
5
6struct pstack;
7struct pstack *pstack__new(unsigned short max_nr_entries);
8void pstack__delete(struct pstack *self);
9bool pstack__empty(const struct pstack *self);
10void pstack__remove(struct pstack *self, void *key);
11void pstack__push(struct pstack *self, void *key);
12void *pstack__pop(struct pstack *self);
13
14#endif /* _PERF_PSTACK_ */
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c
index 2726fe40eb5d..01f03242b86a 100644
--- a/tools/perf/util/quote.c
+++ b/tools/perf/util/quote.c
@@ -1,8 +1,6 @@
1#include "cache.h" 1#include "cache.h"
2#include "quote.h" 2#include "quote.h"
3 3
4int quote_path_fully = 1;
5
6/* Help to copy the thing properly quoted for the shell safety. 4/* Help to copy the thing properly quoted for the shell safety.
7 * any single quote is replaced with '\'', any exclamation point 5 * any single quote is replaced with '\'', any exclamation point
8 * is replaced with '\!', and the whole thing is enclosed in a 6 * is replaced with '\!', and the whole thing is enclosed in a
@@ -19,7 +17,7 @@ static inline int need_bs_quote(char c)
19 return (c == '\'' || c == '!'); 17 return (c == '\'' || c == '!');
20} 18}
21 19
22void sq_quote_buf(struct strbuf *dst, const char *src) 20static void sq_quote_buf(struct strbuf *dst, const char *src)
23{ 21{
24 char *to_free = NULL; 22 char *to_free = NULL;
25 23
@@ -41,23 +39,6 @@ void sq_quote_buf(struct strbuf *dst, const char *src)
41 free(to_free); 39 free(to_free);
42} 40}
43 41
44void sq_quote_print(FILE *stream, const char *src)
45{
46 char c;
47
48 fputc('\'', stream);
49 while ((c = *src++)) {
50 if (need_bs_quote(c)) {
51 fputs("'\\", stream);
52 fputc(c, stream);
53 fputc('\'', stream);
54 } else {
55 fputc(c, stream);
56 }
57 }
58 fputc('\'', stream);
59}
60
61void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) 42void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
62{ 43{
63 int i; 44 int i;
@@ -71,415 +52,3 @@ void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen)
71 die("Too many or long arguments"); 52 die("Too many or long arguments");
72 } 53 }
73} 54}
74
75char *sq_dequote_step(char *arg, char **next)
76{
77 char *dst = arg;
78 char *src = arg;
79 char c;
80
81 if (*src != '\'')
82 return NULL;
83 for (;;) {
84 c = *++src;
85 if (!c)
86 return NULL;
87 if (c != '\'') {
88 *dst++ = c;
89 continue;
90 }
91 /* We stepped out of sq */
92 switch (*++src) {
93 case '\0':
94 *dst = 0;
95 if (next)
96 *next = NULL;
97 return arg;
98 case '\\':
99 c = *++src;
100 if (need_bs_quote(c) && *++src == '\'') {
101 *dst++ = c;
102 continue;
103 }
104 /* Fallthrough */
105 default:
106 if (!next || !isspace(*src))
107 return NULL;
108 do {
109 c = *++src;
110 } while (isspace(c));
111 *dst = 0;
112 *next = src;
113 return arg;
114 }
115 }
116}
117
118char *sq_dequote(char *arg)
119{
120 return sq_dequote_step(arg, NULL);
121}
122
123int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc)
124{
125 char *next = arg;
126
127 if (!*arg)
128 return 0;
129 do {
130 char *dequoted = sq_dequote_step(next, &next);
131 if (!dequoted)
132 return -1;
133 ALLOC_GROW(*argv, *nr + 1, *alloc);
134 (*argv)[(*nr)++] = dequoted;
135 } while (next);
136
137 return 0;
138}
139
140/* 1 means: quote as octal
141 * 0 means: quote as octal if (quote_path_fully)
142 * -1 means: never quote
143 * c: quote as "\\c"
144 */
145#define X8(x) x, x, x, x, x, x, x, x
146#define X16(x) X8(x), X8(x)
147static signed char const sq_lookup[256] = {
148 /* 0 1 2 3 4 5 6 7 */
149 /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 'a',
150 /* 0x08 */ 'b', 't', 'n', 'v', 'f', 'r', 1, 1,
151 /* 0x10 */ X16(1),
152 /* 0x20 */ -1, -1, '"', -1, -1, -1, -1, -1,
153 /* 0x28 */ X16(-1), X16(-1), X16(-1),
154 /* 0x58 */ -1, -1, -1, -1,'\\', -1, -1, -1,
155 /* 0x60 */ X16(-1), X8(-1),
156 /* 0x78 */ -1, -1, -1, -1, -1, -1, -1, 1,
157 /* 0x80 */ /* set to 0 */
158};
159
160static inline int sq_must_quote(char c)
161{
162 return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
163}
164
165/*
166 * Returns the longest prefix not needing a quote up to maxlen if
167 * positive.
168 * This stops at the first \0 because it's marked as a character
169 * needing an escape.
170 */
171static ssize_t next_quote_pos(const char *s, ssize_t maxlen)
172{
173 ssize_t len;
174
175 if (maxlen < 0) {
176 for (len = 0; !sq_must_quote(s[len]); len++);
177 } else {
178 for (len = 0; len < maxlen && !sq_must_quote(s[len]); len++);
179 }
180 return len;
181}
182
183/*
184 * C-style name quoting.
185 *
186 * (1) if sb and fp are both NULL, inspect the input name and counts the
187 * number of bytes that are needed to hold c_style quoted version of name,
188 * counting the double quotes around it but not terminating NUL, and
189 * returns it.
190 * However, if name does not need c_style quoting, it returns 0.
191 *
192 * (2) if sb or fp are not NULL, it emits the c_style quoted version
193 * of name, enclosed with double quotes if asked and needed only.
194 * Return value is the same as in (1).
195 */
196static size_t quote_c_style_counted(const char *name, ssize_t maxlen,
197 struct strbuf *sb, FILE *fp, int no_dq)
198{
199#define EMIT(c) \
200 do { \
201 if (sb) strbuf_addch(sb, (c)); \
202 if (fp) fputc((c), fp); \
203 count++; \
204 } while (0)
205
206#define EMITBUF(s, l) \
207 do { \
208 int __ret; \
209 if (sb) strbuf_add(sb, (s), (l)); \
210 if (fp) __ret = fwrite((s), (l), 1, fp); \
211 count += (l); \
212 } while (0)
213
214 ssize_t len, count = 0;
215 const char *p = name;
216
217 for (;;) {
218 int ch;
219
220 len = next_quote_pos(p, maxlen);
221 if (len == maxlen || !p[len])
222 break;
223
224 if (!no_dq && p == name)
225 EMIT('"');
226
227 EMITBUF(p, len);
228 EMIT('\\');
229 p += len;
230 ch = (unsigned char)*p++;
231 if (sq_lookup[ch] >= ' ') {
232 EMIT(sq_lookup[ch]);
233 } else {
234 EMIT(((ch >> 6) & 03) + '0');
235 EMIT(((ch >> 3) & 07) + '0');
236 EMIT(((ch >> 0) & 07) + '0');
237 }
238 }
239
240 EMITBUF(p, len);
241 if (p == name) /* no ending quote needed */
242 return 0;
243
244 if (!no_dq)
245 EMIT('"');
246 return count;
247}
248
249size_t quote_c_style(const char *name, struct strbuf *sb, FILE *fp, int nodq)
250{
251 return quote_c_style_counted(name, -1, sb, fp, nodq);
252}
253
254void quote_two_c_style(struct strbuf *sb, const char *prefix, const char *path, int nodq)
255{
256 if (quote_c_style(prefix, NULL, NULL, 0) ||
257 quote_c_style(path, NULL, NULL, 0)) {
258 if (!nodq)
259 strbuf_addch(sb, '"');
260 quote_c_style(prefix, sb, NULL, 1);
261 quote_c_style(path, sb, NULL, 1);
262 if (!nodq)
263 strbuf_addch(sb, '"');
264 } else {
265 strbuf_addstr(sb, prefix);
266 strbuf_addstr(sb, path);
267 }
268}
269
270void write_name_quoted(const char *name, FILE *fp, int terminator)
271{
272 if (terminator) {
273 quote_c_style(name, NULL, fp, 0);
274 } else {
275 fputs(name, fp);
276 }
277 fputc(terminator, fp);
278}
279
280void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
281 const char *name, FILE *fp, int terminator)
282{
283 int needquote = 0;
284
285 if (terminator) {
286 needquote = next_quote_pos(pfx, pfxlen) < pfxlen
287 || name[next_quote_pos(name, -1)];
288 }
289 if (needquote) {
290 fputc('"', fp);
291 quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
292 quote_c_style(name, NULL, fp, 1);
293 fputc('"', fp);
294 } else {
295 int ret;
296
297 ret = fwrite(pfx, pfxlen, 1, fp);
298 fputs(name, fp);
299 }
300 fputc(terminator, fp);
301}
302
303/* quote path as relative to the given prefix */
304char *quote_path_relative(const char *in, int len,
305 struct strbuf *out, const char *prefix)
306{
307 int needquote;
308
309 if (len < 0)
310 len = strlen(in);
311
312 /* "../" prefix itself does not need quoting, but "in" might. */
313 needquote = (next_quote_pos(in, len) < len);
314 strbuf_setlen(out, 0);
315 strbuf_grow(out, len);
316
317 if (needquote)
318 strbuf_addch(out, '"');
319 if (prefix) {
320 int off = 0;
321 while (off < len && prefix[off] && prefix[off] == in[off])
322 if (prefix[off] == '/') {
323 prefix += off + 1;
324 in += off + 1;
325 len -= off + 1;
326 off = 0;
327 } else
328 off++;
329
330 for (; *prefix; prefix++)
331 if (*prefix == '/')
332 strbuf_addstr(out, "../");
333 }
334
335 quote_c_style_counted (in, len, out, NULL, 1);
336
337 if (needquote)
338 strbuf_addch(out, '"');
339 if (!out->len)
340 strbuf_addstr(out, "./");
341
342 return out->buf;
343}
344
345/*
346 * C-style name unquoting.
347 *
348 * Quoted should point at the opening double quote.
349 * + Returns 0 if it was able to unquote the string properly, and appends the
350 * result in the strbuf `sb'.
351 * + Returns -1 in case of error, and doesn't touch the strbuf. Though note
352 * that this function will allocate memory in the strbuf, so calling
353 * strbuf_release is mandatory whichever result unquote_c_style returns.
354 *
355 * Updates endp pointer to point at one past the ending double quote if given.
356 */
357int unquote_c_style(struct strbuf *sb, const char *quoted, const char **endp)
358{
359 size_t oldlen = sb->len, len;
360 int ch, ac;
361
362 if (*quoted++ != '"')
363 return -1;
364
365 for (;;) {
366 len = strcspn(quoted, "\"\\");
367 strbuf_add(sb, quoted, len);
368 quoted += len;
369
370 switch (*quoted++) {
371 case '"':
372 if (endp)
373 *endp = quoted;
374 return 0;
375 case '\\':
376 break;
377 default:
378 goto error;
379 }
380
381 switch ((ch = *quoted++)) {
382 case 'a': ch = '\a'; break;
383 case 'b': ch = '\b'; break;
384 case 'f': ch = '\f'; break;
385 case 'n': ch = '\n'; break;
386 case 'r': ch = '\r'; break;
387 case 't': ch = '\t'; break;
388 case 'v': ch = '\v'; break;
389
390 case '\\': case '"':
391 break; /* verbatim */
392
393 /* octal values with first digit over 4 overflow */
394 case '0': case '1': case '2': case '3':
395 ac = ((ch - '0') << 6);
396 if ((ch = *quoted++) < '0' || '7' < ch)
397 goto error;
398 ac |= ((ch - '0') << 3);
399 if ((ch = *quoted++) < '0' || '7' < ch)
400 goto error;
401 ac |= (ch - '0');
402 ch = ac;
403 break;
404 default:
405 goto error;
406 }
407 strbuf_addch(sb, ch);
408 }
409
410 error:
411 strbuf_setlen(sb, oldlen);
412 return -1;
413}
414
415/* quoting as a string literal for other languages */
416
417void perl_quote_print(FILE *stream, const char *src)
418{
419 const char sq = '\'';
420 const char bq = '\\';
421 char c;
422
423 fputc(sq, stream);
424 while ((c = *src++)) {
425 if (c == sq || c == bq)
426 fputc(bq, stream);
427 fputc(c, stream);
428 }
429 fputc(sq, stream);
430}
431
432void python_quote_print(FILE *stream, const char *src)
433{
434 const char sq = '\'';
435 const char bq = '\\';
436 const char nl = '\n';
437 char c;
438
439 fputc(sq, stream);
440 while ((c = *src++)) {
441 if (c == nl) {
442 fputc(bq, stream);
443 fputc('n', stream);
444 continue;
445 }
446 if (c == sq || c == bq)
447 fputc(bq, stream);
448 fputc(c, stream);
449 }
450 fputc(sq, stream);
451}
452
453void tcl_quote_print(FILE *stream, const char *src)
454{
455 char c;
456
457 fputc('"', stream);
458 while ((c = *src++)) {
459 switch (c) {
460 case '[': case ']':
461 case '{': case '}':
462 case '$': case '\\': case '"':
463 fputc('\\', stream);
464 default:
465 fputc(c, stream);
466 break;
467 case '\f':
468 fputs("\\f", stream);
469 break;
470 case '\r':
471 fputs("\\r", stream);
472 break;
473 case '\n':
474 fputs("\\n", stream);
475 break;
476 case '\t':
477 fputs("\\t", stream);
478 break;
479 case '\v':
480 fputs("\\v", stream);
481 break;
482 }
483 }
484 fputc('"', stream);
485}
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index b6a019733919..172889ea234f 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -22,47 +22,8 @@
22 * 22 *
23 * Note that the above examples leak memory! Remember to free result from 23 * Note that the above examples leak memory! Remember to free result from
24 * sq_quote() in a real application. 24 * sq_quote() in a real application.
25 *
26 * sq_quote_buf() writes to an existing buffer of specified size; it
27 * will return the number of characters that would have been written
28 * excluding the final null regardless of the buffer size.
29 */ 25 */
30 26
31extern void sq_quote_print(FILE *stream, const char *src);
32
33extern void sq_quote_buf(struct strbuf *, const char *src);
34extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); 27extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
35 28
36/* This unwraps what sq_quote() produces in place, but returns
37 * NULL if the input does not look like what sq_quote would have
38 * produced.
39 */
40extern char *sq_dequote(char *);
41
42/*
43 * Same as the above, but can be used to unwrap many arguments in the
44 * same string separated by space. "next" is changed to point to the
45 * next argument that should be passed as first parameter. When there
46 * is no more argument to be dequoted, "next" is updated to point to NULL.
47 */
48extern char *sq_dequote_step(char *arg, char **next);
49extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc);
50
51extern int unquote_c_style(struct strbuf *, const char *quoted, const char **endp);
52extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq);
53extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
54
55extern void write_name_quoted(const char *name, FILE *, int terminator);
56extern void write_name_quotedpfx(const char *pfx, ssize_t pfxlen,
57 const char *name, FILE *, int terminator);
58
59/* quote path as relative to the given prefix */
60char *quote_path_relative(const char *in, int len,
61 struct strbuf *out, const char *prefix);
62
63/* quoting as a string literal for other languages */
64extern void perl_quote_print(FILE *stream, const char *src);
65extern void python_quote_print(FILE *stream, const char *src);
66extern void tcl_quote_print(FILE *stream, const char *src);
67
68#endif /* __PERF_QUOTE_H */ 29#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
index 2b615acf94d7..da8e9b285f51 100644
--- a/tools/perf/util/run-command.c
+++ b/tools/perf/util/run-command.c
@@ -212,93 +212,3 @@ int run_command_v_opt(const char **argv, int opt)
212 prepare_run_command_v_opt(&cmd, argv, opt); 212 prepare_run_command_v_opt(&cmd, argv, opt);
213 return run_command(&cmd); 213 return run_command(&cmd);
214} 214}
215
216int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
217{
218 struct child_process cmd;
219 prepare_run_command_v_opt(&cmd, argv, opt);
220 cmd.dir = dir;
221 cmd.env = env;
222 return run_command(&cmd);
223}
224
225int start_async(struct async *async)
226{
227 int pipe_out[2];
228
229 if (pipe(pipe_out) < 0)
230 return error("cannot create pipe: %s", strerror(errno));
231 async->out = pipe_out[0];
232
233 /* Flush stdio before fork() to avoid cloning buffers */
234 fflush(NULL);
235
236 async->pid = fork();
237 if (async->pid < 0) {
238 error("fork (async) failed: %s", strerror(errno));
239 close_pair(pipe_out);
240 return -1;
241 }
242 if (!async->pid) {
243 close(pipe_out[0]);
244 exit(!!async->proc(pipe_out[1], async->data));
245 }
246 close(pipe_out[1]);
247
248 return 0;
249}
250
251int finish_async(struct async *async)
252{
253 int ret = 0;
254
255 if (wait_or_whine(async->pid))
256 ret = error("waitpid (async) failed");
257
258 return ret;
259}
260
261int run_hook(const char *index_file, const char *name, ...)
262{
263 struct child_process hook;
264 const char **argv = NULL, *env[2];
265 char idx[PATH_MAX];
266 va_list args;
267 int ret;
268 size_t i = 0, alloc = 0;
269
270 if (access(perf_path("hooks/%s", name), X_OK) < 0)
271 return 0;
272
273 va_start(args, name);
274 ALLOC_GROW(argv, i + 1, alloc);
275 argv[i++] = perf_path("hooks/%s", name);
276 while (argv[i-1]) {
277 ALLOC_GROW(argv, i + 1, alloc);
278 argv[i++] = va_arg(args, const char *);
279 }
280 va_end(args);
281
282 memset(&hook, 0, sizeof(hook));
283 hook.argv = argv;
284 hook.no_stdin = 1;
285 hook.stdout_to_stderr = 1;
286 if (index_file) {
287 snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file);
288 env[0] = idx;
289 env[1] = NULL;
290 hook.env = env;
291 }
292
293 ret = start_command(&hook);
294 free(argv);
295 if (ret) {
296 warning("Could not spawn %s", argv[0]);
297 return ret;
298 }
299 ret = finish_command(&hook);
300 if (ret == -ERR_RUN_COMMAND_WAITPID_SIGNAL)
301 warning("%s exited due to uncaught signal", argv[0]);
302
303 return ret;
304}
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
index d79028727ce2..1ef264d5069c 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/perf/util/run-command.h
@@ -50,39 +50,9 @@ int start_command(struct child_process *);
50int finish_command(struct child_process *); 50int finish_command(struct child_process *);
51int run_command(struct child_process *); 51int run_command(struct child_process *);
52 52
53extern int run_hook(const char *index_file, const char *name, ...);
54
55#define RUN_COMMAND_NO_STDIN 1 53#define RUN_COMMAND_NO_STDIN 1
56#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */ 54#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */
57#define RUN_COMMAND_STDOUT_TO_STDERR 4 55#define RUN_COMMAND_STDOUT_TO_STDERR 4
58int run_command_v_opt(const char **argv, int opt); 56int run_command_v_opt(const char **argv, int opt);
59 57
60/*
61 * env (the environment) is to be formatted like environ: "VAR=VALUE".
62 * To unset an environment variable use just "VAR".
63 */
64int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env);
65
66/*
67 * The purpose of the following functions is to feed a pipe by running
68 * a function asynchronously and providing output that the caller reads.
69 *
70 * It is expected that no synchronization and mutual exclusion between
71 * the caller and the feed function is necessary so that the function
72 * can run in a thread without interfering with the caller.
73 */
74struct async {
75 /*
76 * proc writes to fd and closes it;
77 * returns 0 on success, non-zero on failure
78 */
79 int (*proc)(int fd, void *data);
80 void *data;
81 int out; /* caller reads from here and closes it */
82 pid_t pid;
83};
84
85int start_async(struct async *async);
86int finish_async(struct async *async);
87
88#endif /* __PERF_RUN_COMMAND_H */ 58#endif /* __PERF_RUN_COMMAND_H */
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 6d6d76b8a21e..93680818e244 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * trace-event-perl. Feed perf trace events to an embedded Perl interpreter. 2 * trace-event-perl. Feed perf script events to an embedded Perl interpreter.
3 * 3 *
4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> 4 * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com>
5 * 5 *
@@ -25,10 +25,16 @@
25#include <ctype.h> 25#include <ctype.h>
26#include <errno.h> 26#include <errno.h>
27 27
28#include "../perf.h" 28#include "../../perf.h"
29#include "util.h" 29#include "../util.h"
30#include "trace-event.h" 30#include "../trace-event.h"
31#include "trace-event-perl.h" 31
32#include <EXTERN.h>
33#include <perl.h>
34
35void boot_Perf__Trace__Context(pTHX_ CV *cv);
36void boot_DynaLoader(pTHX_ CV *cv);
37typedef PerlInterpreter * INTERP;
32 38
33void xs_init(pTHX); 39void xs_init(pTHX);
34 40
@@ -49,7 +55,7 @@ INTERP my_perl;
49 55
50struct event *events[FTRACE_MAX_EVENT]; 56struct event *events[FTRACE_MAX_EVENT];
51 57
52static struct scripting_context *scripting_context; 58extern struct scripting_context *scripting_context;
53 59
54static char *cur_field_name; 60static char *cur_field_name;
55static int zero_flag_atom; 61static int zero_flag_atom;
@@ -239,33 +245,6 @@ static inline struct event *find_cache_event(int type)
239 return event; 245 return event;
240} 246}
241 247
242int common_pc(struct scripting_context *context)
243{
244 int pc;
245
246 pc = parse_common_pc(context->event_data);
247
248 return pc;
249}
250
251int common_flags(struct scripting_context *context)
252{
253 int flags;
254
255 flags = parse_common_flags(context->event_data);
256
257 return flags;
258}
259
260int common_lock_depth(struct scripting_context *context)
261{
262 int lock_depth;
263
264 lock_depth = parse_common_lock_depth(context->event_data);
265
266 return lock_depth;
267}
268
269static void perl_process_event(int cpu, void *data, 248static void perl_process_event(int cpu, void *data,
270 int size __unused, 249 int size __unused,
271 unsigned long long nsecs, char *comm) 250 unsigned long long nsecs, char *comm)
@@ -392,7 +371,6 @@ static int perl_start_script(const char *script, int argc, const char **argv)
392 run_start_sub(); 371 run_start_sub();
393 372
394 free(command_line); 373 free(command_line);
395 fprintf(stderr, "perf trace started with Perl script %s\n\n", script);
396 return 0; 374 return 0;
397error: 375error:
398 perl_free(my_perl); 376 perl_free(my_perl);
@@ -415,8 +393,6 @@ static int perl_stop_script(void)
415 perl_destruct(my_perl); 393 perl_destruct(my_perl);
416 perl_free(my_perl); 394 perl_free(my_perl);
417 395
418 fprintf(stderr, "\nperf trace Perl script stopped\n");
419
420 return 0; 396 return 0;
421} 397}
422 398
@@ -435,8 +411,8 @@ static int perl_generate_script(const char *outfile)
435 return -1; 411 return -1;
436 } 412 }
437 413
438 fprintf(ofp, "# perf trace event handlers, " 414 fprintf(ofp, "# perf script event handlers, "
439 "generated by perf trace -g perl\n"); 415 "generated by perf script -g perl\n");
440 416
441 fprintf(ofp, "# Licensed under the terms of the GNU GPL" 417 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
442 " License version 2\n\n"); 418 " License version 2\n\n");
@@ -587,75 +563,3 @@ struct scripting_ops perl_scripting_ops = {
587 .process_event = perl_process_event, 563 .process_event = perl_process_event,
588 .generate_script = perl_generate_script, 564 .generate_script = perl_generate_script,
589}; 565};
590
591static void print_unsupported_msg(void)
592{
593 fprintf(stderr, "Perl scripting not supported."
594 " Install libperl and rebuild perf to enable it.\n"
595 "For example:\n # apt-get install libperl-dev (ubuntu)"
596 "\n # yum install perl-ExtUtils-Embed (Fedora)"
597 "\n etc.\n");
598}
599
600static int perl_start_script_unsupported(const char *script __unused,
601 int argc __unused,
602 const char **argv __unused)
603{
604 print_unsupported_msg();
605
606 return -1;
607}
608
609static int perl_stop_script_unsupported(void)
610{
611 return 0;
612}
613
614static void perl_process_event_unsupported(int cpu __unused,
615 void *data __unused,
616 int size __unused,
617 unsigned long long nsecs __unused,
618 char *comm __unused)
619{
620}
621
622static int perl_generate_script_unsupported(const char *outfile __unused)
623{
624 print_unsupported_msg();
625
626 return -1;
627}
628
629struct scripting_ops perl_scripting_unsupported_ops = {
630 .name = "Perl",
631 .start_script = perl_start_script_unsupported,
632 .stop_script = perl_stop_script_unsupported,
633 .process_event = perl_process_event_unsupported,
634 .generate_script = perl_generate_script_unsupported,
635};
636
637static void register_perl_scripting(struct scripting_ops *scripting_ops)
638{
639 int err;
640 err = script_spec_register("Perl", scripting_ops);
641 if (err)
642 die("error registering Perl script extension");
643
644 err = script_spec_register("pl", scripting_ops);
645 if (err)
646 die("error registering pl script extension");
647
648 scripting_context = malloc(sizeof(struct scripting_context));
649}
650
651#ifdef NO_LIBPERL
652void setup_perl_scripting(void)
653{
654 register_perl_scripting(&perl_scripting_unsupported_ops);
655}
656#else
657void setup_perl_scripting(void)
658{
659 register_perl_scripting(&perl_scripting_ops);
660}
661#endif
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
new file mode 100644
index 000000000000..c6d99334bdfa
--- /dev/null
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -0,0 +1,594 @@
1/*
2 * trace-event-python. Feed trace events to an embedded Python interpreter.
3 *
4 * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com>
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 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <Python.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <errno.h>
29
30#include "../../perf.h"
31#include "../util.h"
32#include "../trace-event.h"
33
34PyMODINIT_FUNC initperf_trace_context(void);
35
36#define FTRACE_MAX_EVENT \
37 ((1 << (sizeof(unsigned short) * 8)) - 1)
38
39struct event *events[FTRACE_MAX_EVENT];
40
41#define MAX_FIELDS 64
42#define N_COMMON_FIELDS 7
43
44extern struct scripting_context *scripting_context;
45
46static char *cur_field_name;
47static int zero_flag_atom;
48
49static PyObject *main_module, *main_dict;
50
51static void handler_call_die(const char *handler_name)
52{
53 PyErr_Print();
54 Py_FatalError("problem in Python trace event handler");
55}
56
57static void define_value(enum print_arg_type field_type,
58 const char *ev_name,
59 const char *field_name,
60 const char *field_value,
61 const char *field_str)
62{
63 const char *handler_name = "define_flag_value";
64 PyObject *handler, *t, *retval;
65 unsigned long long value;
66 unsigned n = 0;
67
68 if (field_type == PRINT_SYMBOL)
69 handler_name = "define_symbolic_value";
70
71 t = PyTuple_New(4);
72 if (!t)
73 Py_FatalError("couldn't create Python tuple");
74
75 value = eval_flag(field_value);
76
77 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
78 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
79 PyTuple_SetItem(t, n++, PyInt_FromLong(value));
80 PyTuple_SetItem(t, n++, PyString_FromString(field_str));
81
82 handler = PyDict_GetItemString(main_dict, handler_name);
83 if (handler && PyCallable_Check(handler)) {
84 retval = PyObject_CallObject(handler, t);
85 if (retval == NULL)
86 handler_call_die(handler_name);
87 }
88
89 Py_DECREF(t);
90}
91
92static void define_values(enum print_arg_type field_type,
93 struct print_flag_sym *field,
94 const char *ev_name,
95 const char *field_name)
96{
97 define_value(field_type, ev_name, field_name, field->value,
98 field->str);
99
100 if (field->next)
101 define_values(field_type, field->next, ev_name, field_name);
102}
103
104static void define_field(enum print_arg_type field_type,
105 const char *ev_name,
106 const char *field_name,
107 const char *delim)
108{
109 const char *handler_name = "define_flag_field";
110 PyObject *handler, *t, *retval;
111 unsigned n = 0;
112
113 if (field_type == PRINT_SYMBOL)
114 handler_name = "define_symbolic_field";
115
116 if (field_type == PRINT_FLAGS)
117 t = PyTuple_New(3);
118 else
119 t = PyTuple_New(2);
120 if (!t)
121 Py_FatalError("couldn't create Python tuple");
122
123 PyTuple_SetItem(t, n++, PyString_FromString(ev_name));
124 PyTuple_SetItem(t, n++, PyString_FromString(field_name));
125 if (field_type == PRINT_FLAGS)
126 PyTuple_SetItem(t, n++, PyString_FromString(delim));
127
128 handler = PyDict_GetItemString(main_dict, handler_name);
129 if (handler && PyCallable_Check(handler)) {
130 retval = PyObject_CallObject(handler, t);
131 if (retval == NULL)
132 handler_call_die(handler_name);
133 }
134
135 Py_DECREF(t);
136}
137
138static void define_event_symbols(struct event *event,
139 const char *ev_name,
140 struct print_arg *args)
141{
142 switch (args->type) {
143 case PRINT_NULL:
144 break;
145 case PRINT_ATOM:
146 define_value(PRINT_FLAGS, ev_name, cur_field_name, "0",
147 args->atom.atom);
148 zero_flag_atom = 0;
149 break;
150 case PRINT_FIELD:
151 if (cur_field_name)
152 free(cur_field_name);
153 cur_field_name = strdup(args->field.name);
154 break;
155 case PRINT_FLAGS:
156 define_event_symbols(event, ev_name, args->flags.field);
157 define_field(PRINT_FLAGS, ev_name, cur_field_name,
158 args->flags.delim);
159 define_values(PRINT_FLAGS, args->flags.flags, ev_name,
160 cur_field_name);
161 break;
162 case PRINT_SYMBOL:
163 define_event_symbols(event, ev_name, args->symbol.field);
164 define_field(PRINT_SYMBOL, ev_name, cur_field_name, NULL);
165 define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
166 cur_field_name);
167 break;
168 case PRINT_STRING:
169 break;
170 case PRINT_TYPE:
171 define_event_symbols(event, ev_name, args->typecast.item);
172 break;
173 case PRINT_OP:
174 if (strcmp(args->op.op, ":") == 0)
175 zero_flag_atom = 1;
176 define_event_symbols(event, ev_name, args->op.left);
177 define_event_symbols(event, ev_name, args->op.right);
178 break;
179 default:
180 /* we should warn... */
181 return;
182 }
183
184 if (args->next)
185 define_event_symbols(event, ev_name, args->next);
186}
187
188static inline struct event *find_cache_event(int type)
189{
190 static char ev_name[256];
191 struct event *event;
192
193 if (events[type])
194 return events[type];
195
196 events[type] = event = trace_find_event(type);
197 if (!event)
198 return NULL;
199
200 sprintf(ev_name, "%s__%s", event->system, event->name);
201
202 define_event_symbols(event, ev_name, event->print_fmt.args);
203
204 return event;
205}
206
207static void python_process_event(int cpu, void *data,
208 int size __unused,
209 unsigned long long nsecs, char *comm)
210{
211 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
212 static char handler_name[256];
213 struct format_field *field;
214 unsigned long long val;
215 unsigned long s, ns;
216 struct event *event;
217 unsigned n = 0;
218 int type;
219 int pid;
220
221 t = PyTuple_New(MAX_FIELDS);
222 if (!t)
223 Py_FatalError("couldn't create Python tuple");
224
225 type = trace_parse_common_type(data);
226
227 event = find_cache_event(type);
228 if (!event)
229 die("ug! no event found for type %d", type);
230
231 pid = trace_parse_common_pid(data);
232
233 sprintf(handler_name, "%s__%s", event->system, event->name);
234
235 handler = PyDict_GetItemString(main_dict, handler_name);
236 if (handler && !PyCallable_Check(handler))
237 handler = NULL;
238 if (!handler) {
239 dict = PyDict_New();
240 if (!dict)
241 Py_FatalError("couldn't create Python dict");
242 }
243 s = nsecs / NSECS_PER_SEC;
244 ns = nsecs - s * NSECS_PER_SEC;
245
246 scripting_context->event_data = data;
247
248 context = PyCObject_FromVoidPtr(scripting_context, NULL);
249
250 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
251 PyTuple_SetItem(t, n++,
252 PyCObject_FromVoidPtr(scripting_context, NULL));
253
254 if (handler) {
255 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
256 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
257 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
258 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
259 PyTuple_SetItem(t, n++, PyString_FromString(comm));
260 } else {
261 PyDict_SetItemString(dict, "common_cpu", PyInt_FromLong(cpu));
262 PyDict_SetItemString(dict, "common_s", PyInt_FromLong(s));
263 PyDict_SetItemString(dict, "common_ns", PyInt_FromLong(ns));
264 PyDict_SetItemString(dict, "common_pid", PyInt_FromLong(pid));
265 PyDict_SetItemString(dict, "common_comm", PyString_FromString(comm));
266 }
267 for (field = event->format.fields; field; field = field->next) {
268 if (field->flags & FIELD_IS_STRING) {
269 int offset;
270 if (field->flags & FIELD_IS_DYNAMIC) {
271 offset = *(int *)(data + field->offset);
272 offset &= 0xffff;
273 } else
274 offset = field->offset;
275 obj = PyString_FromString((char *)data + offset);
276 } else { /* FIELD_IS_NUMERIC */
277 val = read_size(data + field->offset, field->size);
278 if (field->flags & FIELD_IS_SIGNED) {
279 if ((long long)val >= LONG_MIN &&
280 (long long)val <= LONG_MAX)
281 obj = PyInt_FromLong(val);
282 else
283 obj = PyLong_FromLongLong(val);
284 } else {
285 if (val <= LONG_MAX)
286 obj = PyInt_FromLong(val);
287 else
288 obj = PyLong_FromUnsignedLongLong(val);
289 }
290 }
291 if (handler)
292 PyTuple_SetItem(t, n++, obj);
293 else
294 PyDict_SetItemString(dict, field->name, obj);
295
296 }
297 if (!handler)
298 PyTuple_SetItem(t, n++, dict);
299
300 if (_PyTuple_Resize(&t, n) == -1)
301 Py_FatalError("error resizing Python tuple");
302
303 if (handler) {
304 retval = PyObject_CallObject(handler, t);
305 if (retval == NULL)
306 handler_call_die(handler_name);
307 } else {
308 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
309 if (handler && PyCallable_Check(handler)) {
310
311 retval = PyObject_CallObject(handler, t);
312 if (retval == NULL)
313 handler_call_die("trace_unhandled");
314 }
315 Py_DECREF(dict);
316 }
317
318 Py_DECREF(t);
319}
320
321static int run_start_sub(void)
322{
323 PyObject *handler, *retval;
324 int err = 0;
325
326 main_module = PyImport_AddModule("__main__");
327 if (main_module == NULL)
328 return -1;
329 Py_INCREF(main_module);
330
331 main_dict = PyModule_GetDict(main_module);
332 if (main_dict == NULL) {
333 err = -1;
334 goto error;
335 }
336 Py_INCREF(main_dict);
337
338 handler = PyDict_GetItemString(main_dict, "trace_begin");
339 if (handler == NULL || !PyCallable_Check(handler))
340 goto out;
341
342 retval = PyObject_CallObject(handler, NULL);
343 if (retval == NULL)
344 handler_call_die("trace_begin");
345
346 Py_DECREF(retval);
347 return err;
348error:
349 Py_XDECREF(main_dict);
350 Py_XDECREF(main_module);
351out:
352 return err;
353}
354
355/*
356 * Start trace script
357 */
358static int python_start_script(const char *script, int argc, const char **argv)
359{
360 const char **command_line;
361 char buf[PATH_MAX];
362 int i, err = 0;
363 FILE *fp;
364
365 command_line = malloc((argc + 1) * sizeof(const char *));
366 command_line[0] = script;
367 for (i = 1; i < argc + 1; i++)
368 command_line[i] = argv[i - 1];
369
370 Py_Initialize();
371
372 initperf_trace_context();
373
374 PySys_SetArgv(argc + 1, (char **)command_line);
375
376 fp = fopen(script, "r");
377 if (!fp) {
378 sprintf(buf, "Can't open python script \"%s\"", script);
379 perror(buf);
380 err = -1;
381 goto error;
382 }
383
384 err = PyRun_SimpleFile(fp, script);
385 if (err) {
386 fprintf(stderr, "Error running python script %s\n", script);
387 goto error;
388 }
389
390 err = run_start_sub();
391 if (err) {
392 fprintf(stderr, "Error starting python script %s\n", script);
393 goto error;
394 }
395
396 free(command_line);
397
398 return err;
399error:
400 Py_Finalize();
401 free(command_line);
402
403 return err;
404}
405
406/*
407 * Stop trace script
408 */
409static int python_stop_script(void)
410{
411 PyObject *handler, *retval;
412 int err = 0;
413
414 handler = PyDict_GetItemString(main_dict, "trace_end");
415 if (handler == NULL || !PyCallable_Check(handler))
416 goto out;
417
418 retval = PyObject_CallObject(handler, NULL);
419 if (retval == NULL)
420 handler_call_die("trace_end");
421 else
422 Py_DECREF(retval);
423out:
424 Py_XDECREF(main_dict);
425 Py_XDECREF(main_module);
426 Py_Finalize();
427
428 return err;
429}
430
431static int python_generate_script(const char *outfile)
432{
433 struct event *event = NULL;
434 struct format_field *f;
435 char fname[PATH_MAX];
436 int not_first, count;
437 FILE *ofp;
438
439 sprintf(fname, "%s.py", outfile);
440 ofp = fopen(fname, "w");
441 if (ofp == NULL) {
442 fprintf(stderr, "couldn't open %s\n", fname);
443 return -1;
444 }
445 fprintf(ofp, "# perf script event handlers, "
446 "generated by perf script -g python\n");
447
448 fprintf(ofp, "# Licensed under the terms of the GNU GPL"
449 " License version 2\n\n");
450
451 fprintf(ofp, "# The common_* event handler fields are the most useful "
452 "fields common to\n");
453
454 fprintf(ofp, "# all events. They don't necessarily correspond to "
455 "the 'common_*' fields\n");
456
457 fprintf(ofp, "# in the format files. Those fields not available as "
458 "handler params can\n");
459
460 fprintf(ofp, "# be retrieved using Python functions of the form "
461 "common_*(context).\n");
462
463 fprintf(ofp, "# See the perf-trace-python Documentation for the list "
464 "of available functions.\n\n");
465
466 fprintf(ofp, "import os\n");
467 fprintf(ofp, "import sys\n\n");
468
469 fprintf(ofp, "sys.path.append(os.environ['PERF_EXEC_PATH'] + \\\n");
470 fprintf(ofp, "\t'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')\n");
471 fprintf(ofp, "\nfrom perf_trace_context import *\n");
472 fprintf(ofp, "from Core import *\n\n\n");
473
474 fprintf(ofp, "def trace_begin():\n");
475 fprintf(ofp, "\tprint \"in trace_begin\"\n\n");
476
477 fprintf(ofp, "def trace_end():\n");
478 fprintf(ofp, "\tprint \"in trace_end\"\n\n");
479
480 while ((event = trace_find_next_event(event))) {
481 fprintf(ofp, "def %s__%s(", event->system, event->name);
482 fprintf(ofp, "event_name, ");
483 fprintf(ofp, "context, ");
484 fprintf(ofp, "common_cpu,\n");
485 fprintf(ofp, "\tcommon_secs, ");
486 fprintf(ofp, "common_nsecs, ");
487 fprintf(ofp, "common_pid, ");
488 fprintf(ofp, "common_comm,\n\t");
489
490 not_first = 0;
491 count = 0;
492
493 for (f = event->format.fields; f; f = f->next) {
494 if (not_first++)
495 fprintf(ofp, ", ");
496 if (++count % 5 == 0)
497 fprintf(ofp, "\n\t");
498
499 fprintf(ofp, "%s", f->name);
500 }
501 fprintf(ofp, "):\n");
502
503 fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
504 "common_secs, common_nsecs,\n\t\t\t"
505 "common_pid, common_comm)\n\n");
506
507 fprintf(ofp, "\t\tprint \"");
508
509 not_first = 0;
510 count = 0;
511
512 for (f = event->format.fields; f; f = f->next) {
513 if (not_first++)
514 fprintf(ofp, ", ");
515 if (count && count % 3 == 0) {
516 fprintf(ofp, "\" \\\n\t\t\"");
517 }
518 count++;
519
520 fprintf(ofp, "%s=", f->name);
521 if (f->flags & FIELD_IS_STRING ||
522 f->flags & FIELD_IS_FLAG ||
523 f->flags & FIELD_IS_SYMBOLIC)
524 fprintf(ofp, "%%s");
525 else if (f->flags & FIELD_IS_SIGNED)
526 fprintf(ofp, "%%d");
527 else
528 fprintf(ofp, "%%u");
529 }
530
531 fprintf(ofp, "\\n\" %% \\\n\t\t(");
532
533 not_first = 0;
534 count = 0;
535
536 for (f = event->format.fields; f; f = f->next) {
537 if (not_first++)
538 fprintf(ofp, ", ");
539
540 if (++count % 5 == 0)
541 fprintf(ofp, "\n\t\t");
542
543 if (f->flags & FIELD_IS_FLAG) {
544 if ((count - 1) % 5 != 0) {
545 fprintf(ofp, "\n\t\t");
546 count = 4;
547 }
548 fprintf(ofp, "flag_str(\"");
549 fprintf(ofp, "%s__%s\", ", event->system,
550 event->name);
551 fprintf(ofp, "\"%s\", %s)", f->name,
552 f->name);
553 } else if (f->flags & FIELD_IS_SYMBOLIC) {
554 if ((count - 1) % 5 != 0) {
555 fprintf(ofp, "\n\t\t");
556 count = 4;
557 }
558 fprintf(ofp, "symbol_str(\"");
559 fprintf(ofp, "%s__%s\", ", event->system,
560 event->name);
561 fprintf(ofp, "\"%s\", %s)", f->name,
562 f->name);
563 } else
564 fprintf(ofp, "%s", f->name);
565 }
566
567 fprintf(ofp, "),\n\n");
568 }
569
570 fprintf(ofp, "def trace_unhandled(event_name, context, "
571 "event_fields_dict):\n");
572
573 fprintf(ofp, "\t\tprint ' '.join(['%%s=%%s'%%(k,str(v))"
574 "for k,v in sorted(event_fields_dict.items())])\n\n");
575
576 fprintf(ofp, "def print_header("
577 "event_name, cpu, secs, nsecs, pid, comm):\n"
578 "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t"
579 "(event_name, cpu, secs, nsecs, pid, comm),\n");
580
581 fclose(ofp);
582
583 fprintf(stderr, "generated Python script: %s\n", fname);
584
585 return 0;
586}
587
588struct scripting_ops python_scripting_ops = {
589 .name = "Python",
590 .start_script = python_start_script,
591 .stop_script = python_stop_script,
592 .process_event = python_process_event,
593 .generate_script = python_generate_script,
594};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ce3a6c8abe76..313dac2d94ce 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,7 +1,11 @@
1#define _FILE_OFFSET_BITS 64
2
1#include <linux/kernel.h> 3#include <linux/kernel.h>
2 4
5#include <byteswap.h>
3#include <unistd.h> 6#include <unistd.h>
4#include <sys/types.h> 7#include <sys/types.h>
8#include <sys/mman.h>
5 9
6#include "session.h" 10#include "session.h"
7#include "sort.h" 11#include "sort.h"
@@ -11,10 +15,22 @@ static int perf_session__open(struct perf_session *self, bool force)
11{ 15{
12 struct stat input_stat; 16 struct stat input_stat;
13 17
18 if (!strcmp(self->filename, "-")) {
19 self->fd_pipe = true;
20 self->fd = STDIN_FILENO;
21
22 if (perf_header__read(self, self->fd) < 0)
23 pr_err("incompatible file format");
24
25 return 0;
26 }
27
14 self->fd = open(self->filename, O_RDONLY); 28 self->fd = open(self->filename, O_RDONLY);
15 if (self->fd < 0) { 29 if (self->fd < 0) {
16 pr_err("failed to open file: %s", self->filename); 30 int err = errno;
17 if (!strcmp(self->filename, "perf.data")) 31
32 pr_err("failed to open %s: %s", self->filename, strerror(err));
33 if (err == ENOENT && !strcmp(self->filename, "perf.data"))
18 pr_err(" (try 'perf record' first)"); 34 pr_err(" (try 'perf record' first)");
19 pr_err("\n"); 35 pr_err("\n");
20 return -errno; 36 return -errno;
@@ -35,7 +51,7 @@ static int perf_session__open(struct perf_session *self, bool force)
35 goto out_close; 51 goto out_close;
36 } 52 }
37 53
38 if (perf_header__read(&self->header, self->fd) < 0) { 54 if (perf_header__read(self, self->fd) < 0) {
39 pr_err("incompatible file format"); 55 pr_err("incompatible file format");
40 goto out_close; 56 goto out_close;
41 } 57 }
@@ -49,7 +65,69 @@ out_close:
49 return -1; 65 return -1;
50} 66}
51 67
52struct perf_session *perf_session__new(const char *filename, int mode, bool force) 68static void perf_session__id_header_size(struct perf_session *session)
69{
70 struct sample_data *data;
71 u64 sample_type = session->sample_type;
72 u16 size = 0;
73
74 if (!session->sample_id_all)
75 goto out;
76
77 if (sample_type & PERF_SAMPLE_TID)
78 size += sizeof(data->tid) * 2;
79
80 if (sample_type & PERF_SAMPLE_TIME)
81 size += sizeof(data->time);
82
83 if (sample_type & PERF_SAMPLE_ID)
84 size += sizeof(data->id);
85
86 if (sample_type & PERF_SAMPLE_STREAM_ID)
87 size += sizeof(data->stream_id);
88
89 if (sample_type & PERF_SAMPLE_CPU)
90 size += sizeof(data->cpu) * 2;
91out:
92 session->id_hdr_size = size;
93}
94
95void perf_session__set_sample_id_all(struct perf_session *session, bool value)
96{
97 session->sample_id_all = value;
98 perf_session__id_header_size(session);
99}
100
101void perf_session__set_sample_type(struct perf_session *session, u64 type)
102{
103 session->sample_type = type;
104}
105
106void perf_session__update_sample_type(struct perf_session *self)
107{
108 self->sample_type = perf_header__sample_type(&self->header);
109 self->sample_id_all = perf_header__sample_id_all(&self->header);
110 perf_session__id_header_size(self);
111}
112
113int perf_session__create_kernel_maps(struct perf_session *self)
114{
115 int ret = machine__create_kernel_maps(&self->host_machine);
116
117 if (ret >= 0)
118 ret = machines__create_guest_kernel_maps(&self->machines);
119 return ret;
120}
121
122static void perf_session__destroy_kernel_maps(struct perf_session *self)
123{
124 machine__destroy_kernel_maps(&self->host_machine);
125 machines__destroy_guest_kernel_maps(&self->machines);
126}
127
128struct perf_session *perf_session__new(const char *filename, int mode,
129 bool force, bool repipe,
130 struct perf_event_ops *ops)
53{ 131{
54 size_t len = filename ? strlen(filename) + 1 : 0; 132 size_t len = filename ? strlen(filename) + 1 : 0;
55 struct perf_session *self = zalloc(sizeof(*self) + len); 133 struct perf_session *self = zalloc(sizeof(*self) + len);
@@ -62,17 +140,45 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
62 140
63 memcpy(self->filename, filename, len); 141 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT; 142 self->threads = RB_ROOT;
143 INIT_LIST_HEAD(&self->dead_threads);
144 self->hists_tree = RB_ROOT;
65 self->last_match = NULL; 145 self->last_match = NULL;
66 self->mmap_window = 32; 146 /*
67 self->cwd = NULL; 147 * On 64bit we can mmap the data file in one go. No need for tiny mmap
68 self->cwdlen = 0; 148 * slices. On 32bit we use 32MB.
69 map_groups__init(&self->kmaps); 149 */
150#if BITS_PER_LONG == 64
151 self->mmap_window = ULLONG_MAX;
152#else
153 self->mmap_window = 32 * 1024 * 1024ULL;
154#endif
155 self->machines = RB_ROOT;
156 self->repipe = repipe;
157 INIT_LIST_HEAD(&self->ordered_samples.samples);
158 INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
159 INIT_LIST_HEAD(&self->ordered_samples.to_free);
160 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
70 161
71 if (perf_session__create_kernel_maps(self) < 0) 162 if (mode == O_RDONLY) {
72 goto out_delete; 163 if (perf_session__open(self, force) < 0)
164 goto out_delete;
165 } else if (mode == O_WRONLY) {
166 /*
167 * In O_RDONLY mode this will be performed when reading the
168 * kernel MMAP event, in event__process_mmap().
169 */
170 if (perf_session__create_kernel_maps(self) < 0)
171 goto out_delete;
172 }
173
174 perf_session__update_sample_type(self);
175
176 if (ops && ops->ordering_requires_timestamps &&
177 ops->ordered_samples && !self->sample_id_all) {
178 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
179 ops->ordered_samples = false;
180 }
73 181
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0)
75 goto out_delete;
76out: 182out:
77 return self; 183 return self;
78out_free: 184out_free:
@@ -83,14 +189,51 @@ out_delete:
83 return NULL; 189 return NULL;
84} 190}
85 191
192static void perf_session__delete_dead_threads(struct perf_session *self)
193{
194 struct thread *n, *t;
195
196 list_for_each_entry_safe(t, n, &self->dead_threads, node) {
197 list_del(&t->node);
198 thread__delete(t);
199 }
200}
201
202static void perf_session__delete_threads(struct perf_session *self)
203{
204 struct rb_node *nd = rb_first(&self->threads);
205
206 while (nd) {
207 struct thread *t = rb_entry(nd, struct thread, rb_node);
208
209 rb_erase(&t->rb_node, &self->threads);
210 nd = rb_next(nd);
211 thread__delete(t);
212 }
213}
214
86void perf_session__delete(struct perf_session *self) 215void perf_session__delete(struct perf_session *self)
87{ 216{
88 perf_header__exit(&self->header); 217 perf_header__exit(&self->header);
218 perf_session__destroy_kernel_maps(self);
219 perf_session__delete_dead_threads(self);
220 perf_session__delete_threads(self);
221 machine__exit(&self->host_machine);
89 close(self->fd); 222 close(self->fd);
90 free(self->cwd);
91 free(self); 223 free(self);
92} 224}
93 225
226void perf_session__remove_thread(struct perf_session *self, struct thread *th)
227{
228 self->last_match = NULL;
229 rb_erase(&th->rb_node, &self->threads);
230 /*
231 * We may have references to this thread, for instance in some hist_entry
232 * instances, so just move them to a separate list.
233 */
234 list_add_tail(&th->node, &self->dead_threads);
235}
236
94static bool symbol__match_parent_regex(struct symbol *sym) 237static bool symbol__match_parent_regex(struct symbol *sym)
95{ 238{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 239 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -99,22 +242,17 @@ static bool symbol__match_parent_regex(struct symbol *sym)
99 return 0; 242 return 0;
100} 243}
101 244
102struct symbol **perf_session__resolve_callchain(struct perf_session *self, 245struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread, 246 struct thread *thread,
104 struct ip_callchain *chain, 247 struct ip_callchain *chain,
105 struct symbol **parent) 248 struct symbol **parent)
106{ 249{
107 u8 cpumode = PERF_RECORD_MISC_USER; 250 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i; 251 unsigned int i;
252 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms));
110 253
111 if (symbol_conf.use_callchain) { 254 if (!syms)
112 syms = calloc(chain->nr, sizeof(*syms)); 255 return NULL;
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118 256
119 for (i = 0; i < chain->nr; i++) { 257 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i]; 258 u64 ip = chain->ips[i];
@@ -134,17 +272,863 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
134 continue; 272 continue;
135 } 273 }
136 274
275 al.filtered = false;
137 thread__find_addr_location(thread, self, cpumode, 276 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL); 277 MAP__FUNCTION, thread->pid, ip, &al, NULL);
139 if (al.sym != NULL) { 278 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent && 279 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym)) 280 symbol__match_parent_regex(al.sym))
142 *parent = al.sym; 281 *parent = al.sym;
143 if (!symbol_conf.use_callchain) 282 if (!symbol_conf.use_callchain)
144 break; 283 break;
145 syms[i] = al.sym; 284 syms[i].map = al.map;
285 syms[i].sym = al.sym;
146 } 286 }
147 } 287 }
148 288
149 return syms; 289 return syms;
150} 290}
291
292static int process_event_synth_stub(event_t *event __used,
293 struct perf_session *session __used)
294{
295 dump_printf(": unhandled!\n");
296 return 0;
297}
298
299static int process_event_stub(event_t *event __used,
300 struct sample_data *sample __used,
301 struct perf_session *session __used)
302{
303 dump_printf(": unhandled!\n");
304 return 0;
305}
306
307static int process_finished_round_stub(event_t *event __used,
308 struct perf_session *session __used,
309 struct perf_event_ops *ops __used)
310{
311 dump_printf(": unhandled!\n");
312 return 0;
313}
314
315static int process_finished_round(event_t *event,
316 struct perf_session *session,
317 struct perf_event_ops *ops);
318
319static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
320{
321 if (handler->sample == NULL)
322 handler->sample = process_event_stub;
323 if (handler->mmap == NULL)
324 handler->mmap = process_event_stub;
325 if (handler->comm == NULL)
326 handler->comm = process_event_stub;
327 if (handler->fork == NULL)
328 handler->fork = process_event_stub;
329 if (handler->exit == NULL)
330 handler->exit = process_event_stub;
331 if (handler->lost == NULL)
332 handler->lost = event__process_lost;
333 if (handler->read == NULL)
334 handler->read = process_event_stub;
335 if (handler->throttle == NULL)
336 handler->throttle = process_event_stub;
337 if (handler->unthrottle == NULL)
338 handler->unthrottle = process_event_stub;
339 if (handler->attr == NULL)
340 handler->attr = process_event_synth_stub;
341 if (handler->event_type == NULL)
342 handler->event_type = process_event_synth_stub;
343 if (handler->tracing_data == NULL)
344 handler->tracing_data = process_event_synth_stub;
345 if (handler->build_id == NULL)
346 handler->build_id = process_event_synth_stub;
347 if (handler->finished_round == NULL) {
348 if (handler->ordered_samples)
349 handler->finished_round = process_finished_round;
350 else
351 handler->finished_round = process_finished_round_stub;
352 }
353}
354
355void mem_bswap_64(void *src, int byte_size)
356{
357 u64 *m = src;
358
359 while (byte_size > 0) {
360 *m = bswap_64(*m);
361 byte_size -= sizeof(u64);
362 ++m;
363 }
364}
365
366static void event__all64_swap(event_t *self)
367{
368 struct perf_event_header *hdr = &self->header;
369 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
370}
371
372static void event__comm_swap(event_t *self)
373{
374 self->comm.pid = bswap_32(self->comm.pid);
375 self->comm.tid = bswap_32(self->comm.tid);
376}
377
378static void event__mmap_swap(event_t *self)
379{
380 self->mmap.pid = bswap_32(self->mmap.pid);
381 self->mmap.tid = bswap_32(self->mmap.tid);
382 self->mmap.start = bswap_64(self->mmap.start);
383 self->mmap.len = bswap_64(self->mmap.len);
384 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
385}
386
387static void event__task_swap(event_t *self)
388{
389 self->fork.pid = bswap_32(self->fork.pid);
390 self->fork.tid = bswap_32(self->fork.tid);
391 self->fork.ppid = bswap_32(self->fork.ppid);
392 self->fork.ptid = bswap_32(self->fork.ptid);
393 self->fork.time = bswap_64(self->fork.time);
394}
395
396static void event__read_swap(event_t *self)
397{
398 self->read.pid = bswap_32(self->read.pid);
399 self->read.tid = bswap_32(self->read.tid);
400 self->read.value = bswap_64(self->read.value);
401 self->read.time_enabled = bswap_64(self->read.time_enabled);
402 self->read.time_running = bswap_64(self->read.time_running);
403 self->read.id = bswap_64(self->read.id);
404}
405
406static void event__attr_swap(event_t *self)
407{
408 size_t size;
409
410 self->attr.attr.type = bswap_32(self->attr.attr.type);
411 self->attr.attr.size = bswap_32(self->attr.attr.size);
412 self->attr.attr.config = bswap_64(self->attr.attr.config);
413 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period);
414 self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type);
415 self->attr.attr.read_format = bswap_64(self->attr.attr.read_format);
416 self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events);
417 self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type);
418 self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr);
419 self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len);
420
421 size = self->header.size;
422 size -= (void *)&self->attr.id - (void *)self;
423 mem_bswap_64(self->attr.id, size);
424}
425
426static void event__event_type_swap(event_t *self)
427{
428 self->event_type.event_type.event_id =
429 bswap_64(self->event_type.event_type.event_id);
430}
431
432static void event__tracing_data_swap(event_t *self)
433{
434 self->tracing_data.size = bswap_32(self->tracing_data.size);
435}
436
437typedef void (*event__swap_op)(event_t *self);
438
439static event__swap_op event__swap_ops[] = {
440 [PERF_RECORD_MMAP] = event__mmap_swap,
441 [PERF_RECORD_COMM] = event__comm_swap,
442 [PERF_RECORD_FORK] = event__task_swap,
443 [PERF_RECORD_EXIT] = event__task_swap,
444 [PERF_RECORD_LOST] = event__all64_swap,
445 [PERF_RECORD_READ] = event__read_swap,
446 [PERF_RECORD_SAMPLE] = event__all64_swap,
447 [PERF_RECORD_HEADER_ATTR] = event__attr_swap,
448 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap,
449 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap,
450 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
451 [PERF_RECORD_HEADER_MAX] = NULL,
452};
453
454struct sample_queue {
455 u64 timestamp;
456 u64 file_offset;
457 event_t *event;
458 struct list_head list;
459};
460
461static void perf_session_free_sample_buffers(struct perf_session *session)
462{
463 struct ordered_samples *os = &session->ordered_samples;
464
465 while (!list_empty(&os->to_free)) {
466 struct sample_queue *sq;
467
468 sq = list_entry(os->to_free.next, struct sample_queue, list);
469 list_del(&sq->list);
470 free(sq);
471 }
472}
473
474static int perf_session_deliver_event(struct perf_session *session,
475 event_t *event,
476 struct sample_data *sample,
477 struct perf_event_ops *ops,
478 u64 file_offset);
479
480static void flush_sample_queue(struct perf_session *s,
481 struct perf_event_ops *ops)
482{
483 struct ordered_samples *os = &s->ordered_samples;
484 struct list_head *head = &os->samples;
485 struct sample_queue *tmp, *iter;
486 struct sample_data sample;
487 u64 limit = os->next_flush;
488 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
489
490 if (!ops->ordered_samples || !limit)
491 return;
492
493 list_for_each_entry_safe(iter, tmp, head, list) {
494 if (iter->timestamp > limit)
495 break;
496
497 event__parse_sample(iter->event, s, &sample);
498 perf_session_deliver_event(s, iter->event, &sample, ops,
499 iter->file_offset);
500
501 os->last_flush = iter->timestamp;
502 list_del(&iter->list);
503 list_add(&iter->list, &os->sample_cache);
504 }
505
506 if (list_empty(head)) {
507 os->last_sample = NULL;
508 } else if (last_ts <= limit) {
509 os->last_sample =
510 list_entry(head->prev, struct sample_queue, list);
511 }
512}
513
514/*
515 * When perf record finishes a pass on every buffers, it records this pseudo
516 * event.
517 * We record the max timestamp t found in the pass n.
518 * Assuming these timestamps are monotonic across cpus, we know that if
519 * a buffer still has events with timestamps below t, they will be all
520 * available and then read in the pass n + 1.
521 * Hence when we start to read the pass n + 2, we can safely flush every
522 * events with timestamps below t.
523 *
524 * ============ PASS n =================
525 * CPU 0 | CPU 1
526 * |
527 * cnt1 timestamps | cnt2 timestamps
528 * 1 | 2
529 * 2 | 3
530 * - | 4 <--- max recorded
531 *
532 * ============ PASS n + 1 ==============
533 * CPU 0 | CPU 1
534 * |
535 * cnt1 timestamps | cnt2 timestamps
536 * 3 | 5
537 * 4 | 6
538 * 5 | 7 <---- max recorded
539 *
540 * Flush every events below timestamp 4
541 *
542 * ============ PASS n + 2 ==============
543 * CPU 0 | CPU 1
544 * |
545 * cnt1 timestamps | cnt2 timestamps
546 * 6 | 8
547 * 7 | 9
548 * - | 10
549 *
550 * Flush every events below timestamp 7
551 * etc...
552 */
553static int process_finished_round(event_t *event __used,
554 struct perf_session *session,
555 struct perf_event_ops *ops)
556{
557 flush_sample_queue(session, ops);
558 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
559
560 return 0;
561}
562
563/* The queue is ordered by time */
564static void __queue_event(struct sample_queue *new, struct perf_session *s)
565{
566 struct ordered_samples *os = &s->ordered_samples;
567 struct sample_queue *sample = os->last_sample;
568 u64 timestamp = new->timestamp;
569 struct list_head *p;
570
571 os->last_sample = new;
572
573 if (!sample) {
574 list_add(&new->list, &os->samples);
575 os->max_timestamp = timestamp;
576 return;
577 }
578
579 /*
580 * last_sample might point to some random place in the list as it's
581 * the last queued event. We expect that the new event is close to
582 * this.
583 */
584 if (sample->timestamp <= timestamp) {
585 while (sample->timestamp <= timestamp) {
586 p = sample->list.next;
587 if (p == &os->samples) {
588 list_add_tail(&new->list, &os->samples);
589 os->max_timestamp = timestamp;
590 return;
591 }
592 sample = list_entry(p, struct sample_queue, list);
593 }
594 list_add_tail(&new->list, &sample->list);
595 } else {
596 while (sample->timestamp > timestamp) {
597 p = sample->list.prev;
598 if (p == &os->samples) {
599 list_add(&new->list, &os->samples);
600 return;
601 }
602 sample = list_entry(p, struct sample_queue, list);
603 }
604 list_add(&new->list, &sample->list);
605 }
606}
607
608#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))
609
610static int perf_session_queue_event(struct perf_session *s, event_t *event,
611 struct sample_data *data, u64 file_offset)
612{
613 struct ordered_samples *os = &s->ordered_samples;
614 struct list_head *sc = &os->sample_cache;
615 u64 timestamp = data->time;
616 struct sample_queue *new;
617
618 if (!timestamp || timestamp == ~0ULL)
619 return -ETIME;
620
621 if (timestamp < s->ordered_samples.last_flush) {
622 printf("Warning: Timestamp below last timeslice flush\n");
623 return -EINVAL;
624 }
625
626 if (!list_empty(sc)) {
627 new = list_entry(sc->next, struct sample_queue, list);
628 list_del(&new->list);
629 } else if (os->sample_buffer) {
630 new = os->sample_buffer + os->sample_buffer_idx;
631 if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER)
632 os->sample_buffer = NULL;
633 } else {
634 os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new));
635 if (!os->sample_buffer)
636 return -ENOMEM;
637 list_add(&os->sample_buffer->list, &os->to_free);
638 os->sample_buffer_idx = 2;
639 new = os->sample_buffer + 1;
640 }
641
642 new->timestamp = timestamp;
643 new->file_offset = file_offset;
644 new->event = event;
645
646 __queue_event(new, s);
647
648 return 0;
649}
650
651static void callchain__printf(struct sample_data *sample)
652{
653 unsigned int i;
654
655 printf("... chain: nr:%Lu\n", sample->callchain->nr);
656
657 for (i = 0; i < sample->callchain->nr; i++)
658 printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]);
659}
660
661static void perf_session__print_tstamp(struct perf_session *session,
662 event_t *event,
663 struct sample_data *sample)
664{
665 if (event->header.type != PERF_RECORD_SAMPLE &&
666 !session->sample_id_all) {
667 fputs("-1 -1 ", stdout);
668 return;
669 }
670
671 if ((session->sample_type & PERF_SAMPLE_CPU))
672 printf("%u ", sample->cpu);
673
674 if (session->sample_type & PERF_SAMPLE_TIME)
675 printf("%Lu ", sample->time);
676}
677
678static void dump_event(struct perf_session *session, event_t *event,
679 u64 file_offset, struct sample_data *sample)
680{
681 if (!dump_trace)
682 return;
683
684 printf("\n%#Lx [%#x]: event: %d\n", file_offset, event->header.size,
685 event->header.type);
686
687 trace_event(event);
688
689 if (sample)
690 perf_session__print_tstamp(session, event, sample);
691
692 printf("%#Lx [%#x]: PERF_RECORD_%s", file_offset, event->header.size,
693 event__get_event_name(event->header.type));
694}
695
696static void dump_sample(struct perf_session *session, event_t *event,
697 struct sample_data *sample)
698{
699 if (!dump_trace)
700 return;
701
702 printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
703 sample->pid, sample->tid, sample->ip, sample->period);
704
705 if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
706 callchain__printf(sample);
707}
708
709static int perf_session_deliver_event(struct perf_session *session,
710 event_t *event,
711 struct sample_data *sample,
712 struct perf_event_ops *ops,
713 u64 file_offset)
714{
715 dump_event(session, event, file_offset, sample);
716
717 switch (event->header.type) {
718 case PERF_RECORD_SAMPLE:
719 dump_sample(session, event, sample);
720 return ops->sample(event, sample, session);
721 case PERF_RECORD_MMAP:
722 return ops->mmap(event, sample, session);
723 case PERF_RECORD_COMM:
724 return ops->comm(event, sample, session);
725 case PERF_RECORD_FORK:
726 return ops->fork(event, sample, session);
727 case PERF_RECORD_EXIT:
728 return ops->exit(event, sample, session);
729 case PERF_RECORD_LOST:
730 return ops->lost(event, sample, session);
731 case PERF_RECORD_READ:
732 return ops->read(event, sample, session);
733 case PERF_RECORD_THROTTLE:
734 return ops->throttle(event, sample, session);
735 case PERF_RECORD_UNTHROTTLE:
736 return ops->unthrottle(event, sample, session);
737 default:
738 ++session->hists.stats.nr_unknown_events;
739 return -1;
740 }
741}
742
743static int perf_session__preprocess_sample(struct perf_session *session,
744 event_t *event, struct sample_data *sample)
745{
746 if (event->header.type != PERF_RECORD_SAMPLE ||
747 !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
748 return 0;
749
750 if (!ip_callchain__valid(sample->callchain, event)) {
751 pr_debug("call-chain problem with event, skipping it.\n");
752 ++session->hists.stats.nr_invalid_chains;
753 session->hists.stats.total_invalid_chains += sample->period;
754 return -EINVAL;
755 }
756 return 0;
757}
758
759static int perf_session__process_user_event(struct perf_session *session, event_t *event,
760 struct perf_event_ops *ops, u64 file_offset)
761{
762 dump_event(session, event, file_offset, NULL);
763
764 /* These events are processed right away */
765 switch (event->header.type) {
766 case PERF_RECORD_HEADER_ATTR:
767 return ops->attr(event, session);
768 case PERF_RECORD_HEADER_EVENT_TYPE:
769 return ops->event_type(event, session);
770 case PERF_RECORD_HEADER_TRACING_DATA:
771 /* setup for reading amidst mmap */
772 lseek(session->fd, file_offset, SEEK_SET);
773 return ops->tracing_data(event, session);
774 case PERF_RECORD_HEADER_BUILD_ID:
775 return ops->build_id(event, session);
776 case PERF_RECORD_FINISHED_ROUND:
777 return ops->finished_round(event, session, ops);
778 default:
779 return -EINVAL;
780 }
781}
782
783static int perf_session__process_event(struct perf_session *session,
784 event_t *event,
785 struct perf_event_ops *ops,
786 u64 file_offset)
787{
788 struct sample_data sample;
789 int ret;
790
791 if (session->header.needs_swap && event__swap_ops[event->header.type])
792 event__swap_ops[event->header.type](event);
793
794 if (event->header.type >= PERF_RECORD_HEADER_MAX)
795 return -EINVAL;
796
797 hists__inc_nr_events(&session->hists, event->header.type);
798
799 if (event->header.type >= PERF_RECORD_USER_TYPE_START)
800 return perf_session__process_user_event(session, event, ops, file_offset);
801
802 /*
803 * For all kernel events we get the sample data
804 */
805 event__parse_sample(event, session, &sample);
806
807 /* Preprocess sample records - precheck callchains */
808 if (perf_session__preprocess_sample(session, event, &sample))
809 return 0;
810
811 if (ops->ordered_samples) {
812 ret = perf_session_queue_event(session, event, &sample,
813 file_offset);
814 if (ret != -ETIME)
815 return ret;
816 }
817
818 return perf_session_deliver_event(session, event, &sample, ops,
819 file_offset);
820}
821
822void perf_event_header__bswap(struct perf_event_header *self)
823{
824 self->type = bswap_32(self->type);
825 self->misc = bswap_16(self->misc);
826 self->size = bswap_16(self->size);
827}
828
829static struct thread *perf_session__register_idle_thread(struct perf_session *self)
830{
831 struct thread *thread = perf_session__findnew(self, 0);
832
833 if (thread == NULL || thread__set_comm(thread, "swapper")) {
834 pr_err("problem inserting idle task.\n");
835 thread = NULL;
836 }
837
838 return thread;
839}
840
841static void perf_session__warn_about_errors(const struct perf_session *session,
842 const struct perf_event_ops *ops)
843{
844 if (ops->lost == event__process_lost &&
845 session->hists.stats.total_lost != 0) {
846 ui__warning("Processed %Lu events and LOST %Lu!\n\n"
847 "Check IO/CPU overload!\n\n",
848 session->hists.stats.total_period,
849 session->hists.stats.total_lost);
850 }
851
852 if (session->hists.stats.nr_unknown_events != 0) {
853 ui__warning("Found %u unknown events!\n\n"
854 "Is this an older tool processing a perf.data "
855 "file generated by a more recent tool?\n\n"
856 "If that is not the case, consider "
857 "reporting to linux-kernel@vger.kernel.org.\n\n",
858 session->hists.stats.nr_unknown_events);
859 }
860
861 if (session->hists.stats.nr_invalid_chains != 0) {
862 ui__warning("Found invalid callchains!\n\n"
863 "%u out of %u events were discarded for this reason.\n\n"
864 "Consider reporting to linux-kernel@vger.kernel.org.\n\n",
865 session->hists.stats.nr_invalid_chains,
866 session->hists.stats.nr_events[PERF_RECORD_SAMPLE]);
867 }
868}
869
870#define session_done() (*(volatile int *)(&session_done))
871volatile int session_done;
872
873static int __perf_session__process_pipe_events(struct perf_session *self,
874 struct perf_event_ops *ops)
875{
876 event_t event;
877 uint32_t size;
878 int skip = 0;
879 u64 head;
880 int err;
881 void *p;
882
883 perf_event_ops__fill_defaults(ops);
884
885 head = 0;
886more:
887 err = readn(self->fd, &event, sizeof(struct perf_event_header));
888 if (err <= 0) {
889 if (err == 0)
890 goto done;
891
892 pr_err("failed to read event header\n");
893 goto out_err;
894 }
895
896 if (self->header.needs_swap)
897 perf_event_header__bswap(&event.header);
898
899 size = event.header.size;
900 if (size == 0)
901 size = 8;
902
903 p = &event;
904 p += sizeof(struct perf_event_header);
905
906 if (size - sizeof(struct perf_event_header)) {
907 err = readn(self->fd, p, size - sizeof(struct perf_event_header));
908 if (err <= 0) {
909 if (err == 0) {
910 pr_err("unexpected end of event stream\n");
911 goto done;
912 }
913
914 pr_err("failed to read event data\n");
915 goto out_err;
916 }
917 }
918
919 if (size == 0 ||
920 (skip = perf_session__process_event(self, &event, ops, head)) < 0) {
921 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
922 head, event.header.size, event.header.type);
923 /*
924 * assume we lost track of the stream, check alignment, and
925 * increment a single u64 in the hope to catch on again 'soon'.
926 */
927 if (unlikely(head & 7))
928 head &= ~7ULL;
929
930 size = 8;
931 }
932
933 head += size;
934
935 if (skip > 0)
936 head += skip;
937
938 if (!session_done())
939 goto more;
940done:
941 err = 0;
942out_err:
943 perf_session__warn_about_errors(self, ops);
944 perf_session_free_sample_buffers(self);
945 return err;
946}
947
948int __perf_session__process_events(struct perf_session *session,
949 u64 data_offset, u64 data_size,
950 u64 file_size, struct perf_event_ops *ops)
951{
952 u64 head, page_offset, file_offset, file_pos, progress_next;
953 int err, mmap_prot, mmap_flags, map_idx = 0;
954 struct ui_progress *progress;
955 size_t page_size, mmap_size;
956 char *buf, *mmaps[8];
957 event_t *event;
958 uint32_t size;
959
960 perf_event_ops__fill_defaults(ops);
961
962 page_size = sysconf(_SC_PAGESIZE);
963
964 page_offset = page_size * (data_offset / page_size);
965 file_offset = page_offset;
966 head = data_offset - page_offset;
967
968 if (data_offset + data_size < file_size)
969 file_size = data_offset + data_size;
970
971 progress_next = file_size / 16;
972 progress = ui_progress__new("Processing events...", file_size);
973 if (progress == NULL)
974 return -1;
975
976 mmap_size = session->mmap_window;
977 if (mmap_size > file_size)
978 mmap_size = file_size;
979
980 memset(mmaps, 0, sizeof(mmaps));
981
982 mmap_prot = PROT_READ;
983 mmap_flags = MAP_SHARED;
984
985 if (session->header.needs_swap) {
986 mmap_prot |= PROT_WRITE;
987 mmap_flags = MAP_PRIVATE;
988 }
989remap:
990 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd,
991 file_offset);
992 if (buf == MAP_FAILED) {
993 pr_err("failed to mmap file\n");
994 err = -errno;
995 goto out_err;
996 }
997 mmaps[map_idx] = buf;
998 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
999 file_pos = file_offset + head;
1000
1001more:
1002 event = (event_t *)(buf + head);
1003
1004 if (session->header.needs_swap)
1005 perf_event_header__bswap(&event->header);
1006 size = event->header.size;
1007 if (size == 0)
1008 size = 8;
1009
1010 if (head + event->header.size > mmap_size) {
1011 if (mmaps[map_idx]) {
1012 munmap(mmaps[map_idx], mmap_size);
1013 mmaps[map_idx] = NULL;
1014 }
1015
1016 page_offset = page_size * (head / page_size);
1017 file_offset += page_offset;
1018 head -= page_offset;
1019 goto remap;
1020 }
1021
1022 size = event->header.size;
1023
1024 if (size == 0 ||
1025 perf_session__process_event(session, event, ops, file_pos) < 0) {
1026 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
1027 file_offset + head, event->header.size,
1028 event->header.type);
1029 /*
1030 * assume we lost track of the stream, check alignment, and
1031 * increment a single u64 in the hope to catch on again 'soon'.
1032 */
1033 if (unlikely(head & 7))
1034 head &= ~7ULL;
1035
1036 size = 8;
1037 }
1038
1039 head += size;
1040 file_pos += size;
1041
1042 if (file_pos >= progress_next) {
1043 progress_next += file_size / 16;
1044 ui_progress__update(progress, file_pos);
1045 }
1046
1047 if (file_pos < file_size)
1048 goto more;
1049
1050 err = 0;
1051 /* do the final flush for ordered samples */
1052 session->ordered_samples.next_flush = ULLONG_MAX;
1053 flush_sample_queue(session, ops);
1054out_err:
1055 ui_progress__delete(progress);
1056 perf_session__warn_about_errors(session, ops);
1057 perf_session_free_sample_buffers(session);
1058 return err;
1059}
1060
1061int perf_session__process_events(struct perf_session *self,
1062 struct perf_event_ops *ops)
1063{
1064 int err;
1065
1066 if (perf_session__register_idle_thread(self) == NULL)
1067 return -ENOMEM;
1068
1069 if (!self->fd_pipe)
1070 err = __perf_session__process_events(self,
1071 self->header.data_offset,
1072 self->header.data_size,
1073 self->size, ops);
1074 else
1075 err = __perf_session__process_pipe_events(self, ops);
1076
1077 return err;
1078}
1079
1080bool perf_session__has_traces(struct perf_session *self, const char *msg)
1081{
1082 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
1083 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
1084 return false;
1085 }
1086
1087 return true;
1088}
1089
1090int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
1091 const char *symbol_name,
1092 u64 addr)
1093{
1094 char *bracket;
1095 enum map_type i;
1096 struct ref_reloc_sym *ref;
1097
1098 ref = zalloc(sizeof(struct ref_reloc_sym));
1099 if (ref == NULL)
1100 return -ENOMEM;
1101
1102 ref->name = strdup(symbol_name);
1103 if (ref->name == NULL) {
1104 free(ref);
1105 return -ENOMEM;
1106 }
1107
1108 bracket = strchr(ref->name, ']');
1109 if (bracket)
1110 *bracket = '\0';
1111
1112 ref->addr = addr;
1113
1114 for (i = 0; i < MAP__NR_TYPES; ++i) {
1115 struct kmap *kmap = map__kmap(maps[i]);
1116 kmap->ref_reloc_sym = ref;
1117 }
1118
1119 return 0;
1120}
1121
1122size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
1123{
1124 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) +
1125 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
1126 machines__fprintf_dsos(&self->machines, fp);
1127}
1128
1129size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
1130 bool with_hits)
1131{
1132 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
1133 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
1134}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 32eaa1bada06..decd83f274fd 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -1,61 +1,157 @@
1#ifndef __PERF_SESSION_H 1#ifndef __PERF_SESSION_H
2#define __PERF_SESSION_H 2#define __PERF_SESSION_H
3 3
4#include "hist.h"
4#include "event.h" 5#include "event.h"
5#include "header.h" 6#include "header.h"
7#include "symbol.h"
6#include "thread.h" 8#include "thread.h"
7#include <linux/rbtree.h> 9#include <linux/rbtree.h>
8#include "../../../include/linux/perf_event.h" 10#include "../../../include/linux/perf_event.h"
9 11
12struct sample_queue;
10struct ip_callchain; 13struct ip_callchain;
11struct thread; 14struct thread;
12struct symbol; 15
16struct ordered_samples {
17 u64 last_flush;
18 u64 next_flush;
19 u64 max_timestamp;
20 struct list_head samples;
21 struct list_head sample_cache;
22 struct list_head to_free;
23 struct sample_queue *sample_buffer;
24 struct sample_queue *last_sample;
25 int sample_buffer_idx;
26};
13 27
14struct perf_session { 28struct perf_session {
15 struct perf_header header; 29 struct perf_header header;
16 unsigned long size; 30 unsigned long size;
17 unsigned long mmap_window; 31 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads; 32 struct rb_root threads;
33 struct list_head dead_threads;
20 struct thread *last_match; 34 struct thread *last_match;
21 struct events_stats events_stats; 35 struct machine host_machine;
22 unsigned long event_total[PERF_RECORD_MAX]; 36 struct rb_root machines;
23 struct rb_root hists; 37 struct rb_root hists_tree;
38 /*
39 * FIXME: should point to the first entry in hists_tree and
40 * be a hists instance. Right now its only 'report'
41 * that is using ->hists_tree while all the rest use
42 * ->hists.
43 */
44 struct hists hists;
24 u64 sample_type; 45 u64 sample_type;
25 int fd; 46 int fd;
47 bool fd_pipe;
48 bool repipe;
49 bool sample_id_all;
50 u16 id_hdr_size;
26 int cwdlen; 51 int cwdlen;
27 char *cwd; 52 char *cwd;
53 struct ordered_samples ordered_samples;
28 char filename[0]; 54 char filename[0];
29}; 55};
30 56
31typedef int (*event_op)(event_t *self, struct perf_session *session); 57struct perf_event_ops;
58
59typedef int (*event_op)(event_t *self, struct sample_data *sample,
60 struct perf_session *session);
61typedef int (*event_synth_op)(event_t *self, struct perf_session *session);
62typedef int (*event_op2)(event_t *self, struct perf_session *session,
63 struct perf_event_ops *ops);
32 64
33struct perf_event_ops { 65struct perf_event_ops {
34 event_op process_sample_event; 66 event_op sample,
35 event_op process_mmap_event; 67 mmap,
36 event_op process_comm_event; 68 comm,
37 event_op process_fork_event; 69 fork,
38 event_op process_exit_event; 70 exit,
39 event_op process_lost_event; 71 lost,
40 event_op process_read_event; 72 read,
41 event_op process_throttle_event; 73 throttle,
42 event_op process_unthrottle_event; 74 unthrottle;
43 int (*sample_type_check)(struct perf_session *session); 75 event_synth_op attr,
44 unsigned long total_unknown; 76 event_type,
45 bool full_paths; 77 tracing_data,
78 build_id;
79 event_op2 finished_round;
80 bool ordered_samples;
81 bool ordering_requires_timestamps;
46}; 82};
47 83
48struct perf_session *perf_session__new(const char *filename, int mode, bool force); 84struct perf_session *perf_session__new(const char *filename, int mode,
85 bool force, bool repipe,
86 struct perf_event_ops *ops);
49void perf_session__delete(struct perf_session *self); 87void perf_session__delete(struct perf_session *self);
50 88
89void perf_event_header__bswap(struct perf_event_header *self);
90
91int __perf_session__process_events(struct perf_session *self,
92 u64 data_offset, u64 data_size, u64 size,
93 struct perf_event_ops *ops);
51int perf_session__process_events(struct perf_session *self, 94int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops); 95 struct perf_event_ops *event_ops);
53 96
54struct symbol **perf_session__resolve_callchain(struct perf_session *self, 97struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread, 98 struct thread *thread,
56 struct ip_callchain *chain, 99 struct ip_callchain *chain,
57 struct symbol **parent); 100 struct symbol **parent);
101
102bool perf_session__has_traces(struct perf_session *self, const char *msg);
103
104int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
105 const char *symbol_name,
106 u64 addr);
107
108void mem_bswap_64(void *src, int byte_size);
109
110int perf_session__create_kernel_maps(struct perf_session *self);
111
112void perf_session__update_sample_type(struct perf_session *self);
113void perf_session__set_sample_id_all(struct perf_session *session, bool value);
114void perf_session__set_sample_type(struct perf_session *session, u64 type);
115void perf_session__remove_thread(struct perf_session *self, struct thread *th);
116
117static inline
118struct machine *perf_session__find_host_machine(struct perf_session *self)
119{
120 return &self->host_machine;
121}
122
123static inline
124struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
125{
126 if (pid == HOST_KERNEL_ID)
127 return &self->host_machine;
128 return machines__find(&self->machines, pid);
129}
130
131static inline
132struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
133{
134 if (pid == HOST_KERNEL_ID)
135 return &self->host_machine;
136 return machines__findnew(&self->machines, pid);
137}
138
139static inline
140void perf_session__process_machines(struct perf_session *self,
141 machine__process_t process)
142{
143 process(&self->host_machine, self);
144 return machines__process(&self->machines, process, self);
145}
146
147size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
58 148
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 149size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
150 FILE *fp, bool with_hits);
60 151
152static inline
153size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp)
154{
155 return hists__fprintf_nr_events(&self->hists, fp);
156}
61#endif /* __PERF_SESSION_H */ 157#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sigchain.c b/tools/perf/util/sigchain.c
index 1118b99e57d3..ba785e9b1841 100644
--- a/tools/perf/util/sigchain.c
+++ b/tools/perf/util/sigchain.c
@@ -16,7 +16,7 @@ static void check_signum(int sig)
16 die("BUG: signal out of range: %d", sig); 16 die("BUG: signal out of range: %d", sig);
17} 17}
18 18
19int sigchain_push(int sig, sigchain_fun f) 19static int sigchain_push(int sig, sigchain_fun f)
20{ 20{
21 struct sigchain_signal *s = signals + sig; 21 struct sigchain_signal *s = signals + sig;
22 check_signum(sig); 22 check_signum(sig);
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
index 1a53c11265fd..959d64eb5557 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/perf/util/sigchain.h
@@ -3,7 +3,6 @@
3 3
4typedef void (*sigchain_fun)(int); 4typedef void (*sigchain_fun)(int);
5 5
6int sigchain_push(int sig, sigchain_fun f);
7int sigchain_pop(int sig); 6int sigchain_pop(int sig);
8 7
9void sigchain_push_common(sigchain_fun f); 8void sigchain_push_common(sigchain_fun f);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index cb0f327de9e8..f44fa541d56e 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,56 +1,74 @@
1#include "sort.h" 1#include "sort.h"
2#include "hist.h"
2 3
3regex_t parent_regex; 4regex_t parent_regex;
4char default_parent_pattern[] = "^sys_|^do_page_fault"; 5const char default_parent_pattern[] = "^sys_|^do_page_fault";
5char *parent_pattern = default_parent_pattern; 6const char *parent_pattern = default_parent_pattern;
6char default_sort_order[] = "comm,dso,symbol"; 7const char default_sort_order[] = "comm,dso,symbol";
7char *sort_order = default_sort_order; 8const char *sort_order = default_sort_order;
8int sort__need_collapse = 0; 9int sort__need_collapse = 0;
9int sort__has_parent = 0; 10int sort__has_parent = 0;
10 11
11enum sort_type sort__first_dimension; 12enum sort_type sort__first_dimension;
12 13
13unsigned int dsos__col_width;
14unsigned int comms__col_width;
15unsigned int threads__col_width;
16static unsigned int parent_symbol__col_width;
17char * field_sep; 14char * field_sep;
18 15
19LIST_HEAD(hist_entry__sort_list); 16LIST_HEAD(hist_entry__sort_list);
20 17
18static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
19 size_t size, unsigned int width);
20static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
21 size_t size, unsigned int width);
22static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
23 size_t size, unsigned int width);
24static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
25 size_t size, unsigned int width);
26static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
27 size_t size, unsigned int width);
28static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
29 size_t size, unsigned int width);
30
21struct sort_entry sort_thread = { 31struct sort_entry sort_thread = {
22 .header = "Command: Pid", 32 .se_header = "Command: Pid",
23 .cmp = sort__thread_cmp, 33 .se_cmp = sort__thread_cmp,
24 .print = sort__thread_print, 34 .se_snprintf = hist_entry__thread_snprintf,
25 .width = &threads__col_width, 35 .se_width_idx = HISTC_THREAD,
26}; 36};
27 37
28struct sort_entry sort_comm = { 38struct sort_entry sort_comm = {
29 .header = "Command", 39 .se_header = "Command",
30 .cmp = sort__comm_cmp, 40 .se_cmp = sort__comm_cmp,
31 .collapse = sort__comm_collapse, 41 .se_collapse = sort__comm_collapse,
32 .print = sort__comm_print, 42 .se_snprintf = hist_entry__comm_snprintf,
33 .width = &comms__col_width, 43 .se_width_idx = HISTC_COMM,
34}; 44};
35 45
36struct sort_entry sort_dso = { 46struct sort_entry sort_dso = {
37 .header = "Shared Object", 47 .se_header = "Shared Object",
38 .cmp = sort__dso_cmp, 48 .se_cmp = sort__dso_cmp,
39 .print = sort__dso_print, 49 .se_snprintf = hist_entry__dso_snprintf,
40 .width = &dsos__col_width, 50 .se_width_idx = HISTC_DSO,
41}; 51};
42 52
43struct sort_entry sort_sym = { 53struct sort_entry sort_sym = {
44 .header = "Symbol", 54 .se_header = "Symbol",
45 .cmp = sort__sym_cmp, 55 .se_cmp = sort__sym_cmp,
46 .print = sort__sym_print, 56 .se_snprintf = hist_entry__sym_snprintf,
57 .se_width_idx = HISTC_SYMBOL,
47}; 58};
48 59
49struct sort_entry sort_parent = { 60struct sort_entry sort_parent = {
50 .header = "Parent symbol", 61 .se_header = "Parent symbol",
51 .cmp = sort__parent_cmp, 62 .se_cmp = sort__parent_cmp,
52 .print = sort__parent_print, 63 .se_snprintf = hist_entry__parent_snprintf,
53 .width = &parent_symbol__col_width, 64 .se_width_idx = HISTC_PARENT,
65};
66
67struct sort_entry sort_cpu = {
68 .se_header = "CPU",
69 .se_cmp = sort__cpu_cmp,
70 .se_snprintf = hist_entry__cpu_snprintf,
71 .se_width_idx = HISTC_CPU,
54}; 72};
55 73
56struct sort_dimension { 74struct sort_dimension {
@@ -65,6 +83,7 @@ static struct sort_dimension sort_dimensions[] = {
65 { .name = "dso", .entry = &sort_dso, }, 83 { .name = "dso", .entry = &sort_dso, },
66 { .name = "symbol", .entry = &sort_sym, }, 84 { .name = "symbol", .entry = &sort_sym, },
67 { .name = "parent", .entry = &sort_parent, }, 85 { .name = "parent", .entry = &sort_parent, },
86 { .name = "cpu", .entry = &sort_cpu, },
68}; 87};
69 88
70int64_t cmp_null(void *l, void *r) 89int64_t cmp_null(void *l, void *r)
@@ -85,45 +104,38 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
85 return right->thread->pid - left->thread->pid; 104 return right->thread->pid - left->thread->pid;
86} 105}
87 106
88int repsep_fprintf(FILE *fp, const char *fmt, ...) 107static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
89{ 108{
90 int n; 109 int n;
91 va_list ap; 110 va_list ap;
92 111
93 va_start(ap, fmt); 112 va_start(ap, fmt);
94 if (!field_sep) 113 n = vsnprintf(bf, size, fmt, ap);
95 n = vfprintf(fp, fmt, ap); 114 if (field_sep && n > 0) {
96 else { 115 char *sep = bf;
97 char *bf = NULL; 116
98 n = vasprintf(&bf, fmt, ap); 117 while (1) {
99 if (n > 0) { 118 sep = strchr(sep, *field_sep);
100 char *sep = bf; 119 if (sep == NULL)
101 120 break;
102 while (1) { 121 *sep = '.';
103 sep = strchr(sep, *field_sep);
104 if (sep == NULL)
105 break;
106 *sep = '.';
107 }
108 } 122 }
109 fputs(bf, fp);
110 free(bf);
111 } 123 }
112 va_end(ap); 124 va_end(ap);
113 return n; 125 return n;
114} 126}
115 127
116size_t 128static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
117sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width) 129 size_t size, unsigned int width)
118{ 130{
119 return repsep_fprintf(fp, "%*s:%5d", width - 6, 131 return repsep_snprintf(bf, size, "%*s:%5d", width,
120 self->thread->comm ?: "", self->thread->pid); 132 self->thread->comm ?: "", self->thread->pid);
121} 133}
122 134
123size_t 135static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
124sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width) 136 size_t size, unsigned int width)
125{ 137{
126 return repsep_fprintf(fp, "%*s", width, self->thread->comm); 138 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
127} 139}
128 140
129/* --sort dso */ 141/* --sort dso */
@@ -131,8 +143,8 @@ sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
131int64_t 143int64_t
132sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 144sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
133{ 145{
134 struct dso *dso_l = left->map ? left->map->dso : NULL; 146 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
135 struct dso *dso_r = right->map ? right->map->dso : NULL; 147 struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL;
136 const char *dso_name_l, *dso_name_r; 148 const char *dso_name_l, *dso_name_r;
137 149
138 if (!dso_l || !dso_r) 150 if (!dso_l || !dso_r)
@@ -149,16 +161,16 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
149 return strcmp(dso_name_l, dso_name_r); 161 return strcmp(dso_name_l, dso_name_r);
150} 162}
151 163
152size_t 164static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
153sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) 165 size_t size, unsigned int width)
154{ 166{
155 if (self->map && self->map->dso) { 167 if (self->ms.map && self->ms.map->dso) {
156 const char *dso_name = !verbose ? self->map->dso->short_name : 168 const char *dso_name = !verbose ? self->ms.map->dso->short_name :
157 self->map->dso->long_name; 169 self->ms.map->dso->long_name;
158 return repsep_fprintf(fp, "%-*s", width, dso_name); 170 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
159 } 171 }
160 172
161 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); 173 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
162} 174}
163 175
164/* --sort symbol */ 176/* --sort symbol */
@@ -168,31 +180,33 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
168{ 180{
169 u64 ip_l, ip_r; 181 u64 ip_l, ip_r;
170 182
171 if (left->sym == right->sym) 183 if (left->ms.sym == right->ms.sym)
172 return 0; 184 return 0;
173 185
174 ip_l = left->sym ? left->sym->start : left->ip; 186 ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
175 ip_r = right->sym ? right->sym->start : right->ip; 187 ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
176 188
177 return (int64_t)(ip_r - ip_l); 189 return (int64_t)(ip_r - ip_l);
178} 190}
179 191
180 192static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
181size_t 193 size_t size, unsigned int width __used)
182sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
183{ 194{
184 size_t ret = 0; 195 size_t ret = 0;
185 196
186 if (verbose) { 197 if (verbose) {
187 char o = self->map ? dso__symtab_origin(self->map->dso) : '!'; 198 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
188 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o); 199 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
200 BITS_PER_LONG / 4, self->ip, o);
189 } 201 }
190 202
191 ret += repsep_fprintf(fp, "[%c] ", self->level); 203 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
192 if (self->sym) 204 if (self->ms.sym)
193 ret += repsep_fprintf(fp, "%s", self->sym->name); 205 ret += repsep_snprintf(bf + ret, size - ret, "%s",
206 self->ms.sym->name);
194 else 207 else
195 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); 208 ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
209 BITS_PER_LONG / 4, self->ip);
196 210
197 return ret; 211 return ret;
198} 212}
@@ -231,13 +245,27 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
231 return strcmp(sym_l->name, sym_r->name); 245 return strcmp(sym_l->name, sym_r->name);
232} 246}
233 247
234size_t 248static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
235sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width) 249 size_t size, unsigned int width)
236{ 250{
237 return repsep_fprintf(fp, "%-*s", width, 251 return repsep_snprintf(bf, size, "%-*s", width,
238 self->parent ? self->parent->name : "[other]"); 252 self->parent ? self->parent->name : "[other]");
239} 253}
240 254
255/* --sort cpu */
256
257int64_t
258sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
259{
260 return right->cpu - left->cpu;
261}
262
263static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
264 size_t size, unsigned int width)
265{
266 return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
267}
268
241int sort_dimension__add(const char *tok) 269int sort_dimension__add(const char *tok)
242{ 270{
243 unsigned int i; 271 unsigned int i;
@@ -251,7 +279,7 @@ int sort_dimension__add(const char *tok)
251 if (strncasecmp(tok, sd->name, strlen(tok))) 279 if (strncasecmp(tok, sd->name, strlen(tok)))
252 continue; 280 continue;
253 281
254 if (sd->entry->collapse) 282 if (sd->entry->se_collapse)
255 sort__need_collapse = 1; 283 sort__need_collapse = 1;
256 284
257 if (sd->entry == &sort_parent) { 285 if (sd->entry == &sort_parent) {
@@ -260,9 +288,8 @@ int sort_dimension__add(const char *tok)
260 char err[BUFSIZ]; 288 char err[BUFSIZ];
261 289
262 regerror(ret, &parent_regex, err, sizeof(err)); 290 regerror(ret, &parent_regex, err, sizeof(err));
263 fprintf(stderr, "Invalid regex: %s\n%s", 291 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
264 parent_pattern, err); 292 return -EINVAL;
265 exit(-1);
266 } 293 }
267 sort__has_parent = 1; 294 sort__has_parent = 1;
268 } 295 }
@@ -278,6 +305,8 @@ int sort_dimension__add(const char *tok)
278 sort__first_dimension = SORT_SYM; 305 sort__first_dimension = SORT_SYM;
279 else if (!strcmp(sd->name, "parent")) 306 else if (!strcmp(sd->name, "parent"))
280 sort__first_dimension = SORT_PARENT; 307 sort__first_dimension = SORT_PARENT;
308 else if (!strcmp(sd->name, "cpu"))
309 sort__first_dimension = SORT_CPU;
281 } 310 }
282 311
283 list_add_tail(&sd->entry->list, &hist_entry__sort_list); 312 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 753f9ea99fb0..0b91053a7d11 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -25,10 +25,10 @@
25#include "sort.h" 25#include "sort.h"
26 26
27extern regex_t parent_regex; 27extern regex_t parent_regex;
28extern char *sort_order; 28extern const char *sort_order;
29extern char default_parent_pattern[]; 29extern const char default_parent_pattern[];
30extern char *parent_pattern; 30extern const char *parent_pattern;
31extern char default_sort_order[]; 31extern const char default_sort_order[];
32extern int sort__need_collapse; 32extern int sort__need_collapse;
33extern int sort__has_parent; 33extern int sort__has_parent;
34extern char *field_sep; 34extern char *field_sep;
@@ -36,26 +36,41 @@ extern struct sort_entry sort_comm;
36extern struct sort_entry sort_dso; 36extern struct sort_entry sort_dso;
37extern struct sort_entry sort_sym; 37extern struct sort_entry sort_sym;
38extern struct sort_entry sort_parent; 38extern struct sort_entry sort_parent;
39extern unsigned int dsos__col_width;
40extern unsigned int comms__col_width;
41extern unsigned int threads__col_width;
42extern enum sort_type sort__first_dimension; 39extern enum sort_type sort__first_dimension;
43 40
41/**
42 * struct hist_entry - histogram entry
43 *
44 * @row_offset - offset from the first callchain expanded to appear on screen
45 * @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
46 */
44struct hist_entry { 47struct hist_entry {
45 struct rb_node rb_node; 48 struct rb_node rb_node;
46 u64 count; 49 u64 period;
50 u64 period_sys;
51 u64 period_us;
52 u64 period_guest_sys;
53 u64 period_guest_us;
54 struct map_symbol ms;
47 struct thread *thread; 55 struct thread *thread;
48 struct map *map;
49 struct symbol *sym;
50 u64 ip; 56 u64 ip;
57 s32 cpu;
58 u32 nr_events;
59
60 /* XXX These two should move to some tree widget lib */
61 u16 row_offset;
62 u16 nr_rows;
63
64 bool init_have_children;
51 char level; 65 char level;
52 struct symbol *parent; 66 u8 filtered;
53 struct callchain_node callchain; 67 struct symbol *parent;
54 union { 68 union {
55 unsigned long position; 69 unsigned long position;
56 struct hist_entry *pair; 70 struct hist_entry *pair;
57 struct rb_root sorted_chain; 71 struct rb_root sorted_chain;
58 }; 72 };
73 struct callchain_root callchain[0];
59}; 74};
60 75
61enum sort_type { 76enum sort_type {
@@ -63,7 +78,8 @@ enum sort_type {
63 SORT_COMM, 78 SORT_COMM,
64 SORT_DSO, 79 SORT_DSO,
65 SORT_SYM, 80 SORT_SYM,
66 SORT_PARENT 81 SORT_PARENT,
82 SORT_CPU,
67}; 83};
68 84
69/* 85/*
@@ -73,12 +89,13 @@ enum sort_type {
73struct sort_entry { 89struct sort_entry {
74 struct list_head list; 90 struct list_head list;
75 91
76 const char *header; 92 const char *se_header;
77 93
78 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 94 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
79 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 95 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
80 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width); 96 int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size,
81 unsigned int *width; 97 unsigned int width);
98 u8 se_width_idx;
82 bool elide; 99 bool elide;
83}; 100};
84 101
@@ -87,7 +104,6 @@ extern struct list_head hist_entry__sort_list;
87 104
88void setup_sorting(const char * const usagestr[], const struct option *opts); 105void setup_sorting(const char * const usagestr[], const struct option *opts);
89 106
90extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
91extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); 107extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
92extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); 108extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
93extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int); 109extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int);
@@ -99,6 +115,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
99extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *); 115extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
100extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *); 116extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
101extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); 117extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
118int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
102extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); 119extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
103extern int sort_dimension__add(const char *); 120extern int sort_dimension__add(const char *);
104void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, 121void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 5249d5a1b0c2..92e068517c1a 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -41,16 +41,6 @@ char *strbuf_detach(struct strbuf *sb, size_t *sz)
41 return res; 41 return res;
42} 42}
43 43
44void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
45{
46 strbuf_release(sb);
47 sb->buf = buf;
48 sb->len = len;
49 sb->alloc = alloc;
50 strbuf_grow(sb, 0);
51 sb->buf[sb->len] = '\0';
52}
53
54void strbuf_grow(struct strbuf *sb, size_t extra) 44void strbuf_grow(struct strbuf *sb, size_t extra)
55{ 45{
56 if (sb->len + extra + 1 <= sb->len) 46 if (sb->len + extra + 1 <= sb->len)
@@ -60,94 +50,7 @@ void strbuf_grow(struct strbuf *sb, size_t extra)
60 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); 50 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
61} 51}
62 52
63void strbuf_trim(struct strbuf *sb) 53static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
64{
65 char *b = sb->buf;
66 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
67 sb->len--;
68 while (sb->len > 0 && isspace(*b)) {
69 b++;
70 sb->len--;
71 }
72 memmove(sb->buf, b, sb->len);
73 sb->buf[sb->len] = '\0';
74}
75void strbuf_rtrim(struct strbuf *sb)
76{
77 while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
78 sb->len--;
79 sb->buf[sb->len] = '\0';
80}
81
82void strbuf_ltrim(struct strbuf *sb)
83{
84 char *b = sb->buf;
85 while (sb->len > 0 && isspace(*b)) {
86 b++;
87 sb->len--;
88 }
89 memmove(sb->buf, b, sb->len);
90 sb->buf[sb->len] = '\0';
91}
92
93void strbuf_tolower(struct strbuf *sb)
94{
95 unsigned int i;
96
97 for (i = 0; i < sb->len; i++)
98 sb->buf[i] = tolower(sb->buf[i]);
99}
100
101struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
102{
103 int alloc = 2, pos = 0;
104 char *n, *p;
105 struct strbuf **ret;
106 struct strbuf *t;
107
108 ret = calloc(alloc, sizeof(struct strbuf *));
109 p = n = sb->buf;
110 while (n < sb->buf + sb->len) {
111 int len;
112 n = memchr(n, delim, sb->len - (n - sb->buf));
113 if (pos + 1 >= alloc) {
114 alloc = alloc * 2;
115 ret = realloc(ret, sizeof(struct strbuf *) * alloc);
116 }
117 if (!n)
118 n = sb->buf + sb->len - 1;
119 len = n - p + 1;
120 t = malloc(sizeof(struct strbuf));
121 strbuf_init(t, len);
122 strbuf_add(t, p, len);
123 ret[pos] = t;
124 ret[++pos] = NULL;
125 p = ++n;
126 }
127 return ret;
128}
129
130void strbuf_list_free(struct strbuf **sbs)
131{
132 struct strbuf **s = sbs;
133
134 while (*s) {
135 strbuf_release(*s);
136 free(*s++);
137 }
138 free(sbs);
139}
140
141int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
142{
143 int len = a->len < b->len ? a->len: b->len;
144 int cmp = memcmp(a->buf, b->buf, len);
145 if (cmp)
146 return cmp;
147 return a->len < b->len ? -1: a->len != b->len;
148}
149
150void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
151 const void *data, size_t dlen) 54 const void *data, size_t dlen)
152{ 55{
153 if (pos + len < pos) 56 if (pos + len < pos)
@@ -166,11 +69,6 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
166 strbuf_setlen(sb, sb->len + dlen - len); 69 strbuf_setlen(sb, sb->len + dlen - len);
167} 70}
168 71
169void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
170{
171 strbuf_splice(sb, pos, 0, data, len);
172}
173
174void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) 72void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
175{ 73{
176 strbuf_splice(sb, pos, len, NULL, 0); 74 strbuf_splice(sb, pos, len, NULL, 0);
@@ -183,13 +81,6 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len)
183 strbuf_setlen(sb, sb->len + len); 81 strbuf_setlen(sb, sb->len + len);
184} 82}
185 83
186void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
187{
188 strbuf_grow(sb, len);
189 memcpy(sb->buf + sb->len, sb->buf + pos, len);
190 strbuf_setlen(sb, sb->len + len);
191}
192
193void strbuf_addf(struct strbuf *sb, const char *fmt, ...) 84void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
194{ 85{
195 int len; 86 int len;
@@ -214,57 +105,6 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
214 strbuf_setlen(sb, sb->len + len); 105 strbuf_setlen(sb, sb->len + len);
215} 106}
216 107
217void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
218 void *context)
219{
220 for (;;) {
221 const char *percent;
222 size_t consumed;
223
224 percent = strchrnul(format, '%');
225 strbuf_add(sb, format, percent - format);
226 if (!*percent)
227 break;
228 format = percent + 1;
229
230 consumed = fn(sb, format, context);
231 if (consumed)
232 format += consumed;
233 else
234 strbuf_addch(sb, '%');
235 }
236}
237
238size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
239 void *context)
240{
241 struct strbuf_expand_dict_entry *e = context;
242 size_t len;
243
244 for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
245 if (!strncmp(placeholder, e->placeholder, len)) {
246 if (e->value)
247 strbuf_addstr(sb, e->value);
248 return len;
249 }
250 }
251 return 0;
252}
253
254size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
255{
256 size_t res;
257 size_t oldalloc = sb->alloc;
258
259 strbuf_grow(sb, size);
260 res = fread(sb->buf + sb->len, 1, size, f);
261 if (res > 0)
262 strbuf_setlen(sb, sb->len + res);
263 else if (oldalloc == 0)
264 strbuf_release(sb);
265 return res;
266}
267
268ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) 108ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
269{ 109{
270 size_t oldlen = sb->len; 110 size_t oldlen = sb->len;
@@ -291,70 +131,3 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
291 sb->buf[sb->len] = '\0'; 131 sb->buf[sb->len] = '\0';
292 return sb->len - oldlen; 132 return sb->len - oldlen;
293} 133}
294
295#define STRBUF_MAXLINK (2*PATH_MAX)
296
297int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint)
298{
299 size_t oldalloc = sb->alloc;
300
301 if (hint < 32)
302 hint = 32;
303
304 while (hint < STRBUF_MAXLINK) {
305 ssize_t len;
306
307 strbuf_grow(sb, hint);
308 len = readlink(path, sb->buf, hint);
309 if (len < 0) {
310 if (errno != ERANGE)
311 break;
312 } else if (len < hint) {
313 strbuf_setlen(sb, len);
314 return 0;
315 }
316
317 /* .. the buffer was too small - try again */
318 hint *= 2;
319 }
320 if (oldalloc == 0)
321 strbuf_release(sb);
322 return -1;
323}
324
325int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
326{
327 int ch;
328
329 strbuf_grow(sb, 0);
330 if (feof(fp))
331 return EOF;
332
333 strbuf_reset(sb);
334 while ((ch = fgetc(fp)) != EOF) {
335 if (ch == term)
336 break;
337 strbuf_grow(sb, 1);
338 sb->buf[sb->len++] = ch;
339 }
340 if (ch == EOF && sb->len == 0)
341 return EOF;
342
343 sb->buf[sb->len] = '\0';
344 return 0;
345}
346
347int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint)
348{
349 int fd, len;
350
351 fd = open(path, O_RDONLY);
352 if (fd < 0)
353 return -1;
354 len = strbuf_read(sb, fd, hint);
355 close(fd);
356 if (len < 0)
357 return -1;
358
359 return len;
360}
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index a3d121d6c83e..436ac319f6c7 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -53,12 +53,6 @@ struct strbuf {
53extern void strbuf_init(struct strbuf *buf, ssize_t hint); 53extern void strbuf_init(struct strbuf *buf, ssize_t hint);
54extern void strbuf_release(struct strbuf *); 54extern void strbuf_release(struct strbuf *);
55extern char *strbuf_detach(struct strbuf *, size_t *); 55extern char *strbuf_detach(struct strbuf *, size_t *);
56extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
57static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {
58 struct strbuf tmp = *a;
59 *a = *b;
60 *b = tmp;
61}
62 56
63/*----- strbuf size related -----*/ 57/*----- strbuf size related -----*/
64static inline ssize_t strbuf_avail(const struct strbuf *sb) { 58static inline ssize_t strbuf_avail(const struct strbuf *sb) {
@@ -74,17 +68,6 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
74 sb->len = len; 68 sb->len = len;
75 sb->buf[len] = '\0'; 69 sb->buf[len] = '\0';
76} 70}
77#define strbuf_reset(sb) strbuf_setlen(sb, 0)
78
79/*----- content related -----*/
80extern void strbuf_trim(struct strbuf *);
81extern void strbuf_rtrim(struct strbuf *);
82extern void strbuf_ltrim(struct strbuf *);
83extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
84extern void strbuf_tolower(struct strbuf *);
85
86extern struct strbuf **strbuf_split(const struct strbuf *, int delim);
87extern void strbuf_list_free(struct strbuf **);
88 71
89/*----- add data in your buffer -----*/ 72/*----- add data in your buffer -----*/
90static inline void strbuf_addch(struct strbuf *sb, int c) { 73static inline void strbuf_addch(struct strbuf *sb, int c) {
@@ -93,45 +76,17 @@ static inline void strbuf_addch(struct strbuf *sb, int c) {
93 sb->buf[sb->len] = '\0'; 76 sb->buf[sb->len] = '\0';
94} 77}
95 78
96extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
97extern void strbuf_remove(struct strbuf *, size_t pos, size_t len); 79extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
98 80
99/* splice pos..pos+len with given data */
100extern void strbuf_splice(struct strbuf *, size_t pos, size_t len,
101 const void *, size_t);
102
103extern void strbuf_add(struct strbuf *, const void *, size_t); 81extern void strbuf_add(struct strbuf *, const void *, size_t);
104static inline void strbuf_addstr(struct strbuf *sb, const char *s) { 82static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
105 strbuf_add(sb, s, strlen(s)); 83 strbuf_add(sb, s, strlen(s));
106} 84}
107static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) {
108 strbuf_add(sb, sb2->buf, sb2->len);
109}
110extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
111
112typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
113extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
114struct strbuf_expand_dict_entry {
115 const char *placeholder;
116 const char *value;
117};
118extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
119 85
120__attribute__((format(printf,2,3))) 86__attribute__((format(printf,2,3)))
121extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); 87extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
122 88
123extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
124/* XXX: if read fails, any partial read is undone */ 89/* XXX: if read fails, any partial read is undone */
125extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); 90extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
126extern int strbuf_read_file(struct strbuf *sb, const char *path, ssize_t hint);
127extern int strbuf_readlink(struct strbuf *sb, const char *path, ssize_t hint);
128
129extern int strbuf_getline(struct strbuf *, FILE *, int);
130
131extern void stripspace(struct strbuf *buf, int skip_comments);
132extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
133
134extern int strbuf_branchname(struct strbuf *sb, const char *name);
135extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
136 91
137#endif /* __PERF_STRBUF_H */ 92#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 5352d7dccc61..8fc0bd3a3a4a 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,48 +1,5 @@
1#include "string.h"
2#include "util.h" 1#include "util.h"
3 2#include "string.h"
4static int hex(char ch)
5{
6 if ((ch >= '0') && (ch <= '9'))
7 return ch - '0';
8 if ((ch >= 'a') && (ch <= 'f'))
9 return ch - 'a' + 10;
10 if ((ch >= 'A') && (ch <= 'F'))
11 return ch - 'A' + 10;
12 return -1;
13}
14
15/*
16 * While we find nice hex chars, build a long_val.
17 * Return number of chars processed.
18 */
19int hex2u64(const char *ptr, u64 *long_val)
20{
21 const char *p = ptr;
22 *long_val = 0;
23
24 while (*p) {
25 const int hex_val = hex(*p);
26
27 if (hex_val < 0)
28 break;
29
30 *long_val = (*long_val << 4) | hex_val;
31 p++;
32 }
33
34 return p - ptr;
35}
36
37char *strxfrchar(char *s, char from, char to)
38{
39 char *p = s;
40
41 while ((p = strchr(p, from)) != NULL)
42 *p++ = to;
43
44 return s;
45}
46 3
47#define K 1024LL 4#define K 1024LL
48/* 5/*
@@ -227,16 +184,73 @@ fail:
227 return NULL; 184 return NULL;
228} 185}
229 186
230/* Glob expression pattern matching */ 187/* Character class matching */
231bool strglobmatch(const char *str, const char *pat) 188static bool __match_charclass(const char *pat, char c, const char **npat)
189{
190 bool complement = false, ret = true;
191
192 if (*pat == '!') {
193 complement = true;
194 pat++;
195 }
196 if (*pat++ == c) /* First character is special */
197 goto end;
198
199 while (*pat && *pat != ']') { /* Matching */
200 if (*pat == '-' && *(pat + 1) != ']') { /* Range */
201 if (*(pat - 1) <= c && c <= *(pat + 1))
202 goto end;
203 if (*(pat - 1) > *(pat + 1))
204 goto error;
205 pat += 2;
206 } else if (*pat++ == c)
207 goto end;
208 }
209 if (!*pat)
210 goto error;
211 ret = false;
212
213end:
214 while (*pat && *pat != ']') /* Searching closing */
215 pat++;
216 if (!*pat)
217 goto error;
218 *npat = pat + 1;
219 return complement ? !ret : ret;
220
221error:
222 return false;
223}
224
225/* Glob/lazy pattern matching */
226static bool __match_glob(const char *str, const char *pat, bool ignore_space)
232{ 227{
233 while (*str && *pat && *pat != '*') { 228 while (*str && *pat && *pat != '*') {
234 if (*pat == '?') { 229 if (ignore_space) {
230 /* Ignore spaces for lazy matching */
231 if (isspace(*str)) {
232 str++;
233 continue;
234 }
235 if (isspace(*pat)) {
236 pat++;
237 continue;
238 }
239 }
240 if (*pat == '?') { /* Matches any single character */
235 str++; 241 str++;
236 pat++; 242 pat++;
237 } else 243 continue;
238 if (*str++ != *pat++) 244 } else if (*pat == '[') /* Character classes/Ranges */
245 if (__match_charclass(pat + 1, *str, &pat)) {
246 str++;
247 continue;
248 } else
239 return false; 249 return false;
250 else if (*pat == '\\') /* Escaped char match as normal char */
251 pat++;
252 if (*str++ != *pat++)
253 return false;
240 } 254 }
241 /* Check wild card */ 255 /* Check wild card */
242 if (*pat == '*') { 256 if (*pat == '*') {
@@ -245,9 +259,38 @@ bool strglobmatch(const char *str, const char *pat)
245 if (!*pat) /* Tail wild card matches all */ 259 if (!*pat) /* Tail wild card matches all */
246 return true; 260 return true;
247 while (*str) 261 while (*str)
248 if (strglobmatch(str++, pat)) 262 if (__match_glob(str++, pat, ignore_space))
249 return true; 263 return true;
250 } 264 }
251 return !*str && !*pat; 265 return !*str && !*pat;
252} 266}
253 267
268/**
269 * strglobmatch - glob expression pattern matching
270 * @str: the target string to match
271 * @pat: the pattern string to match
272 *
273 * This returns true if the @str matches @pat. @pat can includes wildcards
274 * ('*','?') and character classes ([CHARS], complementation and ranges are
275 * also supported). Also, this supports escape character ('\') to use special
276 * characters as normal character.
277 *
278 * Note: if @pat syntax is broken, this always returns false.
279 */
280bool strglobmatch(const char *str, const char *pat)
281{
282 return __match_glob(str, pat, false);
283}
284
285/**
286 * strlazymatch - matching pattern strings lazily with glob pattern
287 * @str: the target string to match
288 * @pat: the pattern string to match
289 *
290 * This is similar to strglobmatch, except this ignores spaces in
291 * the target string.
292 */
293bool strlazymatch(const char *str, const char *pat)
294{
295 return __match_glob(str, pat, true);
296}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
deleted file mode 100644
index 02ede58c54b4..000000000000
--- a/tools/perf/util/string.h
+++ /dev/null
@@ -1,17 +0,0 @@
1#ifndef __PERF_STRING_H_
2#define __PERF_STRING_H_
3
4#include <stdbool.h>
5#include "types.h"
6
7int hex2u64(const char *ptr, u64 *val);
8char *strxfrchar(char *s, char from, char to);
9s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat);
13
14#define _STR(x) #x
15#define STR(x) _STR(x)
16
17#endif /* __PERF_STRING_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab92763edb03..15ccfba8cdf8 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,39 +1,43 @@
1#include "util.h" 1#define _GNU_SOURCE
2#include "../perf.h" 2#include <ctype.h>
3#include "session.h" 3#include <dirent.h>
4#include "sort.h" 4#include <errno.h>
5#include "string.h" 5#include <libgen.h>
6#include "symbol.h" 6#include <stdlib.h>
7#include "thread.h" 7#include <stdio.h>
8 8#include <string.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <sys/param.h>
12#include <fcntl.h>
13#include <unistd.h>
14#include "build-id.h"
9#include "debug.h" 15#include "debug.h"
16#include "symbol.h"
17#include "strlist.h"
10 18
11#include <asm/bug.h>
12#include <libelf.h> 19#include <libelf.h>
13#include <gelf.h> 20#include <gelf.h>
14#include <elf.h> 21#include <elf.h>
15#include <limits.h> 22#include <limits.h>
16#include <sys/utsname.h> 23#include <sys/utsname.h>
17 24
25#ifndef KSYM_NAME_LEN
26#define KSYM_NAME_LEN 128
27#endif
28
18#ifndef NT_GNU_BUILD_ID 29#ifndef NT_GNU_BUILD_ID
19#define NT_GNU_BUILD_ID 3 30#define NT_GNU_BUILD_ID 3
20#endif 31#endif
21 32
22enum dso_origin { 33static bool dso__build_id_equal(const struct dso *self, u8 *build_id);
23 DSO__ORIG_KERNEL = 0, 34static int elf_read_build_id(Elf *elf, void *bf, size_t size);
24 DSO__ORIG_JAVA_JIT,
25 DSO__ORIG_FEDORA,
26 DSO__ORIG_UBUNTU,
27 DSO__ORIG_BUILDID,
28 DSO__ORIG_DSO,
29 DSO__ORIG_KMODULE,
30 DSO__ORIG_NOT_FOUND,
31};
32
33static void dsos__add(struct list_head *head, struct dso *dso); 35static void dsos__add(struct list_head *head, struct dso *dso);
34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 36static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 37static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct perf_session *session, symbol_filter_t filter); 38 symbol_filter_t filter);
39static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
40 symbol_filter_t filter);
37static int vmlinux_path__nr_entries; 41static int vmlinux_path__nr_entries;
38static char **vmlinux_path; 42static char **vmlinux_path;
39 43
@@ -41,8 +45,17 @@ struct symbol_conf symbol_conf = {
41 .exclude_other = true, 45 .exclude_other = true,
42 .use_modules = true, 46 .use_modules = true,
43 .try_vmlinux_path = true, 47 .try_vmlinux_path = true,
48 .symfs = "",
44}; 49};
45 50
51int dso__name_len(const struct dso *self)
52{
53 if (verbose)
54 return self->long_name_len;
55
56 return self->short_name_len;
57}
58
46bool dso__loaded(const struct dso *self, enum map_type type) 59bool dso__loaded(const struct dso *self, enum map_type type)
47{ 60{
48 return self->loaded & (1 << type); 61 return self->loaded & (1 << type);
@@ -53,17 +66,12 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type)
53 return self->sorted_by_name & (1 << type); 66 return self->sorted_by_name & (1 << type);
54} 67}
55 68
56static void dso__set_loaded(struct dso *self, enum map_type type)
57{
58 self->loaded |= (1 << type);
59}
60
61static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 69static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{ 70{
63 self->sorted_by_name |= (1 << type); 71 self->sorted_by_name |= (1 << type);
64} 72}
65 73
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 74bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{ 75{
68 switch (map_type) { 76 switch (map_type) {
69 case MAP__FUNCTION: 77 case MAP__FUNCTION:
@@ -89,7 +97,7 @@ static void symbols__fixup_end(struct rb_root *self)
89 prev = curr; 97 prev = curr;
90 curr = rb_entry(nd, struct symbol, rb_node); 98 curr = rb_entry(nd, struct symbol, rb_node);
91 99
92 if (prev->end == prev->start) 100 if (prev->end == prev->start && prev->end != curr->start)
93 prev->end = curr->start - 1; 101 prev->end = curr->start - 1;
94 } 102 }
95 103
@@ -118,7 +126,7 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
118 * We still haven't the actual symbols, so guess the 126 * We still haven't the actual symbols, so guess the
119 * last map final address. 127 * last map final address.
120 */ 128 */
121 curr->end = ~0UL; 129 curr->end = ~0ULL;
122} 130}
123 131
124static void map_groups__fixup_end(struct map_groups *self) 132static void map_groups__fixup_end(struct map_groups *self)
@@ -128,39 +136,45 @@ static void map_groups__fixup_end(struct map_groups *self)
128 __map_groups__fixup_end(self, i); 136 __map_groups__fixup_end(self, i);
129} 137}
130 138
131static struct symbol *symbol__new(u64 start, u64 len, const char *name) 139static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
140 const char *name)
132{ 141{
133 size_t namelen = strlen(name) + 1; 142 size_t namelen = strlen(name) + 1;
134 struct symbol *self = zalloc(symbol_conf.priv_size + 143 struct symbol *self = calloc(1, (symbol_conf.priv_size +
135 sizeof(*self) + namelen); 144 sizeof(*self) + namelen));
136 if (self == NULL) 145 if (self == NULL)
137 return NULL; 146 return NULL;
138 147
139 if (symbol_conf.priv_size) 148 if (symbol_conf.priv_size)
140 self = ((void *)self) + symbol_conf.priv_size; 149 self = ((void *)self) + symbol_conf.priv_size;
141 150
142 self->start = start; 151 self->start = start;
143 self->end = len ? start + len - 1 : start; 152 self->end = len ? start + len - 1 : start;
153 self->binding = binding;
154 self->namelen = namelen - 1;
144 155
145 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 156 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
146 157
147 memcpy(self->name, name, namelen); 158 memcpy(self->name, name, namelen);
148 159
149 return self; 160 return self;
150} 161}
151 162
152static void symbol__delete(struct symbol *self) 163void symbol__delete(struct symbol *self)
153{ 164{
154 free(((void *)self) - symbol_conf.priv_size); 165 free(((void *)self) - symbol_conf.priv_size);
155} 166}
156 167
157static size_t symbol__fprintf(struct symbol *self, FILE *fp) 168static size_t symbol__fprintf(struct symbol *self, FILE *fp)
158{ 169{
159 return fprintf(fp, " %llx-%llx %s\n", 170 return fprintf(fp, " %llx-%llx %c %s\n",
160 self->start, self->end, self->name); 171 self->start, self->end,
172 self->binding == STB_GLOBAL ? 'g' :
173 self->binding == STB_LOCAL ? 'l' : 'w',
174 self->name);
161} 175}
162 176
163static void dso__set_long_name(struct dso *self, char *name) 177void dso__set_long_name(struct dso *self, char *name)
164{ 178{
165 if (name == NULL) 179 if (name == NULL)
166 return; 180 return;
@@ -168,20 +182,28 @@ static void dso__set_long_name(struct dso *self, char *name)
168 self->long_name_len = strlen(name); 182 self->long_name_len = strlen(name);
169} 183}
170 184
185static void dso__set_short_name(struct dso *self, const char *name)
186{
187 if (name == NULL)
188 return;
189 self->short_name = name;
190 self->short_name_len = strlen(name);
191}
192
171static void dso__set_basename(struct dso *self) 193static void dso__set_basename(struct dso *self)
172{ 194{
173 self->short_name = basename(self->long_name); 195 dso__set_short_name(self, basename(self->long_name));
174} 196}
175 197
176struct dso *dso__new(const char *name) 198struct dso *dso__new(const char *name)
177{ 199{
178 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 200 struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
179 201
180 if (self != NULL) { 202 if (self != NULL) {
181 int i; 203 int i;
182 strcpy(self->name, name); 204 strcpy(self->name, name);
183 dso__set_long_name(self, self->name); 205 dso__set_long_name(self, self->name);
184 self->short_name = self->name; 206 dso__set_short_name(self, self->name);
185 for (i = 0; i < MAP__NR_TYPES; ++i) 207 for (i = 0; i < MAP__NR_TYPES; ++i)
186 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 208 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
187 self->slen_calculated = 0; 209 self->slen_calculated = 0;
@@ -189,6 +211,8 @@ struct dso *dso__new(const char *name)
189 self->loaded = 0; 211 self->loaded = 0;
190 self->sorted_by_name = 0; 212 self->sorted_by_name = 0;
191 self->has_build_id = 0; 213 self->has_build_id = 0;
214 self->kernel = DSO_TYPE_USER;
215 INIT_LIST_HEAD(&self->node);
192 } 216 }
193 217
194 return self; 218 return self;
@@ -212,7 +236,9 @@ void dso__delete(struct dso *self)
212 int i; 236 int i;
213 for (i = 0; i < MAP__NR_TYPES; ++i) 237 for (i = 0; i < MAP__NR_TYPES; ++i)
214 symbols__delete(&self->symbols[i]); 238 symbols__delete(&self->symbols[i]);
215 if (self->long_name != self->name) 239 if (self->sname_alloc)
240 free((char *)self->short_name);
241 if (self->lname_alloc)
216 free(self->long_name); 242 free(self->long_name);
217 free(self); 243 free(self);
218} 244}
@@ -274,7 +300,9 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
274{ 300{
275 struct rb_node **p = &self->rb_node; 301 struct rb_node **p = &self->rb_node;
276 struct rb_node *parent = NULL; 302 struct rb_node *parent = NULL;
277 struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; 303 struct symbol_name_rb_node *symn, *s;
304
305 symn = container_of(sym, struct symbol_name_rb_node, sym);
278 306
279 while (*p != NULL) { 307 while (*p != NULL) {
280 parent = *p; 308 parent = *p;
@@ -344,10 +372,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type)
344 &self->symbols[type]); 372 &self->symbols[type]);
345} 373}
346 374
347int build_id__sprintf(u8 *self, int len, char *bf) 375int build_id__sprintf(const u8 *self, int len, char *bf)
348{ 376{
349 char *bid = bf; 377 char *bid = bf;
350 u8 *raw = self; 378 const u8 *raw = self;
351 int i; 379 int i;
352 380
353 for (i = 0; i < len; ++i) { 381 for (i = 0; i < len; ++i) {
@@ -367,11 +395,29 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
367 return fprintf(fp, "%s", sbuild_id); 395 return fprintf(fp, "%s", sbuild_id);
368} 396}
369 397
398size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp)
399{
400 size_t ret = 0;
401 struct rb_node *nd;
402 struct symbol_name_rb_node *pos;
403
404 for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) {
405 pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
406 fprintf(fp, "%s\n", pos->sym.name);
407 }
408
409 return ret;
410}
411
370size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 412size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
371{ 413{
372 struct rb_node *nd; 414 struct rb_node *nd;
373 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 415 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
374 416
417 if (self->short_name != self->long_name)
418 ret += fprintf(fp, "%s, ", self->long_name);
419 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
420 self->loaded ? "" : "NOT ");
375 ret += dso__fprintf_buildid(self, fp); 421 ret += dso__fprintf_buildid(self, fp);
376 ret += fprintf(fp, ")\n"); 422 ret += fprintf(fp, ")\n");
377 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 423 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
@@ -382,35 +428,37 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
382 return ret; 428 return ret;
383} 429}
384 430
385/* 431int kallsyms__parse(const char *filename, void *arg,
386 * Loads the function entries in /proc/kallsyms into kernel_map->dso, 432 int (*process_symbol)(void *arg, const char *name,
387 * so that we can in the next step set the symbol ->end address and then 433 char type, u64 start, u64 end))
388 * call kernel_maps__split_kallsyms.
389 */
390static int dso__load_all_kallsyms(struct dso *self, struct map *map)
391{ 434{
392 char *line = NULL; 435 char *line = NULL;
393 size_t n; 436 size_t n;
394 struct rb_root *root = &self->symbols[map->type]; 437 int err = -1;
395 FILE *file = fopen("/proc/kallsyms", "r"); 438 u64 prev_start = 0;
439 char prev_symbol_type = 0;
440 char *prev_symbol_name;
441 FILE *file = fopen(filename, "r");
396 442
397 if (file == NULL) 443 if (file == NULL)
398 goto out_failure; 444 goto out_failure;
399 445
446 prev_symbol_name = malloc(KSYM_NAME_LEN);
447 if (prev_symbol_name == NULL)
448 goto out_close;
449
450 err = 0;
451
400 while (!feof(file)) { 452 while (!feof(file)) {
401 u64 start; 453 u64 start;
402 struct symbol *sym;
403 int line_len, len; 454 int line_len, len;
404 char symbol_type; 455 char symbol_type;
405 char *symbol_name; 456 char *symbol_name;
406 457
407 line_len = getline(&line, &n, file); 458 line_len = getline(&line, &n, file);
408 if (line_len < 0) 459 if (line_len < 0 || !line)
409 break; 460 break;
410 461
411 if (!line)
412 goto out_failure;
413
414 line[--line_len] = '\0'; /* \n */ 462 line[--line_len] = '\0'; /* \n */
415 463
416 len = hex2u64(line, &start); 464 len = hex2u64(line, &start);
@@ -420,46 +468,101 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
420 continue; 468 continue;
421 469
422 symbol_type = toupper(line[len]); 470 symbol_type = toupper(line[len]);
423 if (!symbol_type__is_a(symbol_type, map->type)) 471 len += 2;
424 continue; 472 symbol_name = line + len;
473 len = line_len - len;
425 474
426 symbol_name = line + len + 2; 475 if (len >= KSYM_NAME_LEN) {
427 /* 476 err = -1;
428 * Will fix up the end later, when we have all symbols sorted. 477 break;
429 */ 478 }
430 sym = symbol__new(start, 0, symbol_name);
431 479
432 if (sym == NULL) 480 if (prev_symbol_type) {
433 goto out_delete_line; 481 u64 end = start;
434 /* 482 if (end != prev_start)
435 * We will pass the symbols to the filter later, in 483 --end;
436 * map__split_kallsyms, when we have split the maps per module 484 err = process_symbol(arg, prev_symbol_name,
437 */ 485 prev_symbol_type, prev_start, end);
438 symbols__insert(root, sym); 486 if (err)
487 break;
488 }
489
490 memcpy(prev_symbol_name, symbol_name, len + 1);
491 prev_symbol_type = symbol_type;
492 prev_start = start;
439 } 493 }
440 494
495 free(prev_symbol_name);
441 free(line); 496 free(line);
497out_close:
442 fclose(file); 498 fclose(file);
499 return err;
443 500
444 return 0;
445
446out_delete_line:
447 free(line);
448out_failure: 501out_failure:
449 return -1; 502 return -1;
450} 503}
451 504
505struct process_kallsyms_args {
506 struct map *map;
507 struct dso *dso;
508};
509
510static u8 kallsyms2elf_type(char type)
511{
512 if (type == 'W')
513 return STB_WEAK;
514
515 return isupper(type) ? STB_GLOBAL : STB_LOCAL;
516}
517
518static int map__process_kallsym_symbol(void *arg, const char *name,
519 char type, u64 start, u64 end)
520{
521 struct symbol *sym;
522 struct process_kallsyms_args *a = arg;
523 struct rb_root *root = &a->dso->symbols[a->map->type];
524
525 if (!symbol_type__is_a(type, a->map->type))
526 return 0;
527
528 sym = symbol__new(start, end - start + 1,
529 kallsyms2elf_type(type), name);
530 if (sym == NULL)
531 return -ENOMEM;
532 /*
533 * We will pass the symbols to the filter later, in
534 * map__split_kallsyms, when we have split the maps per module
535 */
536 symbols__insert(root, sym);
537
538 return 0;
539}
540
541/*
542 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
543 * so that we can in the next step set the symbol ->end address and then
544 * call kernel_maps__split_kallsyms.
545 */
546static int dso__load_all_kallsyms(struct dso *self, const char *filename,
547 struct map *map)
548{
549 struct process_kallsyms_args args = { .map = map, .dso = self, };
550 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
551}
552
452/* 553/*
453 * Split the symbols into maps, making sure there are no overlaps, i.e. the 554 * Split the symbols into maps, making sure there are no overlaps, i.e. the
454 * kernel range is broken in several maps, named [kernel].N, as we don't have 555 * kernel range is broken in several maps, named [kernel].N, as we don't have
455 * the original ELF section names vmlinux have. 556 * the original ELF section names vmlinux have.
456 */ 557 */
457static int dso__split_kallsyms(struct dso *self, struct map *map, 558static int dso__split_kallsyms(struct dso *self, struct map *map,
458 struct perf_session *session, symbol_filter_t filter) 559 symbol_filter_t filter)
459{ 560{
561 struct map_groups *kmaps = map__kmap(map)->kmaps;
562 struct machine *machine = kmaps->machine;
460 struct map *curr_map = map; 563 struct map *curr_map = map;
461 struct symbol *pos; 564 struct symbol *pos;
462 int count = 0; 565 int count = 0, moved = 0;
463 struct rb_root *root = &self->symbols[map->type]; 566 struct rb_root *root = &self->symbols[map->type];
464 struct rb_node *next = rb_first(root); 567 struct rb_node *next = rb_first(root);
465 int kernel_range = 0; 568 int kernel_range = 0;
@@ -477,13 +580,35 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
477 580
478 *module++ = '\0'; 581 *module++ = '\0';
479 582
480 if (strcmp(self->name, module)) { 583 if (strcmp(curr_map->dso->short_name, module)) {
481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 584 if (curr_map != map &&
585 self->kernel == DSO_TYPE_GUEST_KERNEL &&
586 machine__is_default_guest(machine)) {
587 /*
588 * We assume all symbols of a module are
589 * continuous in * kallsyms, so curr_map
590 * points to a module and all its
591 * symbols are in its kmap. Mark it as
592 * loaded.
593 */
594 dso__set_loaded(curr_map->dso,
595 curr_map->type);
596 }
597
598 curr_map = map_groups__find_by_name(kmaps,
599 map->type, module);
482 if (curr_map == NULL) { 600 if (curr_map == NULL) {
483 pr_debug("/proc/{kallsyms,modules} " 601 pr_debug("%s/proc/{kallsyms,modules} "
484 "inconsistency!\n"); 602 "inconsistency while looking "
485 return -1; 603 "for \"%s\" module!\n",
604 machine->root_dir, module);
605 curr_map = map;
606 goto discard_symbol;
486 } 607 }
608
609 if (curr_map->dso->loaded &&
610 !machine__is_default_guest(machine))
611 goto discard_symbol;
487 } 612 }
488 /* 613 /*
489 * So that we look just like we get from .ko files, 614 * So that we look just like we get from .ko files,
@@ -495,24 +620,37 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
495 char dso_name[PATH_MAX]; 620 char dso_name[PATH_MAX];
496 struct dso *dso; 621 struct dso *dso;
497 622
498 snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 623 if (count == 0) {
499 kernel_range++); 624 curr_map = map;
625 goto filter_symbol;
626 }
627
628 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
629 snprintf(dso_name, sizeof(dso_name),
630 "[guest.kernel].%d",
631 kernel_range++);
632 else
633 snprintf(dso_name, sizeof(dso_name),
634 "[kernel].%d",
635 kernel_range++);
500 636
501 dso = dso__new(dso_name); 637 dso = dso__new(dso_name);
502 if (dso == NULL) 638 if (dso == NULL)
503 return -1; 639 return -1;
504 640
641 dso->kernel = self->kernel;
642
505 curr_map = map__new2(pos->start, dso, map->type); 643 curr_map = map__new2(pos->start, dso, map->type);
506 if (map == NULL) { 644 if (curr_map == NULL) {
507 dso__delete(dso); 645 dso__delete(dso);
508 return -1; 646 return -1;
509 } 647 }
510 648
511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 649 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
512 map_groups__insert(&session->kmaps, curr_map); 650 map_groups__insert(kmaps, curr_map);
513 ++kernel_range; 651 ++kernel_range;
514 } 652 }
515 653filter_symbol:
516 if (filter && filter(curr_map, pos)) { 654 if (filter && filter(curr_map, pos)) {
517discard_symbol: rb_erase(&pos->rb_node, root); 655discard_symbol: rb_erase(&pos->rb_node, root);
518 symbol__delete(pos); 656 symbol__delete(pos);
@@ -520,25 +658,33 @@ discard_symbol: rb_erase(&pos->rb_node, root);
520 if (curr_map != map) { 658 if (curr_map != map) {
521 rb_erase(&pos->rb_node, root); 659 rb_erase(&pos->rb_node, root);
522 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 660 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
523 } 661 ++moved;
524 count++; 662 } else
663 ++count;
525 } 664 }
526 } 665 }
527 666
528 return count; 667 if (curr_map != map &&
529} 668 self->kernel == DSO_TYPE_GUEST_KERNEL &&
669 machine__is_default_guest(kmaps->machine)) {
670 dso__set_loaded(curr_map->dso, curr_map->type);
671 }
530 672
673 return count + moved;
674}
531 675
532static int dso__load_kallsyms(struct dso *self, struct map *map, 676int dso__load_kallsyms(struct dso *self, const char *filename,
533 struct perf_session *session, symbol_filter_t filter) 677 struct map *map, symbol_filter_t filter)
534{ 678{
535 if (dso__load_all_kallsyms(self, map) < 0) 679 if (dso__load_all_kallsyms(self, filename, map) < 0)
536 return -1; 680 return -1;
537 681
538 symbols__fixup_end(&self->symbols[map->type]); 682 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
539 self->origin = DSO__ORIG_KERNEL; 683 self->origin = DSO__ORIG_GUEST_KERNEL;
684 else
685 self->origin = DSO__ORIG_KERNEL;
540 686
541 return dso__split_kallsyms(self, map, session, filter); 687 return dso__split_kallsyms(self, map, filter);
542} 688}
543 689
544static int dso__load_perf_map(struct dso *self, struct map *map, 690static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -579,7 +725,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
579 if (len + 2 >= line_len) 725 if (len + 2 >= line_len)
580 continue; 726 continue;
581 727
582 sym = symbol__new(start, size, line + len); 728 sym = symbol__new(start, size, STB_GLOBAL, line + len);
583 729
584 if (sym == NULL) 730 if (sym == NULL)
585 goto out_delete_line; 731 goto out_delete_line;
@@ -722,8 +868,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
722 char sympltname[1024]; 868 char sympltname[1024];
723 Elf *elf; 869 Elf *elf;
724 int nr = 0, symidx, fd, err = 0; 870 int nr = 0, symidx, fd, err = 0;
871 char name[PATH_MAX];
725 872
726 fd = open(self->long_name, O_RDONLY); 873 snprintf(name, sizeof(name), "%s%s",
874 symbol_conf.symfs, self->long_name);
875 fd = open(name, O_RDONLY);
727 if (fd < 0) 876 if (fd < 0)
728 goto out; 877 goto out;
729 878
@@ -791,7 +940,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
791 "%s@plt", elf_sym__name(&sym, symstrs)); 940 "%s@plt", elf_sym__name(&sym, symstrs));
792 941
793 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 942 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
794 sympltname); 943 STB_GLOBAL, sympltname);
795 if (!f) 944 if (!f)
796 goto out_elf_end; 945 goto out_elf_end;
797 946
@@ -813,7 +962,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
813 "%s@plt", elf_sym__name(&sym, symstrs)); 962 "%s@plt", elf_sym__name(&sym, symstrs));
814 963
815 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 964 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
816 sympltname); 965 STB_GLOBAL, sympltname);
817 if (!f) 966 if (!f)
818 goto out_elf_end; 967 goto out_elf_end;
819 968
@@ -835,8 +984,8 @@ out_close:
835 if (err == 0) 984 if (err == 0)
836 return nr; 985 return nr;
837out: 986out:
838 pr_warning("%s: problems reading %s PLT info.\n", 987 pr_debug("%s: problems reading %s PLT info.\n",
839 __func__, self->long_name); 988 __func__, self->long_name);
840 return 0; 989 return 0;
841} 990}
842 991
@@ -864,43 +1013,82 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
864 } 1013 }
865} 1014}
866 1015
867static int dso__load_sym(struct dso *self, struct map *map, 1016static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
868 struct perf_session *session, const char *name, int fd,
869 symbol_filter_t filter, int kernel, int kmodule)
870{ 1017{
1018 Elf_Scn *sec = NULL;
1019 GElf_Shdr shdr;
1020 size_t cnt = 1;
1021
1022 while ((sec = elf_nextscn(elf, sec)) != NULL) {
1023 gelf_getshdr(sec, &shdr);
1024
1025 if ((addr >= shdr.sh_addr) &&
1026 (addr < (shdr.sh_addr + shdr.sh_size)))
1027 return cnt;
1028
1029 ++cnt;
1030 }
1031
1032 return -1;
1033}
1034
1035static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1036 int fd, symbol_filter_t filter, int kmodule,
1037 int want_symtab)
1038{
1039 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
871 struct map *curr_map = map; 1040 struct map *curr_map = map;
872 struct dso *curr_dso = self; 1041 struct dso *curr_dso = self;
873 size_t dso_name_len = strlen(self->short_name);
874 Elf_Data *symstrs, *secstrs; 1042 Elf_Data *symstrs, *secstrs;
875 uint32_t nr_syms; 1043 uint32_t nr_syms;
876 int err = -1; 1044 int err = -1;
877 uint32_t idx; 1045 uint32_t idx;
878 GElf_Ehdr ehdr; 1046 GElf_Ehdr ehdr;
879 GElf_Shdr shdr; 1047 GElf_Shdr shdr, opdshdr;
880 Elf_Data *syms; 1048 Elf_Data *syms, *opddata = NULL;
881 GElf_Sym sym; 1049 GElf_Sym sym;
882 Elf_Scn *sec, *sec_strndx; 1050 Elf_Scn *sec, *sec_strndx, *opdsec;
883 Elf *elf; 1051 Elf *elf;
884 int nr = 0; 1052 int nr = 0;
1053 size_t opdidx = 0;
885 1054
886 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1055 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
887 if (elf == NULL) { 1056 if (elf == NULL) {
888 pr_err("%s: cannot read %s ELF file.\n", __func__, name); 1057 pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
889 goto out_close; 1058 goto out_close;
890 } 1059 }
891 1060
892 if (gelf_getehdr(elf, &ehdr) == NULL) { 1061 if (gelf_getehdr(elf, &ehdr) == NULL) {
893 pr_err("%s: cannot get elf header.\n", __func__); 1062 pr_debug("%s: cannot get elf header.\n", __func__);
894 goto out_elf_end; 1063 goto out_elf_end;
895 } 1064 }
896 1065
1066 /* Always reject images with a mismatched build-id: */
1067 if (self->has_build_id) {
1068 u8 build_id[BUILD_ID_SIZE];
1069
1070 if (elf_read_build_id(elf, build_id,
1071 BUILD_ID_SIZE) != BUILD_ID_SIZE)
1072 goto out_elf_end;
1073
1074 if (!dso__build_id_equal(self, build_id))
1075 goto out_elf_end;
1076 }
1077
897 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 1078 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
898 if (sec == NULL) { 1079 if (sec == NULL) {
1080 if (want_symtab)
1081 goto out_elf_end;
1082
899 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1083 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
900 if (sec == NULL) 1084 if (sec == NULL)
901 goto out_elf_end; 1085 goto out_elf_end;
902 } 1086 }
903 1087
1088 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
1089 if (opdsec)
1090 opddata = elf_rawdata(opdsec, NULL);
1091
904 syms = elf_getdata(sec, NULL); 1092 syms = elf_getdata(sec, NULL);
905 if (syms == NULL) 1093 if (syms == NULL)
906 goto out_elf_end; 1094 goto out_elf_end;
@@ -924,7 +1112,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
924 nr_syms = shdr.sh_size / shdr.sh_entsize; 1112 nr_syms = shdr.sh_size / shdr.sh_entsize;
925 1113
926 memset(&sym, 0, sizeof(sym)); 1114 memset(&sym, 0, sizeof(sym));
927 if (!kernel) { 1115 if (self->kernel == DSO_TYPE_USER) {
928 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 1116 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
929 elf_section_by_name(elf, &ehdr, &shdr, 1117 elf_section_by_name(elf, &ehdr, &shdr,
930 ".gnu.prelink_undo", 1118 ".gnu.prelink_undo",
@@ -933,14 +1121,35 @@ static int dso__load_sym(struct dso *self, struct map *map,
933 1121
934 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 1122 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
935 struct symbol *f; 1123 struct symbol *f;
936 const char *elf_name; 1124 const char *elf_name = elf_sym__name(&sym, symstrs);
937 char *demangled = NULL; 1125 char *demangled = NULL;
938 int is_label = elf_sym__is_label(&sym); 1126 int is_label = elf_sym__is_label(&sym);
939 const char *section_name; 1127 const char *section_name;
940 1128
1129 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
1130 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
1131 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
1132
941 if (!is_label && !elf_sym__is_a(&sym, map->type)) 1133 if (!is_label && !elf_sym__is_a(&sym, map->type))
942 continue; 1134 continue;
943 1135
1136 /* Reject ARM ELF "mapping symbols": these aren't unique and
1137 * don't identify functions, so will confuse the profile
1138 * output: */
1139 if (ehdr.e_machine == EM_ARM) {
1140 if (!strcmp(elf_name, "$a") ||
1141 !strcmp(elf_name, "$d") ||
1142 !strcmp(elf_name, "$t"))
1143 continue;
1144 }
1145
1146 if (opdsec && sym.st_shndx == opdidx) {
1147 u32 offset = sym.st_value - opdshdr.sh_addr;
1148 u64 *opd = opddata->d_buf + offset;
1149 sym.st_value = *opd;
1150 sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
1151 }
1152
944 sec = elf_getscn(elf, sym.st_shndx); 1153 sec = elf_getscn(elf, sym.st_shndx);
945 if (!sec) 1154 if (!sec)
946 goto out_elf_end; 1155 goto out_elf_end;
@@ -950,14 +1159,14 @@ static int dso__load_sym(struct dso *self, struct map *map,
950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 1159 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
951 continue; 1160 continue;
952 1161
953 elf_name = elf_sym__name(&sym, symstrs);
954 section_name = elf_sec__name(&shdr, secstrs); 1162 section_name = elf_sec__name(&shdr, secstrs);
955 1163
956 if (kernel || kmodule) { 1164 if (self->kernel != DSO_TYPE_USER || kmodule) {
957 char dso_name[PATH_MAX]; 1165 char dso_name[PATH_MAX];
958 1166
959 if (strcmp(section_name, 1167 if (strcmp(section_name,
960 curr_dso->short_name + dso_name_len) == 0) 1168 (curr_dso->short_name +
1169 self->short_name_len)) == 0)
961 goto new_symbol; 1170 goto new_symbol;
962 1171
963 if (strcmp(section_name, ".text") == 0) { 1172 if (strcmp(section_name, ".text") == 0) {
@@ -969,7 +1178,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
969 snprintf(dso_name, sizeof(dso_name), 1178 snprintf(dso_name, sizeof(dso_name),
970 "%s%s", self->short_name, section_name); 1179 "%s%s", self->short_name, section_name);
971 1180
972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); 1181 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
973 if (curr_map == NULL) { 1182 if (curr_map == NULL) {
974 u64 start = sym.st_value; 1183 u64 start = sym.st_value;
975 1184
@@ -979,17 +1188,19 @@ static int dso__load_sym(struct dso *self, struct map *map,
979 curr_dso = dso__new(dso_name); 1188 curr_dso = dso__new(dso_name);
980 if (curr_dso == NULL) 1189 if (curr_dso == NULL)
981 goto out_elf_end; 1190 goto out_elf_end;
1191 curr_dso->kernel = self->kernel;
982 curr_map = map__new2(start, curr_dso, 1192 curr_map = map__new2(start, curr_dso,
983 MAP__FUNCTION); 1193 map->type);
984 if (curr_map == NULL) { 1194 if (curr_map == NULL) {
985 dso__delete(curr_dso); 1195 dso__delete(curr_dso);
986 goto out_elf_end; 1196 goto out_elf_end;
987 } 1197 }
988 curr_map->map_ip = identity__map_ip; 1198 curr_map->map_ip = identity__map_ip;
989 curr_map->unmap_ip = identity__map_ip; 1199 curr_map->unmap_ip = identity__map_ip;
990 curr_dso->origin = DSO__ORIG_KERNEL; 1200 curr_dso->origin = self->origin;
991 map_groups__insert(&session->kmaps, curr_map); 1201 map_groups__insert(kmap->kmaps, curr_map);
992 dsos__add(&dsos__kernel, curr_dso); 1202 dsos__add(&self->node, curr_dso);
1203 dso__set_loaded(curr_dso, map->type);
993 } else 1204 } else
994 curr_dso = curr_map->dso; 1205 curr_dso = curr_map->dso;
995 1206
@@ -997,9 +1208,10 @@ static int dso__load_sym(struct dso *self, struct map *map,
997 } 1208 }
998 1209
999 if (curr_dso->adjust_symbols) { 1210 if (curr_dso->adjust_symbols) {
1000 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 1211 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1001 "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 1212 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1002 (u64)shdr.sh_addr, (u64)shdr.sh_offset); 1213 (u64)sym.st_value, (u64)shdr.sh_addr,
1214 (u64)shdr.sh_offset);
1003 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1215 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1004 } 1216 }
1005 /* 1217 /*
@@ -1011,7 +1223,8 @@ static int dso__load_sym(struct dso *self, struct map *map,
1011 if (demangled != NULL) 1223 if (demangled != NULL)
1012 elf_name = demangled; 1224 elf_name = demangled;
1013new_symbol: 1225new_symbol:
1014 f = symbol__new(sym.st_value, sym.st_size, elf_name); 1226 f = symbol__new(sym.st_value, sym.st_size,
1227 GELF_ST_BIND(sym.st_info), elf_name);
1015 free(demangled); 1228 free(demangled);
1016 if (!f) 1229 if (!f)
1017 goto out_elf_end; 1230 goto out_elf_end;
@@ -1027,8 +1240,16 @@ new_symbol:
1027 /* 1240 /*
1028 * For misannotated, zeroed, ASM function sizes. 1241 * For misannotated, zeroed, ASM function sizes.
1029 */ 1242 */
1030 if (nr > 0) 1243 if (nr > 0) {
1031 symbols__fixup_end(&self->symbols[map->type]); 1244 symbols__fixup_end(&self->symbols[map->type]);
1245 if (kmap) {
1246 /*
1247 * We need to fixup this here too because we create new
1248 * maps here, for things like vsyscall sections.
1249 */
1250 __map_groups__fixup_end(kmap->kmaps, map->type);
1251 }
1252 }
1032 err = nr; 1253 err = nr;
1033out_elf_end: 1254out_elf_end:
1034 elf_end(elf); 1255 elf_end(elf);
@@ -1041,64 +1262,53 @@ static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
1041 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 1262 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1042} 1263}
1043 1264
1044static bool __dsos__read_build_ids(struct list_head *head) 1265bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1045{ 1266{
1046 bool have_build_id = false; 1267 bool have_build_id = false;
1047 struct dso *pos; 1268 struct dso *pos;
1048 1269
1049 list_for_each_entry(pos, head, node) 1270 list_for_each_entry(pos, head, node) {
1271 if (with_hits && !pos->hit)
1272 continue;
1273 if (pos->has_build_id) {
1274 have_build_id = true;
1275 continue;
1276 }
1050 if (filename__read_build_id(pos->long_name, pos->build_id, 1277 if (filename__read_build_id(pos->long_name, pos->build_id,
1051 sizeof(pos->build_id)) > 0) { 1278 sizeof(pos->build_id)) > 0) {
1052 have_build_id = true; 1279 have_build_id = true;
1053 pos->has_build_id = true; 1280 pos->has_build_id = true;
1054 } 1281 }
1282 }
1055 1283
1056 return have_build_id; 1284 return have_build_id;
1057} 1285}
1058 1286
1059bool dsos__read_build_ids(void)
1060{
1061 bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
1062 ubuildids = __dsos__read_build_ids(&dsos__user);
1063 return kbuildids || ubuildids;
1064}
1065
1066/* 1287/*
1067 * Align offset to 4 bytes as needed for note name and descriptor data. 1288 * Align offset to 4 bytes as needed for note name and descriptor data.
1068 */ 1289 */
1069#define NOTE_ALIGN(n) (((n) + 3) & -4U) 1290#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1070 1291
1071int filename__read_build_id(const char *filename, void *bf, size_t size) 1292static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1072{ 1293{
1073 int fd, err = -1; 1294 int err = -1;
1074 GElf_Ehdr ehdr; 1295 GElf_Ehdr ehdr;
1075 GElf_Shdr shdr; 1296 GElf_Shdr shdr;
1076 Elf_Data *data; 1297 Elf_Data *data;
1077 Elf_Scn *sec; 1298 Elf_Scn *sec;
1078 Elf_Kind ek; 1299 Elf_Kind ek;
1079 void *ptr; 1300 void *ptr;
1080 Elf *elf;
1081 1301
1082 if (size < BUILD_ID_SIZE) 1302 if (size < BUILD_ID_SIZE)
1083 goto out; 1303 goto out;
1084 1304
1085 fd = open(filename, O_RDONLY);
1086 if (fd < 0)
1087 goto out;
1088
1089 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1090 if (elf == NULL) {
1091 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1092 goto out_close;
1093 }
1094
1095 ek = elf_kind(elf); 1305 ek = elf_kind(elf);
1096 if (ek != ELF_K_ELF) 1306 if (ek != ELF_K_ELF)
1097 goto out_elf_end; 1307 goto out;
1098 1308
1099 if (gelf_getehdr(elf, &ehdr) == NULL) { 1309 if (gelf_getehdr(elf, &ehdr) == NULL) {
1100 pr_err("%s: cannot get elf header.\n", __func__); 1310 pr_err("%s: cannot get elf header.\n", __func__);
1101 goto out_elf_end; 1311 goto out;
1102 } 1312 }
1103 1313
1104 sec = elf_section_by_name(elf, &ehdr, &shdr, 1314 sec = elf_section_by_name(elf, &ehdr, &shdr,
@@ -1107,12 +1317,12 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
1107 sec = elf_section_by_name(elf, &ehdr, &shdr, 1317 sec = elf_section_by_name(elf, &ehdr, &shdr,
1108 ".notes", NULL); 1318 ".notes", NULL);
1109 if (sec == NULL) 1319 if (sec == NULL)
1110 goto out_elf_end; 1320 goto out;
1111 } 1321 }
1112 1322
1113 data = elf_getdata(sec, NULL); 1323 data = elf_getdata(sec, NULL);
1114 if (data == NULL) 1324 if (data == NULL)
1115 goto out_elf_end; 1325 goto out;
1116 1326
1117 ptr = data->d_buf; 1327 ptr = data->d_buf;
1118 while (ptr < (data->d_buf + data->d_size)) { 1328 while (ptr < (data->d_buf + data->d_size)) {
@@ -1134,7 +1344,31 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
1134 } 1344 }
1135 ptr += descsz; 1345 ptr += descsz;
1136 } 1346 }
1137out_elf_end: 1347
1348out:
1349 return err;
1350}
1351
1352int filename__read_build_id(const char *filename, void *bf, size_t size)
1353{
1354 int fd, err = -1;
1355 Elf *elf;
1356
1357 if (size < BUILD_ID_SIZE)
1358 goto out;
1359
1360 fd = open(filename, O_RDONLY);
1361 if (fd < 0)
1362 goto out;
1363
1364 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1365 if (elf == NULL) {
1366 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1367 goto out_close;
1368 }
1369
1370 err = elf_read_build_id(elf, bf, size);
1371
1138 elf_end(elf); 1372 elf_end(elf);
1139out_close: 1373out_close:
1140 close(fd); 1374 close(fd);
@@ -1191,11 +1425,14 @@ char dso__symtab_origin(const struct dso *self)
1191 static const char origin[] = { 1425 static const char origin[] = {
1192 [DSO__ORIG_KERNEL] = 'k', 1426 [DSO__ORIG_KERNEL] = 'k',
1193 [DSO__ORIG_JAVA_JIT] = 'j', 1427 [DSO__ORIG_JAVA_JIT] = 'j',
1428 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
1194 [DSO__ORIG_FEDORA] = 'f', 1429 [DSO__ORIG_FEDORA] = 'f',
1195 [DSO__ORIG_UBUNTU] = 'u', 1430 [DSO__ORIG_UBUNTU] = 'u',
1196 [DSO__ORIG_BUILDID] = 'b', 1431 [DSO__ORIG_BUILDID] = 'b',
1197 [DSO__ORIG_DSO] = 'd', 1432 [DSO__ORIG_DSO] = 'd',
1198 [DSO__ORIG_KMODULE] = 'K', 1433 [DSO__ORIG_KMODULE] = 'K',
1434 [DSO__ORIG_GUEST_KERNEL] = 'g',
1435 [DSO__ORIG_GUEST_KMODULE] = 'G',
1199 }; 1436 };
1200 1437
1201 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1438 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -1203,19 +1440,27 @@ char dso__symtab_origin(const struct dso *self)
1203 return origin[self->origin]; 1440 return origin[self->origin];
1204} 1441}
1205 1442
1206int dso__load(struct dso *self, struct map *map, struct perf_session *session, 1443int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1207 symbol_filter_t filter)
1208{ 1444{
1209 int size = PATH_MAX; 1445 int size = PATH_MAX;
1210 char *name; 1446 char *name;
1211 u8 build_id[BUILD_ID_SIZE];
1212 int ret = -1; 1447 int ret = -1;
1213 int fd; 1448 int fd;
1449 struct machine *machine;
1450 const char *root_dir;
1451 int want_symtab;
1214 1452
1215 dso__set_loaded(self, map->type); 1453 dso__set_loaded(self, map->type);
1216 1454
1217 if (self->kernel) 1455 if (self->kernel == DSO_TYPE_KERNEL)
1218 return dso__load_kernel_sym(self, map, session, filter); 1456 return dso__load_kernel_sym(self, map, filter);
1457 else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
1458 return dso__load_guest_kernel_sym(self, map, filter);
1459
1460 if (map->groups && map->groups->machine)
1461 machine = map->groups->machine;
1462 else
1463 machine = NULL;
1219 1464
1220 name = malloc(size); 1465 name = malloc(size);
1221 if (!name) 1466 if (!name)
@@ -1230,71 +1475,97 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1230 return ret; 1475 return ret;
1231 } 1476 }
1232 1477
1233 self->origin = DSO__ORIG_FEDORA - 1; 1478 /* Iterate over candidate debug images.
1234 1479 * On the first pass, only load images if they have a full symtab.
1235more: 1480 * Failing that, do a second pass where we accept .dynsym also
1236 do { 1481 */
1237 self->origin++; 1482 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
1483 self->origin != DSO__ORIG_NOT_FOUND;
1484 self->origin++) {
1238 switch (self->origin) { 1485 switch (self->origin) {
1486 case DSO__ORIG_BUILD_ID_CACHE:
1487 /* skip the locally configured cache if a symfs is given */
1488 if (symbol_conf.symfs[0] ||
1489 (dso__build_id_filename(self, name, size) == NULL)) {
1490 continue;
1491 }
1492 break;
1239 case DSO__ORIG_FEDORA: 1493 case DSO__ORIG_FEDORA:
1240 snprintf(name, size, "/usr/lib/debug%s.debug", 1494 snprintf(name, size, "%s/usr/lib/debug%s.debug",
1241 self->long_name); 1495 symbol_conf.symfs, self->long_name);
1242 break; 1496 break;
1243 case DSO__ORIG_UBUNTU: 1497 case DSO__ORIG_UBUNTU:
1244 snprintf(name, size, "/usr/lib/debug%s", 1498 snprintf(name, size, "%s/usr/lib/debug%s",
1245 self->long_name); 1499 symbol_conf.symfs, self->long_name);
1246 break; 1500 break;
1247 case DSO__ORIG_BUILDID: 1501 case DSO__ORIG_BUILDID: {
1248 if (filename__read_build_id(self->long_name, build_id, 1502 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1249 sizeof(build_id))) { 1503
1250 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1504 if (!self->has_build_id)
1251 1505 continue;
1252 build_id__sprintf(build_id, sizeof(build_id), 1506
1253 build_id_hex); 1507 build_id__sprintf(self->build_id,
1254 snprintf(name, size, 1508 sizeof(self->build_id),
1255 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1509 build_id_hex);
1256 build_id_hex, build_id_hex + 2); 1510 snprintf(name, size,
1257 if (self->has_build_id) 1511 "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
1258 goto compare_build_id; 1512 symbol_conf.symfs, build_id_hex, build_id_hex + 2);
1259 break;
1260 } 1513 }
1261 self->origin++; 1514 break;
1262 /* Fall thru */
1263 case DSO__ORIG_DSO: 1515 case DSO__ORIG_DSO:
1264 snprintf(name, size, "%s", self->long_name); 1516 snprintf(name, size, "%s%s",
1517 symbol_conf.symfs, self->long_name);
1518 break;
1519 case DSO__ORIG_GUEST_KMODULE:
1520 if (map->groups && map->groups->machine)
1521 root_dir = map->groups->machine->root_dir;
1522 else
1523 root_dir = "";
1524 snprintf(name, size, "%s%s%s", symbol_conf.symfs,
1525 root_dir, self->long_name);
1265 break; 1526 break;
1266 1527
1267 default: 1528 case DSO__ORIG_KMODULE:
1268 goto out; 1529 snprintf(name, size, "%s%s", symbol_conf.symfs,
1269 } 1530 self->long_name);
1531 break;
1270 1532
1271 if (self->has_build_id) { 1533 default:
1272 if (filename__read_build_id(name, build_id, 1534 /*
1273 sizeof(build_id)) < 0) 1535 * If we wanted a full symtab but no image had one,
1274 goto more; 1536 * relax our requirements and repeat the search.
1275compare_build_id: 1537 */
1276 if (!dso__build_id_equal(self, build_id)) 1538 if (want_symtab) {
1277 goto more; 1539 want_symtab = 0;
1540 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1541 } else
1542 continue;
1278 } 1543 }
1279 1544
1545 /* Name is now the name of the next image to try */
1280 fd = open(name, O_RDONLY); 1546 fd = open(name, O_RDONLY);
1281 } while (fd < 0); 1547 if (fd < 0)
1548 continue;
1282 1549
1283 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 1550 ret = dso__load_sym(self, map, name, fd, filter, 0,
1284 close(fd); 1551 want_symtab);
1552 close(fd);
1285 1553
1286 /* 1554 /*
1287 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 1555 * Some people seem to have debuginfo files _WITHOUT_ debug
1288 */ 1556 * info!?!?
1289 if (!ret) 1557 */
1290 goto more; 1558 if (!ret)
1559 continue;
1291 1560
1292 if (ret > 0) { 1561 if (ret > 0) {
1293 int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1562 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1294 if (nr_plt > 0) 1563 if (nr_plt > 0)
1295 ret += nr_plt; 1564 ret += nr_plt;
1565 break;
1566 }
1296 } 1567 }
1297out: 1568
1298 free(name); 1569 free(name);
1299 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1570 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1300 return 0; 1571 return 0;
@@ -1309,35 +1580,65 @@ struct map *map_groups__find_by_name(struct map_groups *self,
1309 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1580 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1310 struct map *map = rb_entry(nd, struct map, rb_node); 1581 struct map *map = rb_entry(nd, struct map, rb_node);
1311 1582
1312 if (map->dso && strcmp(map->dso->name, name) == 0) 1583 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1313 return map; 1584 return map;
1314 } 1585 }
1315 1586
1316 return NULL; 1587 return NULL;
1317} 1588}
1318 1589
1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 1590static int dso__kernel_module_get_build_id(struct dso *self,
1591 const char *root_dir)
1592{
1593 char filename[PATH_MAX];
1594 /*
1595 * kernel module short names are of the form "[module]" and
1596 * we need just "module" here.
1597 */
1598 const char *name = self->short_name + 1;
1599
1600 snprintf(filename, sizeof(filename),
1601 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1602 root_dir, (int)strlen(name) - 1, name);
1603
1604 if (sysfs__read_build_id(filename, self->build_id,
1605 sizeof(self->build_id)) == 0)
1606 self->has_build_id = true;
1607
1608 return 0;
1609}
1610
1611static int map_groups__set_modules_path_dir(struct map_groups *self,
1612 const char *dir_name)
1320{ 1613{
1321 struct dirent *dent; 1614 struct dirent *dent;
1322 DIR *dir = opendir(dirname); 1615 DIR *dir = opendir(dir_name);
1616 int ret = 0;
1323 1617
1324 if (!dir) { 1618 if (!dir) {
1325 pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1619 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1326 return -1; 1620 return -1;
1327 } 1621 }
1328 1622
1329 while ((dent = readdir(dir)) != NULL) { 1623 while ((dent = readdir(dir)) != NULL) {
1330 char path[PATH_MAX]; 1624 char path[PATH_MAX];
1625 struct stat st;
1626
1627 /*sshfs might return bad dent->d_type, so we have to stat*/
1628 sprintf(path, "%s/%s", dir_name, dent->d_name);
1629 if (stat(path, &st))
1630 continue;
1331 1631
1332 if (dent->d_type == DT_DIR) { 1632 if (S_ISDIR(st.st_mode)) {
1333 if (!strcmp(dent->d_name, ".") || 1633 if (!strcmp(dent->d_name, ".") ||
1334 !strcmp(dent->d_name, "..")) 1634 !strcmp(dent->d_name, ".."))
1335 continue; 1635 continue;
1336 1636
1337 snprintf(path, sizeof(path), "%s/%s", 1637 snprintf(path, sizeof(path), "%s/%s",
1338 dirname, dent->d_name); 1638 dir_name, dent->d_name);
1339 if (perf_session__set_modules_path_dir(self, path) < 0) 1639 ret = map_groups__set_modules_path_dir(self, path);
1340 goto failure; 1640 if (ret < 0)
1641 goto out;
1341 } else { 1642 } else {
1342 char *dot = strrchr(dent->d_name, '.'), 1643 char *dot = strrchr(dent->d_name, '.'),
1343 dso_name[PATH_MAX]; 1644 dso_name[PATH_MAX];
@@ -1350,38 +1651,70 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1350 (int)(dot - dent->d_name), dent->d_name); 1651 (int)(dot - dent->d_name), dent->d_name);
1351 1652
1352 strxfrchar(dso_name, '-', '_'); 1653 strxfrchar(dso_name, '-', '_');
1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); 1654 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1354 if (map == NULL) 1655 if (map == NULL)
1355 continue; 1656 continue;
1356 1657
1357 snprintf(path, sizeof(path), "%s/%s", 1658 snprintf(path, sizeof(path), "%s/%s",
1358 dirname, dent->d_name); 1659 dir_name, dent->d_name);
1359 1660
1360 long_name = strdup(path); 1661 long_name = strdup(path);
1361 if (long_name == NULL) 1662 if (long_name == NULL) {
1362 goto failure; 1663 ret = -1;
1664 goto out;
1665 }
1363 dso__set_long_name(map->dso, long_name); 1666 dso__set_long_name(map->dso, long_name);
1667 map->dso->lname_alloc = 1;
1668 dso__kernel_module_get_build_id(map->dso, "");
1364 } 1669 }
1365 } 1670 }
1366 1671
1367 return 0; 1672out:
1368failure:
1369 closedir(dir); 1673 closedir(dir);
1370 return -1; 1674 return ret;
1371} 1675}
1372 1676
1373static int perf_session__set_modules_path(struct perf_session *self) 1677static char *get_kernel_version(const char *root_dir)
1374{ 1678{
1375 struct utsname uts; 1679 char version[PATH_MAX];
1680 FILE *file;
1681 char *name, *tmp;
1682 const char *prefix = "Linux version ";
1683
1684 sprintf(version, "%s/proc/version", root_dir);
1685 file = fopen(version, "r");
1686 if (!file)
1687 return NULL;
1688
1689 version[0] = '\0';
1690 tmp = fgets(version, sizeof(version), file);
1691 fclose(file);
1692
1693 name = strstr(version, prefix);
1694 if (!name)
1695 return NULL;
1696 name += strlen(prefix);
1697 tmp = strchr(name, ' ');
1698 if (tmp)
1699 *tmp = '\0';
1700
1701 return strdup(name);
1702}
1703
1704static int machine__set_modules_path(struct machine *self)
1705{
1706 char *version;
1376 char modules_path[PATH_MAX]; 1707 char modules_path[PATH_MAX];
1377 1708
1378 if (uname(&uts) < 0) 1709 version = get_kernel_version(self->root_dir);
1710 if (!version)
1379 return -1; 1711 return -1;
1380 1712
1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1713 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1382 uts.release); 1714 self->root_dir, version);
1715 free(version);
1383 1716
1384 return perf_session__set_modules_path_dir(self, modules_path); 1717 return map_groups__set_modules_path_dir(&self->kmaps, modules_path);
1385} 1718}
1386 1719
1387/* 1720/*
@@ -1391,8 +1724,8 @@ static int perf_session__set_modules_path(struct perf_session *self)
1391 */ 1724 */
1392static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1725static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1393{ 1726{
1394 struct map *self = malloc(sizeof(*self)); 1727 struct map *self = calloc(1, (sizeof(*self) +
1395 1728 (dso->kernel ? sizeof(struct kmap) : 0)));
1396 if (self != NULL) { 1729 if (self != NULL) {
1397 /* 1730 /*
1398 * ->end will be filled after we load all the symbols 1731 * ->end will be filled after we load all the symbols
@@ -1403,20 +1736,50 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1403 return self; 1736 return self;
1404} 1737}
1405 1738
1406static int perf_session__create_module_maps(struct perf_session *self) 1739struct map *machine__new_module(struct machine *self, u64 start,
1740 const char *filename)
1741{
1742 struct map *map;
1743 struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename);
1744
1745 if (dso == NULL)
1746 return NULL;
1747
1748 map = map__new2(start, dso, MAP__FUNCTION);
1749 if (map == NULL)
1750 return NULL;
1751
1752 if (machine__is_host(self))
1753 dso->origin = DSO__ORIG_KMODULE;
1754 else
1755 dso->origin = DSO__ORIG_GUEST_KMODULE;
1756 map_groups__insert(&self->kmaps, map);
1757 return map;
1758}
1759
1760static int machine__create_modules(struct machine *self)
1407{ 1761{
1408 char *line = NULL; 1762 char *line = NULL;
1409 size_t n; 1763 size_t n;
1410 FILE *file = fopen("/proc/modules", "r"); 1764 FILE *file;
1411 struct map *map; 1765 struct map *map;
1766 const char *modules;
1767 char path[PATH_MAX];
1768
1769 if (machine__is_default_guest(self))
1770 modules = symbol_conf.default_guest_modules;
1771 else {
1772 sprintf(path, "%s/proc/modules", self->root_dir);
1773 modules = path;
1774 }
1412 1775
1776 file = fopen(modules, "r");
1413 if (file == NULL) 1777 if (file == NULL)
1414 return -1; 1778 return -1;
1415 1779
1416 while (!feof(file)) { 1780 while (!feof(file)) {
1417 char name[PATH_MAX]; 1781 char name[PATH_MAX];
1418 u64 start; 1782 u64 start;
1419 struct dso *dso;
1420 char *sep; 1783 char *sep;
1421 int line_len; 1784 int line_len;
1422 1785
@@ -1442,32 +1805,16 @@ static int perf_session__create_module_maps(struct perf_session *self)
1442 *sep = '\0'; 1805 *sep = '\0';
1443 1806
1444 snprintf(name, sizeof(name), "[%s]", line); 1807 snprintf(name, sizeof(name), "[%s]", line);
1445 dso = dso__new(name); 1808 map = machine__new_module(self, start, name);
1446 1809 if (map == NULL)
1447 if (dso == NULL)
1448 goto out_delete_line;
1449
1450 map = map__new2(start, dso, MAP__FUNCTION);
1451 if (map == NULL) {
1452 dso__delete(dso);
1453 goto out_delete_line; 1810 goto out_delete_line;
1454 } 1811 dso__kernel_module_get_build_id(map->dso, self->root_dir);
1455
1456 snprintf(name, sizeof(name),
1457 "/sys/module/%s/notes/.note.gnu.build-id", line);
1458 if (sysfs__read_build_id(name, dso->build_id,
1459 sizeof(dso->build_id)) == 0)
1460 dso->has_build_id = true;
1461
1462 dso->origin = DSO__ORIG_KMODULE;
1463 map_groups__insert(&self->kmaps, map);
1464 dsos__add(&dsos__kernel, dso);
1465 } 1812 }
1466 1813
1467 free(line); 1814 free(line);
1468 fclose(file); 1815 fclose(file);
1469 1816
1470 return perf_session__set_modules_path(self); 1817 return machine__set_modules_path(self);
1471 1818
1472out_delete_line: 1819out_delete_line:
1473 free(line); 1820 free(line);
@@ -1475,86 +1822,161 @@ out_failure:
1475 return -1; 1822 return -1;
1476} 1823}
1477 1824
1478static int dso__load_vmlinux(struct dso *self, struct map *map, 1825int dso__load_vmlinux(struct dso *self, struct map *map,
1479 struct perf_session *session, 1826 const char *vmlinux, symbol_filter_t filter)
1480 const char *vmlinux, symbol_filter_t filter)
1481{ 1827{
1482 int err = -1, fd; 1828 int err = -1, fd;
1829 char symfs_vmlinux[PATH_MAX];
1483 1830
1484 if (self->has_build_id) { 1831 snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s",
1485 u8 build_id[BUILD_ID_SIZE]; 1832 symbol_conf.symfs, vmlinux);
1486 1833 fd = open(symfs_vmlinux, O_RDONLY);
1487 if (filename__read_build_id(vmlinux, build_id,
1488 sizeof(build_id)) < 0) {
1489 pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1490 return -1;
1491 }
1492 if (!dso__build_id_equal(self, build_id)) {
1493 char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1494 vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1495
1496 build_id__sprintf(self->build_id,
1497 sizeof(self->build_id),
1498 expected_build_id);
1499 build_id__sprintf(build_id, sizeof(build_id),
1500 vmlinux_build_id);
1501 pr_debug("build_id in %s is %s while expected is %s, "
1502 "ignoring it\n", vmlinux, vmlinux_build_id,
1503 expected_build_id);
1504 return -1;
1505 }
1506 }
1507
1508 fd = open(vmlinux, O_RDONLY);
1509 if (fd < 0) 1834 if (fd < 0)
1510 return -1; 1835 return -1;
1511 1836
1512 dso__set_loaded(self, map->type); 1837 dso__set_loaded(self, map->type);
1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); 1838 err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0);
1514 close(fd); 1839 close(fd);
1515 1840
1841 if (err > 0)
1842 pr_debug("Using %s for symbols\n", symfs_vmlinux);
1843
1844 return err;
1845}
1846
1847int dso__load_vmlinux_path(struct dso *self, struct map *map,
1848 symbol_filter_t filter)
1849{
1850 int i, err = 0;
1851 char *filename;
1852
1853 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1854 vmlinux_path__nr_entries + 1);
1855
1856 filename = dso__build_id_filename(self, NULL, 0);
1857 if (filename != NULL) {
1858 err = dso__load_vmlinux(self, map, filename, filter);
1859 if (err > 0) {
1860 dso__set_long_name(self, filename);
1861 goto out;
1862 }
1863 free(filename);
1864 }
1865
1866 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1867 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1868 if (err > 0) {
1869 dso__set_long_name(self, strdup(vmlinux_path[i]));
1870 break;
1871 }
1872 }
1873out:
1516 return err; 1874 return err;
1517} 1875}
1518 1876
1519static int dso__load_kernel_sym(struct dso *self, struct map *map, 1877static int dso__load_kernel_sym(struct dso *self, struct map *map,
1520 struct perf_session *session, symbol_filter_t filter) 1878 symbol_filter_t filter)
1521{ 1879{
1522 int err; 1880 int err;
1523 bool is_kallsyms; 1881 const char *kallsyms_filename = NULL;
1882 char *kallsyms_allocated_filename = NULL;
1883 /*
1884 * Step 1: if the user specified a kallsyms or vmlinux filename, use
1885 * it and only it, reporting errors to the user if it cannot be used.
1886 *
1887 * For instance, try to analyse an ARM perf.data file _without_ a
1888 * build-id, or if the user specifies the wrong path to the right
1889 * vmlinux file, obviously we can't fallback to another vmlinux (a
1890 * x86_86 one, on the machine where analysis is being performed, say),
1891 * or worse, /proc/kallsyms.
1892 *
1893 * If the specified file _has_ a build-id and there is a build-id
1894 * section in the perf.data file, we will still do the expected
1895 * validation in dso__load_vmlinux and will bail out if they don't
1896 * match.
1897 */
1898 if (symbol_conf.kallsyms_name != NULL) {
1899 kallsyms_filename = symbol_conf.kallsyms_name;
1900 goto do_kallsyms;
1901 }
1902
1903 if (symbol_conf.vmlinux_name != NULL) {
1904 err = dso__load_vmlinux(self, map,
1905 symbol_conf.vmlinux_name, filter);
1906 if (err > 0) {
1907 dso__set_long_name(self,
1908 strdup(symbol_conf.vmlinux_name));
1909 goto out_fixup;
1910 }
1911 return err;
1912 }
1524 1913
1525 if (vmlinux_path != NULL) { 1914 if (vmlinux_path != NULL) {
1526 int i; 1915 err = dso__load_vmlinux_path(self, map, filter);
1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1916 if (err > 0)
1528 vmlinux_path__nr_entries); 1917 goto out_fixup;
1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1918 }
1530 err = dso__load_vmlinux(self, map, session, 1919
1531 vmlinux_path[i], filter); 1920 /* do not try local files if a symfs was given */
1532 if (err > 0) { 1921 if (symbol_conf.symfs[0] != 0)
1533 pr_debug("Using %s for symbols\n", 1922 return -1;
1534 vmlinux_path[i]); 1923
1535 dso__set_long_name(self, 1924 /*
1536 strdup(vmlinux_path[i])); 1925 * Say the kernel DSO was created when processing the build-id header table,
1537 goto out_fixup; 1926 * we have a build-id, so check if it is the same as the running kernel,
1927 * using it if it is.
1928 */
1929 if (self->has_build_id) {
1930 u8 kallsyms_build_id[BUILD_ID_SIZE];
1931 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1932
1933 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1934 sizeof(kallsyms_build_id)) == 0) {
1935 if (dso__build_id_equal(self, kallsyms_build_id)) {
1936 kallsyms_filename = "/proc/kallsyms";
1937 goto do_kallsyms;
1538 } 1938 }
1539 } 1939 }
1540 } 1940 /*
1941 * Now look if we have it on the build-id cache in
1942 * $HOME/.debug/[kernel.kallsyms].
1943 */
1944 build_id__sprintf(self->build_id, sizeof(self->build_id),
1945 sbuild_id);
1541 1946
1542 is_kallsyms = self->long_name[0] == '['; 1947 if (asprintf(&kallsyms_allocated_filename,
1543 if (is_kallsyms) 1948 "%s/.debug/[kernel.kallsyms]/%s",
1544 goto do_kallsyms; 1949 getenv("HOME"), sbuild_id) == -1) {
1950 pr_err("Not enough memory for kallsyms file lookup\n");
1951 return -1;
1952 }
1545 1953
1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1954 kallsyms_filename = kallsyms_allocated_filename;
1547 if (err <= 0) { 1955
1548 pr_info("The file %s cannot be used, " 1956 if (access(kallsyms_filename, F_OK)) {
1549 "trying to use /proc/kallsyms...", self->long_name); 1957 pr_err("No kallsyms or vmlinux with build-id %s "
1550do_kallsyms: 1958 "was found\n", sbuild_id);
1551 err = dso__load_kallsyms(self, map, session, filter); 1959 free(kallsyms_allocated_filename);
1552 if (err > 0 && !is_kallsyms) 1960 return -1;
1553 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1961 }
1962 } else {
1963 /*
1964 * Last resort, if we don't have a build-id and couldn't find
1965 * any vmlinux file, try the running kernel kallsyms table.
1966 */
1967 kallsyms_filename = "/proc/kallsyms";
1554 } 1968 }
1555 1969
1970do_kallsyms:
1971 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1972 if (err > 0)
1973 pr_debug("Using %s for symbols\n", kallsyms_filename);
1974 free(kallsyms_allocated_filename);
1975
1556 if (err > 0) { 1976 if (err > 0) {
1557out_fixup: 1977out_fixup:
1978 if (kallsyms_filename != NULL)
1979 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1558 map__fixup_start(map); 1980 map__fixup_start(map);
1559 map__fixup_end(map); 1981 map__fixup_end(map);
1560 } 1982 }
@@ -1562,9 +1984,56 @@ out_fixup:
1562 return err; 1984 return err;
1563} 1985}
1564 1986
1565LIST_HEAD(dsos__user); 1987static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1566LIST_HEAD(dsos__kernel); 1988 symbol_filter_t filter)
1567struct dso *vdso; 1989{
1990 int err;
1991 const char *kallsyms_filename = NULL;
1992 struct machine *machine;
1993 char path[PATH_MAX];
1994
1995 if (!map->groups) {
1996 pr_debug("Guest kernel map hasn't the point to groups\n");
1997 return -1;
1998 }
1999 machine = map->groups->machine;
2000
2001 if (machine__is_default_guest(machine)) {
2002 /*
2003 * if the user specified a vmlinux filename, use it and only
2004 * it, reporting errors to the user if it cannot be used.
2005 * Or use file guest_kallsyms inputted by user on commandline
2006 */
2007 if (symbol_conf.default_guest_vmlinux_name != NULL) {
2008 err = dso__load_vmlinux(self, map,
2009 symbol_conf.default_guest_vmlinux_name, filter);
2010 goto out_try_fixup;
2011 }
2012
2013 kallsyms_filename = symbol_conf.default_guest_kallsyms;
2014 if (!kallsyms_filename)
2015 return -1;
2016 } else {
2017 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2018 kallsyms_filename = path;
2019 }
2020
2021 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
2022 if (err > 0)
2023 pr_debug("Using %s for symbols\n", kallsyms_filename);
2024
2025out_try_fixup:
2026 if (err > 0) {
2027 if (kallsyms_filename != NULL) {
2028 machine__mmap_name(machine, path, sizeof(path));
2029 dso__set_long_name(self, strdup(path));
2030 }
2031 map__fixup_start(map);
2032 map__fixup_end(map);
2033 }
2034
2035 return err;
2036}
1568 2037
1569static void dsos__add(struct list_head *head, struct dso *dso) 2038static void dsos__add(struct list_head *head, struct dso *dso)
1570{ 2039{
@@ -1576,19 +2045,19 @@ static struct dso *dsos__find(struct list_head *head, const char *name)
1576 struct dso *pos; 2045 struct dso *pos;
1577 2046
1578 list_for_each_entry(pos, head, node) 2047 list_for_each_entry(pos, head, node)
1579 if (strcmp(pos->name, name) == 0) 2048 if (strcmp(pos->long_name, name) == 0)
1580 return pos; 2049 return pos;
1581 return NULL; 2050 return NULL;
1582} 2051}
1583 2052
1584struct dso *dsos__findnew(const char *name) 2053struct dso *__dsos__findnew(struct list_head *head, const char *name)
1585{ 2054{
1586 struct dso *dso = dsos__find(&dsos__user, name); 2055 struct dso *dso = dsos__find(head, name);
1587 2056
1588 if (!dso) { 2057 if (!dso) {
1589 dso = dso__new(name); 2058 dso = dso__new(name);
1590 if (dso != NULL) { 2059 if (dso != NULL) {
1591 dsos__add(&dsos__user, dso); 2060 dsos__add(head, dso);
1592 dso__set_basename(dso); 2061 dso__set_basename(dso);
1593 } 2062 }
1594 } 2063 }
@@ -1596,93 +2065,233 @@ struct dso *dsos__findnew(const char *name)
1596 return dso; 2065 return dso;
1597} 2066}
1598 2067
1599static void __dsos__fprintf(struct list_head *head, FILE *fp) 2068size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1600{ 2069{
1601 struct dso *pos; 2070 struct dso *pos;
2071 size_t ret = 0;
1602 2072
1603 list_for_each_entry(pos, head, node) { 2073 list_for_each_entry(pos, head, node) {
1604 int i; 2074 int i;
1605 for (i = 0; i < MAP__NR_TYPES; ++i) 2075 for (i = 0; i < MAP__NR_TYPES; ++i)
1606 dso__fprintf(pos, i, fp); 2076 ret += dso__fprintf(pos, i, fp);
1607 } 2077 }
2078
2079 return ret;
1608} 2080}
1609 2081
1610void dsos__fprintf(FILE *fp) 2082size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp)
1611{ 2083{
1612 __dsos__fprintf(&dsos__kernel, fp); 2084 struct rb_node *nd;
1613 __dsos__fprintf(&dsos__user, fp); 2085 size_t ret = 0;
2086
2087 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
2088 struct machine *pos = rb_entry(nd, struct machine, rb_node);
2089 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2090 ret += __dsos__fprintf(&pos->user_dsos, fp);
2091 }
2092
2093 return ret;
1614} 2094}
1615 2095
1616static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 2096static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
2097 bool with_hits)
1617{ 2098{
1618 struct dso *pos; 2099 struct dso *pos;
1619 size_t ret = 0; 2100 size_t ret = 0;
1620 2101
1621 list_for_each_entry(pos, head, node) { 2102 list_for_each_entry(pos, head, node) {
2103 if (with_hits && !pos->hit)
2104 continue;
1622 ret += dso__fprintf_buildid(pos, fp); 2105 ret += dso__fprintf_buildid(pos, fp);
1623 ret += fprintf(fp, " %s\n", pos->long_name); 2106 ret += fprintf(fp, " %s\n", pos->long_name);
1624 } 2107 }
1625 return ret; 2108 return ret;
1626} 2109}
1627 2110
1628size_t dsos__fprintf_buildid(FILE *fp) 2111size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits)
1629{ 2112{
1630 return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 2113 return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) +
1631 __dsos__fprintf_buildid(&dsos__user, fp)); 2114 __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits);
1632} 2115}
1633 2116
1634static struct dso *dsos__create_kernel( const char *vmlinux) 2117size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
1635{ 2118{
1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 2119 struct rb_node *nd;
2120 size_t ret = 0;
1637 2121
1638 if (kernel == NULL) 2122 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
1639 return NULL; 2123 struct machine *pos = rb_entry(nd, struct machine, rb_node);
2124 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2125 }
2126 return ret;
2127}
2128
2129struct dso *dso__new_kernel(const char *name)
2130{
2131 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
2132
2133 if (self != NULL) {
2134 dso__set_short_name(self, "[kernel]");
2135 self->kernel = DSO_TYPE_KERNEL;
2136 }
2137
2138 return self;
2139}
2140
2141static struct dso *dso__new_guest_kernel(struct machine *machine,
2142 const char *name)
2143{
2144 char bf[PATH_MAX];
2145 struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf)));
2146
2147 if (self != NULL) {
2148 dso__set_short_name(self, "[guest.kernel]");
2149 self->kernel = DSO_TYPE_GUEST_KERNEL;
2150 }
1640 2151
1641 kernel->short_name = "[kernel]"; 2152 return self;
1642 kernel->kernel = 1; 2153}
1643 2154
1644 vdso = dso__new("[vdso]"); 2155void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine)
1645 if (vdso == NULL) 2156{
1646 goto out_delete_kernel_dso; 2157 char path[PATH_MAX];
1647 dso__set_loaded(vdso, MAP__FUNCTION);
1648 2158
1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 2159 if (machine__is_default_guest(machine))
1650 sizeof(kernel->build_id)) == 0) 2160 return;
1651 kernel->has_build_id = true; 2161 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2162 if (sysfs__read_build_id(path, self->build_id,
2163 sizeof(self->build_id)) == 0)
2164 self->has_build_id = true;
2165}
2166
2167static struct dso *machine__create_kernel(struct machine *self)
2168{
2169 const char *vmlinux_name = NULL;
2170 struct dso *kernel;
1652 2171
1653 dsos__add(&dsos__kernel, kernel); 2172 if (machine__is_host(self)) {
1654 dsos__add(&dsos__user, vdso); 2173 vmlinux_name = symbol_conf.vmlinux_name;
2174 kernel = dso__new_kernel(vmlinux_name);
2175 } else {
2176 if (machine__is_default_guest(self))
2177 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2178 kernel = dso__new_guest_kernel(self, vmlinux_name);
2179 }
1655 2180
2181 if (kernel != NULL) {
2182 dso__read_running_kernel_build_id(kernel, self);
2183 dsos__add(&self->kernel_dsos, kernel);
2184 }
1656 return kernel; 2185 return kernel;
2186}
1657 2187
1658out_delete_kernel_dso: 2188struct process_args {
1659 dso__delete(kernel); 2189 u64 start;
1660 return NULL; 2190};
2191
2192static int symbol__in_kernel(void *arg, const char *name,
2193 char type __used, u64 start, u64 end __used)
2194{
2195 struct process_args *args = arg;
2196
2197 if (strchr(name, '['))
2198 return 0;
2199
2200 args->start = start;
2201 return 1;
1661} 2202}
1662 2203
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) 2204/* Figure out the start address of kernel map from /proc/kallsyms */
2205static u64 machine__get_kernel_start_addr(struct machine *machine)
1664{ 2206{
1665 struct map *functions, *variables; 2207 const char *filename;
1666 struct dso *kernel = dsos__create_kernel(vmlinux); 2208 char path[PATH_MAX];
2209 struct process_args args;
1667 2210
1668 if (kernel == NULL) 2211 if (machine__is_host(machine)) {
1669 return -1; 2212 filename = "/proc/kallsyms";
2213 } else {
2214 if (machine__is_default_guest(machine))
2215 filename = (char *)symbol_conf.default_guest_kallsyms;
2216 else {
2217 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
2218 filename = path;
2219 }
2220 }
1670 2221
1671 functions = map__new2(0, kernel, MAP__FUNCTION); 2222 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0)
1672 if (functions == NULL) 2223 return 0;
1673 return -1;
1674 2224
1675 variables = map__new2(0, kernel, MAP__VARIABLE); 2225 return args.start;
1676 if (variables == NULL) { 2226}
1677 map__delete(functions); 2227
1678 return -1; 2228int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2229{
2230 enum map_type type;
2231 u64 start = machine__get_kernel_start_addr(self);
2232
2233 for (type = 0; type < MAP__NR_TYPES; ++type) {
2234 struct kmap *kmap;
2235
2236 self->vmlinux_maps[type] = map__new2(start, kernel, type);
2237 if (self->vmlinux_maps[type] == NULL)
2238 return -1;
2239
2240 self->vmlinux_maps[type]->map_ip =
2241 self->vmlinux_maps[type]->unmap_ip = identity__map_ip;
2242
2243 kmap = map__kmap(self->vmlinux_maps[type]);
2244 kmap->kmaps = &self->kmaps;
2245 map_groups__insert(&self->kmaps, self->vmlinux_maps[type]);
1679 } 2246 }
1680 2247
1681 functions->map_ip = functions->unmap_ip = 2248 return 0;
1682 variables->map_ip = variables->unmap_ip = identity__map_ip; 2249}
1683 map_groups__insert(self, functions); 2250
1684 map_groups__insert(self, variables); 2251void machine__destroy_kernel_maps(struct machine *self)
2252{
2253 enum map_type type;
2254
2255 for (type = 0; type < MAP__NR_TYPES; ++type) {
2256 struct kmap *kmap;
2257
2258 if (self->vmlinux_maps[type] == NULL)
2259 continue;
2260
2261 kmap = map__kmap(self->vmlinux_maps[type]);
2262 map_groups__remove(&self->kmaps, self->vmlinux_maps[type]);
2263 if (kmap->ref_reloc_sym) {
2264 /*
2265 * ref_reloc_sym is shared among all maps, so free just
2266 * on one of them.
2267 */
2268 if (type == MAP__FUNCTION) {
2269 free((char *)kmap->ref_reloc_sym->name);
2270 kmap->ref_reloc_sym->name = NULL;
2271 free(kmap->ref_reloc_sym);
2272 }
2273 kmap->ref_reloc_sym = NULL;
2274 }
2275
2276 map__delete(self->vmlinux_maps[type]);
2277 self->vmlinux_maps[type] = NULL;
2278 }
2279}
2280
2281int machine__create_kernel_maps(struct machine *self)
2282{
2283 struct dso *kernel = machine__create_kernel(self);
2284
2285 if (kernel == NULL ||
2286 __machine__create_kernel_maps(self, kernel) < 0)
2287 return -1;
1685 2288
2289 if (symbol_conf.use_modules && machine__create_modules(self) < 0)
2290 pr_debug("Problems creating module maps, continuing anyway...\n");
2291 /*
2292 * Now that we have all the maps created, just set the ->end of them:
2293 */
2294 map_groups__fixup_end(&self->kmaps);
1686 return 0; 2295 return 0;
1687} 2296}
1688 2297
@@ -1702,9 +2311,6 @@ static int vmlinux_path__init(void)
1702 struct utsname uts; 2311 struct utsname uts;
1703 char bf[PATH_MAX]; 2312 char bf[PATH_MAX];
1704 2313
1705 if (uname(&uts) < 0)
1706 return -1;
1707
1708 vmlinux_path = malloc(sizeof(char *) * 5); 2314 vmlinux_path = malloc(sizeof(char *) * 5);
1709 if (vmlinux_path == NULL) 2315 if (vmlinux_path == NULL)
1710 return -1; 2316 return -1;
@@ -1717,6 +2323,14 @@ static int vmlinux_path__init(void)
1717 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2323 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1718 goto out_fail; 2324 goto out_fail;
1719 ++vmlinux_path__nr_entries; 2325 ++vmlinux_path__nr_entries;
2326
2327 /* only try running kernel version if no symfs was given */
2328 if (symbol_conf.symfs[0] != 0)
2329 return 0;
2330
2331 if (uname(&uts) < 0)
2332 return -1;
2333
1720 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2334 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1721 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2335 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1722 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2336 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
@@ -1741,6 +2355,25 @@ out_fail:
1741 return -1; 2355 return -1;
1742} 2356}
1743 2357
2358size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp)
2359{
2360 int i;
2361 size_t printed = 0;
2362 struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso;
2363
2364 if (kdso->has_build_id) {
2365 char filename[PATH_MAX];
2366 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
2367 printed += fprintf(fp, "[0] %s\n", filename);
2368 }
2369
2370 for (i = 0; i < vmlinux_path__nr_entries; ++i)
2371 printed += fprintf(fp, "[%d] %s\n",
2372 i + kdso->has_build_id, vmlinux_path[i]);
2373
2374 return printed;
2375}
2376
1744static int setup_list(struct strlist **list, const char *list_str, 2377static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name) 2378 const char *list_name)
1746{ 2379{
@@ -1757,6 +2390,11 @@ static int setup_list(struct strlist **list, const char *list_str,
1757 2390
1758int symbol__init(void) 2391int symbol__init(void)
1759{ 2392{
2393 const char *symfs;
2394
2395 if (symbol_conf.initialized)
2396 return 0;
2397
1760 elf_version(EV_CURRENT); 2398 elf_version(EV_CURRENT);
1761 if (symbol_conf.sort_by_name) 2399 if (symbol_conf.sort_by_name)
1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 2400 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
@@ -1782,6 +2420,19 @@ int symbol__init(void)
1782 symbol_conf.sym_list_str, "symbol") < 0) 2420 symbol_conf.sym_list_str, "symbol") < 0)
1783 goto out_free_comm_list; 2421 goto out_free_comm_list;
1784 2422
2423 /*
2424 * A path to symbols of "/" is identical to ""
2425 * reset here for simplicity.
2426 */
2427 symfs = realpath(symbol_conf.symfs, NULL);
2428 if (symfs == NULL)
2429 symfs = symbol_conf.symfs;
2430 if (strcmp(symfs, "/") == 0)
2431 symbol_conf.symfs = "";
2432 if (symfs != symbol_conf.symfs)
2433 free((void *)symfs);
2434
2435 symbol_conf.initialized = true;
1785 return 0; 2436 return 0;
1786 2437
1787out_free_dso_list: 2438out_free_dso_list:
@@ -1791,19 +2442,154 @@ out_free_comm_list:
1791 return -1; 2442 return -1;
1792} 2443}
1793 2444
1794int perf_session__create_kernel_maps(struct perf_session *self) 2445void symbol__exit(void)
1795{ 2446{
1796 if (map_groups__create_kernel_maps(&self->kmaps, 2447 if (!symbol_conf.initialized)
1797 symbol_conf.vmlinux_name) < 0) 2448 return;
2449 strlist__delete(symbol_conf.sym_list);
2450 strlist__delete(symbol_conf.dso_list);
2451 strlist__delete(symbol_conf.comm_list);
2452 vmlinux_path__exit();
2453 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
2454 symbol_conf.initialized = false;
2455}
2456
2457int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
2458{
2459 struct machine *machine = machines__findnew(self, pid);
2460
2461 if (machine == NULL)
1798 return -1; 2462 return -1;
1799 2463
1800 if (symbol_conf.use_modules && 2464 return machine__create_kernel_maps(machine);
1801 perf_session__create_module_maps(self) < 0) 2465}
1802 pr_debug("Failed to load list of modules for session %s, " 2466
1803 "continuing...\n", self->filename); 2467static int hex(char ch)
1804 /* 2468{
1805 * Now that we have all the maps created, just set the ->end of them: 2469 if ((ch >= '0') && (ch <= '9'))
1806 */ 2470 return ch - '0';
1807 map_groups__fixup_end(&self->kmaps); 2471 if ((ch >= 'a') && (ch <= 'f'))
1808 return 0; 2472 return ch - 'a' + 10;
2473 if ((ch >= 'A') && (ch <= 'F'))
2474 return ch - 'A' + 10;
2475 return -1;
2476}
2477
2478/*
2479 * While we find nice hex chars, build a long_val.
2480 * Return number of chars processed.
2481 */
2482int hex2u64(const char *ptr, u64 *long_val)
2483{
2484 const char *p = ptr;
2485 *long_val = 0;
2486
2487 while (*p) {
2488 const int hex_val = hex(*p);
2489
2490 if (hex_val < 0)
2491 break;
2492
2493 *long_val = (*long_val << 4) | hex_val;
2494 p++;
2495 }
2496
2497 return p - ptr;
2498}
2499
2500char *strxfrchar(char *s, char from, char to)
2501{
2502 char *p = s;
2503
2504 while ((p = strchr(p, from)) != NULL)
2505 *p++ = to;
2506
2507 return s;
2508}
2509
2510int machines__create_guest_kernel_maps(struct rb_root *self)
2511{
2512 int ret = 0;
2513 struct dirent **namelist = NULL;
2514 int i, items = 0;
2515 char path[PATH_MAX];
2516 pid_t pid;
2517
2518 if (symbol_conf.default_guest_vmlinux_name ||
2519 symbol_conf.default_guest_modules ||
2520 symbol_conf.default_guest_kallsyms) {
2521 machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID);
2522 }
2523
2524 if (symbol_conf.guestmount) {
2525 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2526 if (items <= 0)
2527 return -ENOENT;
2528 for (i = 0; i < items; i++) {
2529 if (!isdigit(namelist[i]->d_name[0])) {
2530 /* Filter out . and .. */
2531 continue;
2532 }
2533 pid = atoi(namelist[i]->d_name);
2534 sprintf(path, "%s/%s/proc/kallsyms",
2535 symbol_conf.guestmount,
2536 namelist[i]->d_name);
2537 ret = access(path, R_OK);
2538 if (ret) {
2539 pr_debug("Can't access file %s\n", path);
2540 goto failure;
2541 }
2542 machines__create_kernel_maps(self, pid);
2543 }
2544failure:
2545 free(namelist);
2546 }
2547
2548 return ret;
2549}
2550
2551void machines__destroy_guest_kernel_maps(struct rb_root *self)
2552{
2553 struct rb_node *next = rb_first(self);
2554
2555 while (next) {
2556 struct machine *pos = rb_entry(next, struct machine, rb_node);
2557
2558 next = rb_next(&pos->rb_node);
2559 rb_erase(&pos->rb_node, self);
2560 machine__delete(pos);
2561 }
2562}
2563
2564int machine__load_kallsyms(struct machine *self, const char *filename,
2565 enum map_type type, symbol_filter_t filter)
2566{
2567 struct map *map = self->vmlinux_maps[type];
2568 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
2569
2570 if (ret > 0) {
2571 dso__set_loaded(map->dso, type);
2572 /*
2573 * Since /proc/kallsyms will have multiple sessions for the
2574 * kernel, with modules between them, fixup the end of all
2575 * sections.
2576 */
2577 __map_groups__fixup_end(&self->kmaps, type);
2578 }
2579
2580 return ret;
2581}
2582
2583int machine__load_vmlinux_path(struct machine *self, enum map_type type,
2584 symbol_filter_t filter)
2585{
2586 struct map *map = self->vmlinux_maps[type];
2587 int ret = dso__load_vmlinux_path(map->dso, map, filter);
2588
2589 if (ret > 0) {
2590 dso__set_loaded(map->dso, type);
2591 map__reloc_vmlinux(map);
2592 }
2593
2594 return ret;
1809} 2595}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8aded2356f79..670cd1c88f54 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -3,10 +3,11 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <stdbool.h> 5#include <stdbool.h>
6#include "types.h" 6#include <stdint.h>
7#include "map.h"
7#include <linux/list.h> 8#include <linux/list.h>
8#include <linux/rbtree.h> 9#include <linux/rbtree.h>
9#include "event.h" 10#include <stdio.h>
10 11
11#ifdef HAVE_CPLUS_DEMANGLE 12#ifdef HAVE_CPLUS_DEMANGLE
12extern char *cplus_demangle(const char *, int); 13extern char *cplus_demangle(const char *, int);
@@ -27,6 +28,9 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
27#endif 28#endif
28#endif 29#endif
29 30
31int hex2u64(const char *ptr, u64 *val);
32char *strxfrchar(char *s, char from, char to);
33
30/* 34/*
31 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; 35 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
32 * for newer versions we can use mmap to reduce memory usage: 36 * for newer versions we can use mmap to reduce memory usage:
@@ -42,13 +46,19 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
42#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 46#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
43#endif 47#endif
44 48
49#define BUILD_ID_SIZE 20
50
45struct symbol { 51struct symbol {
46 struct rb_node rb_node; 52 struct rb_node rb_node;
47 u64 start; 53 u64 start;
48 u64 end; 54 u64 end;
55 u16 namelen;
56 u8 binding;
49 char name[0]; 57 char name[0];
50}; 58};
51 59
60void symbol__delete(struct symbol *self);
61
52struct strlist; 62struct strlist;
53 63
54struct symbol_conf { 64struct symbol_conf {
@@ -58,16 +68,25 @@ struct symbol_conf {
58 sort_by_name, 68 sort_by_name,
59 show_nr_samples, 69 show_nr_samples,
60 use_callchain, 70 use_callchain,
61 exclude_other; 71 exclude_other,
72 show_cpu_utilization,
73 initialized;
62 const char *vmlinux_name, 74 const char *vmlinux_name,
75 *kallsyms_name,
76 *source_prefix,
63 *field_sep; 77 *field_sep;
64 char *dso_list_str, 78 const char *default_guest_vmlinux_name,
79 *default_guest_kallsyms,
80 *default_guest_modules;
81 const char *guestmount;
82 const char *dso_list_str,
65 *comm_list_str, 83 *comm_list_str,
66 *sym_list_str, 84 *sym_list_str,
67 *col_width_list_str; 85 *col_width_list_str;
68 struct strlist *dso_list, 86 struct strlist *dso_list,
69 *comm_list, 87 *comm_list,
70 *sym_list; 88 *sym_list;
89 const char *symfs;
71}; 90};
72 91
73extern struct symbol_conf symbol_conf; 92extern struct symbol_conf symbol_conf;
@@ -77,6 +96,19 @@ static inline void *symbol__priv(struct symbol *self)
77 return ((void *)self) - symbol_conf.priv_size; 96 return ((void *)self) - symbol_conf.priv_size;
78} 97}
79 98
99struct ref_reloc_sym {
100 const char *name;
101 u64 addr;
102 u64 unrelocated_addr;
103};
104
105struct map_symbol {
106 struct map *map;
107 struct symbol *sym;
108 bool unfolded;
109 bool has_children;
110};
111
80struct addr_location { 112struct addr_location {
81 struct thread *thread; 113 struct thread *thread;
82 struct map *map; 114 struct map *map;
@@ -84,58 +116,121 @@ struct addr_location {
84 u64 addr; 116 u64 addr;
85 char level; 117 char level;
86 bool filtered; 118 bool filtered;
119 u8 cpumode;
120 s32 cpu;
121};
122
123enum dso_kernel_type {
124 DSO_TYPE_USER = 0,
125 DSO_TYPE_KERNEL,
126 DSO_TYPE_GUEST_KERNEL
87}; 127};
88 128
89struct dso { 129struct dso {
90 struct list_head node; 130 struct list_head node;
91 struct rb_root symbols[MAP__NR_TYPES]; 131 struct rb_root symbols[MAP__NR_TYPES];
92 struct rb_root symbol_names[MAP__NR_TYPES]; 132 struct rb_root symbol_names[MAP__NR_TYPES];
133 enum dso_kernel_type kernel;
93 u8 adjust_symbols:1; 134 u8 adjust_symbols:1;
94 u8 slen_calculated:1; 135 u8 slen_calculated:1;
95 u8 has_build_id:1; 136 u8 has_build_id:1;
96 u8 kernel:1; 137 u8 hit:1;
138 u8 annotate_warned:1;
139 u8 sname_alloc:1;
140 u8 lname_alloc:1;
97 unsigned char origin; 141 unsigned char origin;
98 u8 sorted_by_name; 142 u8 sorted_by_name;
99 u8 loaded; 143 u8 loaded;
100 u8 build_id[BUILD_ID_SIZE]; 144 u8 build_id[BUILD_ID_SIZE];
101 u16 long_name_len;
102 const char *short_name; 145 const char *short_name;
103 char *long_name; 146 char *long_name;
147 u16 long_name_len;
148 u16 short_name_len;
104 char name[0]; 149 char name[0];
105}; 150};
106 151
107struct dso *dso__new(const char *name); 152struct dso *dso__new(const char *name);
153struct dso *dso__new_kernel(const char *name);
108void dso__delete(struct dso *self); 154void dso__delete(struct dso *self);
109 155
156int dso__name_len(const struct dso *self);
157
110bool dso__loaded(const struct dso *self, enum map_type type); 158bool dso__loaded(const struct dso *self, enum map_type type);
111bool dso__sorted_by_name(const struct dso *self, enum map_type type); 159bool dso__sorted_by_name(const struct dso *self, enum map_type type);
112 160
161static inline void dso__set_loaded(struct dso *self, enum map_type type)
162{
163 self->loaded |= (1 << type);
164}
165
113void dso__sort_by_name(struct dso *self, enum map_type type); 166void dso__sort_by_name(struct dso *self, enum map_type type);
114 167
115struct perf_session; 168struct dso *__dsos__findnew(struct list_head *head, const char *name);
169
170int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
171int dso__load_vmlinux(struct dso *self, struct map *map,
172 const char *vmlinux, symbol_filter_t filter);
173int dso__load_vmlinux_path(struct dso *self, struct map *map,
174 symbol_filter_t filter);
175int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
176 symbol_filter_t filter);
177int machine__load_kallsyms(struct machine *self, const char *filename,
178 enum map_type type, symbol_filter_t filter);
179int machine__load_vmlinux_path(struct machine *self, enum map_type type,
180 symbol_filter_t filter);
181
182size_t __dsos__fprintf(struct list_head *head, FILE *fp);
116 183
117struct dso *dsos__findnew(const char *name); 184size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits);
118int dso__load(struct dso *self, struct map *map, struct perf_session *session, 185size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp);
119 symbol_filter_t filter); 186size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits);
120void dsos__fprintf(FILE *fp);
121size_t dsos__fprintf_buildid(FILE *fp);
122 187
123size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 188size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
189size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp);
124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 190size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
191
192enum dso_origin {
193 DSO__ORIG_KERNEL = 0,
194 DSO__ORIG_GUEST_KERNEL,
195 DSO__ORIG_JAVA_JIT,
196 DSO__ORIG_BUILD_ID_CACHE,
197 DSO__ORIG_FEDORA,
198 DSO__ORIG_UBUNTU,
199 DSO__ORIG_BUILDID,
200 DSO__ORIG_DSO,
201 DSO__ORIG_GUEST_KMODULE,
202 DSO__ORIG_KMODULE,
203 DSO__ORIG_NOT_FOUND,
204};
205
125char dso__symtab_origin(const struct dso *self); 206char dso__symtab_origin(const struct dso *self);
207void dso__set_long_name(struct dso *self, char *name);
126void dso__set_build_id(struct dso *self, void *build_id); 208void dso__set_build_id(struct dso *self, void *build_id);
209void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine);
127struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 210struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
128struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 211struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name); 212 const char *name);
130 213
131int filename__read_build_id(const char *filename, void *bf, size_t size); 214int filename__read_build_id(const char *filename, void *bf, size_t size);
132int sysfs__read_build_id(const char *filename, void *bf, size_t size); 215int sysfs__read_build_id(const char *filename, void *bf, size_t size);
133bool dsos__read_build_ids(void); 216bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
134int build_id__sprintf(u8 *self, int len, char *bf); 217int build_id__sprintf(const u8 *self, int len, char *bf);
218int kallsyms__parse(const char *filename, void *arg,
219 int (*process_symbol)(void *arg, const char *name,
220 char type, u64 start, u64 end));
221
222void machine__destroy_kernel_maps(struct machine *self);
223int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);
224int machine__create_kernel_maps(struct machine *self);
225
226int machines__create_kernel_maps(struct rb_root *self, pid_t pid);
227int machines__create_guest_kernel_maps(struct rb_root *self);
228void machines__destroy_guest_kernel_maps(struct rb_root *self);
135 229
136int symbol__init(void); 230int symbol__init(void);
137int perf_session__create_kernel_maps(struct perf_session *self); 231void symbol__exit(void);
232bool symbol_type__is_a(char symbol_type, enum map_type map_type);
233
234size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp);
138 235
139extern struct list_head dsos__user, dsos__kernel;
140extern struct dso *vdso;
141#endif /* __PERF_SYMBOL */ 236#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 4a08dcf50b68..00f4eade2e3e 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,13 +7,59 @@
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9 9
10void map_groups__init(struct map_groups *self) 10/* Skip "." and ".." directories */
11static int filter(const struct dirent *dir)
11{ 12{
13 if (dir->d_name[0] == '.')
14 return 0;
15 else
16 return 1;
17}
18
19struct thread_map *thread_map__new_by_pid(pid_t pid)
20{
21 struct thread_map *threads;
22 char name[256];
23 int items;
24 struct dirent **namelist = NULL;
12 int i; 25 int i;
13 for (i = 0; i < MAP__NR_TYPES; ++i) { 26
14 self->maps[i] = RB_ROOT; 27 sprintf(name, "/proc/%d/task", pid);
15 INIT_LIST_HEAD(&self->removed_maps[i]); 28 items = scandir(name, &namelist, filter, NULL);
29 if (items <= 0)
30 return NULL;
31
32 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
33 if (threads != NULL) {
34 for (i = 0; i < items; i++)
35 threads->map[i] = atoi(namelist[i]->d_name);
36 threads->nr = items;
16 } 37 }
38
39 for (i=0; i<items; i++)
40 free(namelist[i]);
41 free(namelist);
42
43 return threads;
44}
45
46struct thread_map *thread_map__new_by_tid(pid_t tid)
47{
48 struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
49
50 if (threads != NULL) {
51 threads->map[0] = tid;
52 threads->nr = 1;
53 }
54
55 return threads;
56}
57
58struct thread_map *thread_map__new(pid_t pid, pid_t tid)
59{
60 if (pid != -1)
61 return thread_map__new_by_pid(pid);
62 return thread_map__new_by_tid(tid);
17} 63}
18 64
19static struct thread *thread__new(pid_t pid) 65static struct thread *thread__new(pid_t pid)
@@ -31,12 +77,26 @@ static struct thread *thread__new(pid_t pid)
31 return self; 77 return self;
32} 78}
33 79
80void thread__delete(struct thread *self)
81{
82 map_groups__exit(&self->mg);
83 free(self->comm);
84 free(self);
85}
86
34int thread__set_comm(struct thread *self, const char *comm) 87int thread__set_comm(struct thread *self, const char *comm)
35{ 88{
89 int err;
90
36 if (self->comm) 91 if (self->comm)
37 free(self->comm); 92 free(self->comm);
38 self->comm = strdup(comm); 93 self->comm = strdup(comm);
39 return self->comm ? 0 : -ENOMEM; 94 err = self->comm == NULL ? -ENOMEM : 0;
95 if (!err) {
96 self->comm_set = true;
97 map_groups__flush(&self->mg);
98 }
99 return err;
40} 100}
41 101
42int thread__comm_len(struct thread *self) 102int thread__comm_len(struct thread *self)
@@ -50,74 +110,10 @@ int thread__comm_len(struct thread *self)
50 return self->comm_len; 110 return self->comm_len;
51} 111}
52 112
53static const char *map_type__name[MAP__NR_TYPES] = {
54 [MAP__FUNCTION] = "Functions",
55 [MAP__VARIABLE] = "Variables",
56};
57
58static size_t __map_groups__fprintf_maps(struct map_groups *self,
59 enum map_type type, FILE *fp)
60{
61 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
62 struct rb_node *nd;
63
64 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
65 struct map *pos = rb_entry(nd, struct map, rb_node);
66 printed += fprintf(fp, "Map:");
67 printed += map__fprintf(pos, fp);
68 if (verbose > 1) {
69 printed += dso__fprintf(pos->dso, type, fp);
70 printed += fprintf(fp, "--\n");
71 }
72 }
73
74 return printed;
75}
76
77size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
78{
79 size_t printed = 0, i;
80 for (i = 0; i < MAP__NR_TYPES; ++i)
81 printed += __map_groups__fprintf_maps(self, i, fp);
82 return printed;
83}
84
85static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
86 enum map_type type, FILE *fp)
87{
88 struct map *pos;
89 size_t printed = 0;
90
91 list_for_each_entry(pos, &self->removed_maps[type], node) {
92 printed += fprintf(fp, "Map:");
93 printed += map__fprintf(pos, fp);
94 if (verbose > 1) {
95 printed += dso__fprintf(pos->dso, type, fp);
96 printed += fprintf(fp, "--\n");
97 }
98 }
99 return printed;
100}
101
102static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
103{
104 size_t printed = 0, i;
105 for (i = 0; i < MAP__NR_TYPES; ++i)
106 printed += __map_groups__fprintf_removed_maps(self, i, fp);
107 return printed;
108}
109
110static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
111{
112 size_t printed = map_groups__fprintf_maps(self, fp);
113 printed += fprintf(fp, "Removed maps:\n");
114 return printed + map_groups__fprintf_removed_maps(self, fp);
115}
116
117static size_t thread__fprintf(struct thread *self, FILE *fp) 113static size_t thread__fprintf(struct thread *self, FILE *fp)
118{ 114{
119 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + 115 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
120 map_groups__fprintf(&self->mg, fp); 116 map_groups__fprintf(&self->mg, verbose, fp);
121} 117}
122 118
123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) 119struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
@@ -159,107 +155,24 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
159 return th; 155 return th;
160} 156}
161 157
162static void map_groups__remove_overlappings(struct map_groups *self,
163 struct map *map)
164{
165 struct rb_root *root = &self->maps[map->type];
166 struct rb_node *next = rb_first(root);
167
168 while (next) {
169 struct map *pos = rb_entry(next, struct map, rb_node);
170 next = rb_next(&pos->rb_node);
171
172 if (!map__overlap(pos, map))
173 continue;
174
175 if (verbose >= 2) {
176 fputs("overlapping maps:\n", stderr);
177 map__fprintf(map, stderr);
178 map__fprintf(pos, stderr);
179 }
180
181 rb_erase(&pos->rb_node, root);
182 /*
183 * We may have references to this map, for instance in some
184 * hist_entry instances, so just move them to a separate
185 * list.
186 */
187 list_add_tail(&pos->node, &self->removed_maps[map->type]);
188 }
189}
190
191void maps__insert(struct rb_root *maps, struct map *map)
192{
193 struct rb_node **p = &maps->rb_node;
194 struct rb_node *parent = NULL;
195 const u64 ip = map->start;
196 struct map *m;
197
198 while (*p != NULL) {
199 parent = *p;
200 m = rb_entry(parent, struct map, rb_node);
201 if (ip < m->start)
202 p = &(*p)->rb_left;
203 else
204 p = &(*p)->rb_right;
205 }
206
207 rb_link_node(&map->rb_node, parent, p);
208 rb_insert_color(&map->rb_node, maps);
209}
210
211struct map *maps__find(struct rb_root *maps, u64 ip)
212{
213 struct rb_node **p = &maps->rb_node;
214 struct rb_node *parent = NULL;
215 struct map *m;
216
217 while (*p != NULL) {
218 parent = *p;
219 m = rb_entry(parent, struct map, rb_node);
220 if (ip < m->start)
221 p = &(*p)->rb_left;
222 else if (ip > m->end)
223 p = &(*p)->rb_right;
224 else
225 return m;
226 }
227
228 return NULL;
229}
230
231void thread__insert_map(struct thread *self, struct map *map) 158void thread__insert_map(struct thread *self, struct map *map)
232{ 159{
233 map_groups__remove_overlappings(&self->mg, map); 160 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr);
234 map_groups__insert(&self->mg, map); 161 map_groups__insert(&self->mg, map);
235} 162}
236 163
237/*
238 * XXX This should not really _copy_ te maps, but refcount them.
239 */
240static int map_groups__clone(struct map_groups *self,
241 struct map_groups *parent, enum map_type type)
242{
243 struct rb_node *nd;
244 for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
245 struct map *map = rb_entry(nd, struct map, rb_node);
246 struct map *new = map__clone(map);
247 if (new == NULL)
248 return -ENOMEM;
249 map_groups__insert(self, new);
250 }
251 return 0;
252}
253
254int thread__fork(struct thread *self, struct thread *parent) 164int thread__fork(struct thread *self, struct thread *parent)
255{ 165{
256 int i; 166 int i;
257 167
258 if (self->comm) 168 if (parent->comm_set) {
259 free(self->comm); 169 if (self->comm)
260 self->comm = strdup(parent->comm); 170 free(self->comm);
261 if (!self->comm) 171 self->comm = strdup(parent->comm);
262 return -ENOMEM; 172 if (!self->comm)
173 return -ENOMEM;
174 self->comm_set = true;
175 }
263 176
264 for (i = 0; i < MAP__NR_TYPES; ++i) 177 for (i = 0; i < MAP__NR_TYPES; ++i)
265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 178 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
@@ -280,16 +193,3 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
280 193
281 return ret; 194 return ret;
282} 195}
283
284struct symbol *map_groups__find_symbol(struct map_groups *self,
285 struct perf_session *session,
286 enum map_type type, u64 addr,
287 symbol_filter_t filter)
288{
289 struct map *map = map_groups__find(self, type, addr);
290
291 if (map != NULL)
292 return map__find_symbol(map, session, map->map_ip(map, addr), filter);
293
294 return NULL;
295}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index c206f72c8881..d7574101054a 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -5,66 +5,58 @@
5#include <unistd.h> 5#include <unistd.h>
6#include "symbol.h" 6#include "symbol.h"
7 7
8struct map_groups {
9 struct rb_root maps[MAP__NR_TYPES];
10 struct list_head removed_maps[MAP__NR_TYPES];
11};
12
13struct thread { 8struct thread {
14 struct rb_node rb_node; 9 union {
10 struct rb_node rb_node;
11 struct list_head node;
12 };
15 struct map_groups mg; 13 struct map_groups mg;
16 pid_t pid; 14 pid_t pid;
17 char shortname[3]; 15 char shortname[3];
16 bool comm_set;
18 char *comm; 17 char *comm;
19 int comm_len; 18 int comm_len;
20}; 19};
21 20
22void map_groups__init(struct map_groups *self); 21struct thread_map {
22 int nr;
23 int map[];
24};
25
26struct perf_session;
27
28void thread__delete(struct thread *self);
29
30struct thread_map *thread_map__new_by_pid(pid_t pid);
31struct thread_map *thread_map__new_by_tid(pid_t tid);
32struct thread_map *thread_map__new(pid_t pid, pid_t tid);
33
34static inline void thread_map__delete(struct thread_map *threads)
35{
36 free(threads);
37}
38
23int thread__set_comm(struct thread *self, const char *comm); 39int thread__set_comm(struct thread *self, const char *comm);
24int thread__comm_len(struct thread *self); 40int thread__comm_len(struct thread *self);
25struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 41struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
26void thread__insert_map(struct thread *self, struct map *map); 42void thread__insert_map(struct thread *self, struct map *map);
27int thread__fork(struct thread *self, struct thread *parent); 43int thread__fork(struct thread *self, struct thread *parent);
28size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp);
29size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 44size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
30 45
31void maps__insert(struct rb_root *maps, struct map *map);
32struct map *maps__find(struct rb_root *maps, u64 addr);
33
34static inline void map_groups__insert(struct map_groups *self, struct map *map)
35{
36 maps__insert(&self->maps[map->type], map);
37}
38
39static inline struct map *map_groups__find(struct map_groups *self,
40 enum map_type type, u64 addr)
41{
42 return maps__find(&self->maps[type], addr);
43}
44
45static inline struct map *thread__find_map(struct thread *self, 46static inline struct map *thread__find_map(struct thread *self,
46 enum map_type type, u64 addr) 47 enum map_type type, u64 addr)
47{ 48{
48 return self ? map_groups__find(&self->mg, type, addr) : NULL; 49 return self ? map_groups__find(&self->mg, type, addr) : NULL;
49} 50}
50 51
52void thread__find_addr_map(struct thread *self,
53 struct perf_session *session, u8 cpumode,
54 enum map_type type, pid_t pid, u64 addr,
55 struct addr_location *al);
56
51void thread__find_addr_location(struct thread *self, 57void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode, 58 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr, 59 enum map_type type, pid_t pid, u64 addr,
54 struct addr_location *al, 60 struct addr_location *al,
55 symbol_filter_t filter); 61 symbol_filter_t filter);
56struct symbol *map_groups__find_symbol(struct map_groups *self,
57 struct perf_session *session,
58 enum map_type type, u64 addr,
59 symbol_filter_t filter);
60
61static inline struct symbol *
62map_groups__find_function(struct map_groups *self, struct perf_session *session,
63 u64 addr, symbol_filter_t filter)
64{
65 return map_groups__find_symbol(self, session, MAP__FUNCTION, addr, filter);
66}
67
68struct map *map_groups__find_by_name(struct map_groups *self,
69 enum map_type type, const char *name);
70#endif /* __PERF_THREAD_H */ 62#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index cace35595530..35729f4c40cb 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -20,6 +20,7 @@
20 */ 20 */
21#define _GNU_SOURCE 21#define _GNU_SOURCE
22#include <dirent.h> 22#include <dirent.h>
23#include <mntent.h>
23#include <stdio.h> 24#include <stdio.h>
24#include <stdlib.h> 25#include <stdlib.h>
25#include <string.h> 26#include <string.h>
@@ -33,10 +34,13 @@
33#include <ctype.h> 34#include <ctype.h>
34#include <errno.h> 35#include <errno.h>
35#include <stdbool.h> 36#include <stdbool.h>
37#include <linux/list.h>
36#include <linux/kernel.h> 38#include <linux/kernel.h>
37 39
38#include "../perf.h" 40#include "../perf.h"
39#include "trace-event.h" 41#include "trace-event.h"
42#include "debugfs.h"
43#include "evsel.h"
40 44
41#define VERSION "0.5" 45#define VERSION "0.5"
42 46
@@ -101,32 +105,12 @@ void *malloc_or_die(unsigned int size)
101 105
102static const char *find_debugfs(void) 106static const char *find_debugfs(void)
103{ 107{
104 static char debugfs[MAX_PATH+1]; 108 const char *path = debugfs_mount(NULL);
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126 109
127 debugfs_found = 1; 110 if (!path)
111 die("Your kernel not support debugfs filesystem");
128 112
129 return debugfs; 113 return path;
130} 114}
131 115
132/* 116/*
@@ -172,10 +156,17 @@ static void put_tracing_file(char *file)
172 free(file); 156 free(file);
173} 157}
174 158
159static ssize_t calc_data_size;
160
175static ssize_t write_or_die(const void *buf, size_t len) 161static ssize_t write_or_die(const void *buf, size_t len)
176{ 162{
177 int ret; 163 int ret;
178 164
165 if (calc_data_size) {
166 calc_data_size += len;
167 return len;
168 }
169
179 ret = write(output_fd, buf, len); 170 ret = write(output_fd, buf, len);
180 if (ret < 0) 171 if (ret < 0)
181 die("writing to '%s'", output_file); 172 die("writing to '%s'", output_file);
@@ -271,6 +262,8 @@ static void read_header_files(void)
271 write_or_die("header_page", 12); 262 write_or_die("header_page", 12);
272 write_or_die(&size, 8); 263 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd); 264 check_size = copy_file_fd(fd);
265 close(fd);
266
274 if (size != check_size) 267 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld", 268 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size); 269 path, size, check_size);
@@ -289,6 +282,7 @@ static void read_header_files(void)
289 if (size != check_size) 282 if (size != check_size)
290 die("wrong size for '%s'", path); 283 die("wrong size for '%s'", path);
291 put_tracing_file(path); 284 put_tracing_file(path);
285 close(fd);
292} 286}
293 287
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 288static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -317,7 +311,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
317 die("can't read directory '%s'", sys); 311 die("can't read directory '%s'", sys);
318 312
319 while ((dent = readdir(dir))) { 313 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 || 314 if (dent->d_type != DT_DIR ||
315 strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 || 316 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps)) 317 !name_in_tp_list(dent->d_name, tps))
323 continue; 318 continue;
@@ -334,7 +329,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
334 329
335 rewinddir(dir); 330 rewinddir(dir);
336 while ((dent = readdir(dir))) { 331 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 || 332 if (dent->d_type != DT_DIR ||
333 strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 || 334 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps)) 335 !name_in_tp_list(dent->d_name, tps))
340 continue; 336 continue;
@@ -353,6 +349,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
353 349
354 free(format); 350 free(format);
355 } 351 }
352 closedir(dir);
356} 353}
357 354
358static void read_ftrace_files(struct tracepoint_path *tps) 355static void read_ftrace_files(struct tracepoint_path *tps)
@@ -394,26 +391,21 @@ static void read_event_files(struct tracepoint_path *tps)
394 die("can't read directory '%s'", path); 391 die("can't read directory '%s'", path);
395 392
396 while ((dent = readdir(dir))) { 393 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 || 394 if (dent->d_type != DT_DIR ||
395 strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 || 396 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 || 397 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps)) 398 !system_in_tp_list(dent->d_name, tps))
401 continue; 399 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 400 count++;
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 } 401 }
411 402
412 write_or_die(&count, 4); 403 write_or_die(&count, 4);
413 404
414 rewinddir(dir); 405 rewinddir(dir);
415 while ((dent = readdir(dir))) { 406 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 || 407 if (dent->d_type != DT_DIR ||
408 strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 || 409 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 || 410 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps)) 411 !system_in_tp_list(dent->d_name, tps))
@@ -422,14 +414,13 @@ static void read_event_files(struct tracepoint_path *tps)
422 sprintf(sys, "%s/%s", path, dent->d_name); 414 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st); 415 ret = stat(sys, &st);
424 if (ret >= 0) { 416 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) { 417 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 418 copy_event_system(sys, tps);
427 copy_event_system(sys, tps);
428 }
429 } 419 }
430 free(sys); 420 free(sys);
431 } 421 }
432 422
423 closedir(dir);
433 put_tracing_file(path); 424 put_tracing_file(path);
434} 425}
435 426
@@ -480,16 +471,17 @@ out:
480} 471}
481 472
482static struct tracepoint_path * 473static struct tracepoint_path *
483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events) 474get_tracepoints_path(struct list_head *pattrs)
484{ 475{
485 struct tracepoint_path path, *ppath = &path; 476 struct tracepoint_path path, *ppath = &path;
486 int i, nr_tracepoints = 0; 477 struct perf_evsel *pos;
478 int nr_tracepoints = 0;
487 479
488 for (i = 0; i < nb_events; i++) { 480 list_for_each_entry(pos, pattrs, node) {
489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT) 481 if (pos->attr.type != PERF_TYPE_TRACEPOINT)
490 continue; 482 continue;
491 ++nr_tracepoints; 483 ++nr_tracepoints;
492 ppath->next = tracepoint_id_to_path(pattrs[i].config); 484 ppath->next = tracepoint_id_to_path(pos->attr.config);
493 if (!ppath->next) 485 if (!ppath->next)
494 die("%s\n", "No memory to alloc tracepoints list"); 486 die("%s\n", "No memory to alloc tracepoints list");
495 ppath = ppath->next; 487 ppath = ppath->next;
@@ -498,10 +490,21 @@ get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
498 return nr_tracepoints > 0 ? path.next : NULL; 490 return nr_tracepoints > 0 ? path.next : NULL;
499} 491}
500 492
501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) 493bool have_tracepoints(struct list_head *pattrs)
494{
495 struct perf_evsel *pos;
496
497 list_for_each_entry(pos, pattrs, node)
498 if (pos->attr.type == PERF_TYPE_TRACEPOINT)
499 return true;
500
501 return false;
502}
503
504int read_tracing_data(int fd, struct list_head *pattrs)
502{ 505{
503 char buf[BUFSIZ]; 506 char buf[BUFSIZ];
504 struct tracepoint_path *tps = get_tracepoints_path(pattrs, nb_events); 507 struct tracepoint_path *tps = get_tracepoints_path(pattrs);
505 508
506 /* 509 /*
507 * What? No tracepoints? No sense writing anything here, bail out. 510 * What? No tracepoints? No sense writing anything here, bail out.
@@ -533,7 +536,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
533 write_or_die(buf, 1); 536 write_or_die(buf, 1);
534 537
535 /* save page_size */ 538 /* save page_size */
536 page_size = getpagesize(); 539 page_size = sysconf(_SC_PAGESIZE);
537 write_or_die(&page_size, 4); 540 write_or_die(&page_size, 4);
538 541
539 read_header_files(); 542 read_header_files();
@@ -544,3 +547,19 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
544 547
545 return 0; 548 return 0;
546} 549}
550
551ssize_t read_tracing_data_size(int fd, struct list_head *pattrs)
552{
553 ssize_t size;
554 int err = 0;
555
556 calc_data_size = 1;
557 err = read_tracing_data(fd, pattrs);
558 size = calc_data_size - 1;
559 calc_data_size = 0;
560
561 if (err < 0)
562 return err;
563
564 return size;
565}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index c5c32be040bf..73a02223c629 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -37,10 +37,12 @@ int header_page_ts_offset;
37int header_page_ts_size; 37int header_page_ts_size;
38int header_page_size_offset; 38int header_page_size_offset;
39int header_page_size_size; 39int header_page_size_size;
40int header_page_overwrite_offset;
41int header_page_overwrite_size;
40int header_page_data_offset; 42int header_page_data_offset;
41int header_page_data_size; 43int header_page_data_size;
42 44
43int latency_format; 45bool latency_format;
44 46
45static char *input_buf; 47static char *input_buf;
46static unsigned long long input_buf_ptr; 48static unsigned long long input_buf_ptr;
@@ -628,23 +630,32 @@ static int test_type(enum event_type type, enum event_type expect)
628 return 0; 630 return 0;
629} 631}
630 632
631static int test_type_token(enum event_type type, char *token, 633static int __test_type_token(enum event_type type, char *token,
632 enum event_type expect, const char *expect_tok) 634 enum event_type expect, const char *expect_tok,
635 bool warn)
633{ 636{
634 if (type != expect) { 637 if (type != expect) {
635 warning("Error: expected type %d but read %d", 638 if (warn)
636 expect, type); 639 warning("Error: expected type %d but read %d",
640 expect, type);
637 return -1; 641 return -1;
638 } 642 }
639 643
640 if (strcmp(token, expect_tok) != 0) { 644 if (strcmp(token, expect_tok) != 0) {
641 warning("Error: expected '%s' but read '%s'", 645 if (warn)
642 expect_tok, token); 646 warning("Error: expected '%s' but read '%s'",
647 expect_tok, token);
643 return -1; 648 return -1;
644 } 649 }
645 return 0; 650 return 0;
646} 651}
647 652
653static int test_type_token(enum event_type type, char *token,
654 enum event_type expect, const char *expect_tok)
655{
656 return __test_type_token(type, token, expect, expect_tok, true);
657}
658
648static int __read_expect_type(enum event_type expect, char **tok, int newline_ok) 659static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
649{ 660{
650 enum event_type type; 661 enum event_type type;
@@ -661,7 +672,8 @@ static int read_expect_type(enum event_type expect, char **tok)
661 return __read_expect_type(expect, tok, 1); 672 return __read_expect_type(expect, tok, 1);
662} 673}
663 674
664static int __read_expected(enum event_type expect, const char *str, int newline_ok) 675static int __read_expected(enum event_type expect, const char *str,
676 int newline_ok, bool warn)
665{ 677{
666 enum event_type type; 678 enum event_type type;
667 char *token; 679 char *token;
@@ -672,7 +684,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
672 else 684 else
673 type = read_token_item(&token); 685 type = read_token_item(&token);
674 686
675 ret = test_type_token(type, token, expect, str); 687 ret = __test_type_token(type, token, expect, str, warn);
676 688
677 free_token(token); 689 free_token(token);
678 690
@@ -681,12 +693,12 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
681 693
682static int read_expected(enum event_type expect, const char *str) 694static int read_expected(enum event_type expect, const char *str)
683{ 695{
684 return __read_expected(expect, str, 1); 696 return __read_expected(expect, str, 1, true);
685} 697}
686 698
687static int read_expected_item(enum event_type expect, const char *str) 699static int read_expected_item(enum event_type expect, const char *str)
688{ 700{
689 return __read_expected(expect, str, 0); 701 return __read_expected(expect, str, 0, true);
690} 702}
691 703
692static char *event_read_name(void) 704static char *event_read_name(void)
@@ -744,7 +756,7 @@ static int field_is_string(struct format_field *field)
744 756
745static int field_is_dynamic(struct format_field *field) 757static int field_is_dynamic(struct format_field *field)
746{ 758{
747 if (!strcmp(field->type, "__data_loc")) 759 if (!strncmp(field->type, "__data_loc", 10))
748 return 1; 760 return 1;
749 761
750 return 0; 762 return 0;
@@ -1925,6 +1937,15 @@ void *raw_field_ptr(struct event *event, const char *name, void *data)
1925 if (!field) 1937 if (!field)
1926 return NULL; 1938 return NULL;
1927 1939
1940 if (field->flags & FIELD_IS_DYNAMIC) {
1941 int offset;
1942
1943 offset = *(int *)(data + field->offset);
1944 offset &= 0xffff;
1945
1946 return data + offset;
1947 }
1948
1928 return data + field->offset; 1949 return data + field->offset;
1929} 1950}
1930 1951
@@ -3078,88 +3099,6 @@ static void print_args(struct print_arg *args)
3078 } 3099 }
3079} 3100}
3080 3101
3081static void parse_header_field(const char *field,
3082 int *offset, int *size)
3083{
3084 char *token;
3085 int type;
3086
3087 if (read_expected(EVENT_ITEM, "field") < 0)
3088 return;
3089 if (read_expected(EVENT_OP, ":") < 0)
3090 return;
3091
3092 /* type */
3093 if (read_expect_type(EVENT_ITEM, &token) < 0)
3094 goto fail;
3095 free_token(token);
3096
3097 if (read_expected(EVENT_ITEM, field) < 0)
3098 return;
3099 if (read_expected(EVENT_OP, ";") < 0)
3100 return;
3101 if (read_expected(EVENT_ITEM, "offset") < 0)
3102 return;
3103 if (read_expected(EVENT_OP, ":") < 0)
3104 return;
3105 if (read_expect_type(EVENT_ITEM, &token) < 0)
3106 goto fail;
3107 *offset = atoi(token);
3108 free_token(token);
3109 if (read_expected(EVENT_OP, ";") < 0)
3110 return;
3111 if (read_expected(EVENT_ITEM, "size") < 0)
3112 return;
3113 if (read_expected(EVENT_OP, ":") < 0)
3114 return;
3115 if (read_expect_type(EVENT_ITEM, &token) < 0)
3116 goto fail;
3117 *size = atoi(token);
3118 free_token(token);
3119 if (read_expected(EVENT_OP, ";") < 0)
3120 return;
3121 type = read_token(&token);
3122 if (type != EVENT_NEWLINE) {
3123 /* newer versions of the kernel have a "signed" type */
3124 if (type != EVENT_ITEM)
3125 goto fail;
3126
3127 if (strcmp(token, "signed") != 0)
3128 goto fail;
3129
3130 free_token(token);
3131
3132 if (read_expected(EVENT_OP, ":") < 0)
3133 return;
3134
3135 if (read_expect_type(EVENT_ITEM, &token))
3136 goto fail;
3137
3138 free_token(token);
3139 if (read_expected(EVENT_OP, ";") < 0)
3140 return;
3141
3142 if (read_expect_type(EVENT_NEWLINE, &token))
3143 goto fail;
3144 }
3145 fail:
3146 free_token(token);
3147}
3148
3149int parse_header_page(char *buf, unsigned long size)
3150{
3151 init_input_buf(buf, size);
3152
3153 parse_header_field("timestamp", &header_page_ts_offset,
3154 &header_page_ts_size);
3155 parse_header_field("commit", &header_page_size_offset,
3156 &header_page_size_size);
3157 parse_header_field("data", &header_page_data_offset,
3158 &header_page_data_size);
3159
3160 return 0;
3161}
3162
3163int parse_ftrace_file(char *buf, unsigned long size) 3102int parse_ftrace_file(char *buf, unsigned long size)
3164{ 3103{
3165 struct format_field *field; 3104 struct format_field *field;
@@ -3277,3 +3216,18 @@ void parse_set_info(int nr_cpus, int long_sz)
3277 cpus = nr_cpus; 3216 cpus = nr_cpus;
3278 long_size = long_sz; 3217 long_size = long_sz;
3279} 3218}
3219
3220int common_pc(struct scripting_context *context)
3221{
3222 return parse_common_pc(context->event_data);
3223}
3224
3225int common_flags(struct scripting_context *context)
3226{
3227 return parse_common_flags(context->event_data);
3228}
3229
3230int common_lock_depth(struct scripting_context *context)
3231{
3232 return parse_common_lock_depth(context->event_data);
3233}
diff --git a/tools/perf/util/trace-event-perl.h b/tools/perf/util/trace-event-perl.h
deleted file mode 100644
index e88fb26137bb..000000000000
--- a/tools/perf/util/trace-event-perl.h
+++ /dev/null
@@ -1,55 +0,0 @@
1#ifndef __PERF_TRACE_EVENT_PERL_H
2#define __PERF_TRACE_EVENT_PERL_H
3#ifdef NO_LIBPERL
4typedef int INTERP;
5#define dSP
6#define ENTER
7#define SAVETMPS
8#define PUTBACK
9#define SPAGAIN
10#define FREETMPS
11#define LEAVE
12#define SP
13#define ERRSV
14#define G_SCALAR (0)
15#define G_DISCARD (0)
16#define G_NOARGS (0)
17#define PUSHMARK(a)
18#define SvTRUE(a) (0)
19#define XPUSHs(s)
20#define sv_2mortal(a)
21#define newSVpv(a,b)
22#define newSVuv(a)
23#define newSViv(a)
24#define get_cv(a,b) (0)
25#define call_pv(a,b) (0)
26#define perl_alloc() (0)
27#define perl_construct(a) (0)
28#define perl_parse(a,b,c,d,e) (0)
29#define perl_run(a) (0)
30#define perl_destruct(a) (0)
31#define perl_free(a) (0)
32#define pTHX void
33#define CV void
34#define dXSUB_SYS
35#define pTHX_
36static inline void newXS(const char *a, void *b, const char *c) {}
37static void boot_Perf__Trace__Context(pTHX_ CV *cv) {}
38static void boot_DynaLoader(pTHX_ CV *cv) {}
39#else
40#include <EXTERN.h>
41#include <perl.h>
42void boot_Perf__Trace__Context(pTHX_ CV *cv);
43void boot_DynaLoader(pTHX_ CV *cv);
44typedef PerlInterpreter * INTERP;
45#endif
46
47struct scripting_context {
48 void *event_data;
49};
50
51int common_pc(struct scripting_context *context);
52int common_flags(struct scripting_context *context);
53int common_lock_depth(struct scripting_context *context);
54
55#endif /* __PERF_TRACE_EVENT_PERL_H */
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index 1744422cafcb..f55cc3a765a1 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -18,7 +18,7 @@
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */ 20 */
21#define _LARGEFILE64_SOURCE 21#define _FILE_OFFSET_BITS 64
22 22
23#include <dirent.h> 23#include <dirent.h>
24#include <stdio.h> 24#include <stdio.h>
@@ -50,17 +50,61 @@ static int long_size;
50 50
51static unsigned long page_size; 51static unsigned long page_size;
52 52
53static ssize_t calc_data_size;
54static bool repipe;
55
56static int do_read(int fd, void *buf, int size)
57{
58 int rsize = size;
59
60 while (size) {
61 int ret = read(fd, buf, size);
62
63 if (ret <= 0)
64 return -1;
65
66 if (repipe) {
67 int retw = write(STDOUT_FILENO, buf, ret);
68
69 if (retw <= 0 || retw != ret)
70 die("repiping input file");
71 }
72
73 size -= ret;
74 buf += ret;
75 }
76
77 return rsize;
78}
79
53static int read_or_die(void *data, int size) 80static int read_or_die(void *data, int size)
54{ 81{
55 int r; 82 int r;
56 83
57 r = read(input_fd, data, size); 84 r = do_read(input_fd, data, size);
58 if (r != size) 85 if (r <= 0)
59 die("reading input file (size expected=%d received=%d)", 86 die("reading input file (size expected=%d received=%d)",
60 size, r); 87 size, r);
88
89 if (calc_data_size)
90 calc_data_size += r;
91
61 return r; 92 return r;
62} 93}
63 94
95/* If it fails, the next read will report it */
96static void skip(int size)
97{
98 char buf[BUFSIZ];
99 int r;
100
101 while (size) {
102 r = size > BUFSIZ ? BUFSIZ : size;
103 read_or_die(buf, r);
104 size -= r;
105 };
106}
107
64static unsigned int read4(void) 108static unsigned int read4(void)
65{ 109{
66 unsigned int data; 110 unsigned int data;
@@ -82,57 +126,36 @@ static char *read_string(void)
82 char buf[BUFSIZ]; 126 char buf[BUFSIZ];
83 char *str = NULL; 127 char *str = NULL;
84 int size = 0; 128 int size = 0;
85 int i; 129 off_t r;
86 int r; 130 char c;
87 131
88 for (;;) { 132 for (;;) {
89 r = read(input_fd, buf, BUFSIZ); 133 r = read(input_fd, &c, 1);
90 if (r < 0) 134 if (r < 0)
91 die("reading input file"); 135 die("reading input file");
92 136
93 if (!r) 137 if (!r)
94 die("no data"); 138 die("no data");
95 139
96 for (i = 0; i < r; i++) { 140 if (repipe) {
97 if (!buf[i]) 141 int retw = write(STDOUT_FILENO, &c, 1);
98 break;
99 }
100 if (i < r)
101 break;
102 142
103 if (str) { 143 if (retw <= 0 || retw != r)
104 size += BUFSIZ; 144 die("repiping input file string");
105 str = realloc(str, size);
106 if (!str)
107 die("malloc of size %d", size);
108 memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
109 } else {
110 size = BUFSIZ;
111 str = malloc_or_die(size);
112 memcpy(str, buf, size);
113 } 145 }
114 }
115 146
116 /* trailing \0: */ 147 buf[size++] = c;
117 i++; 148
118 149 if (!c)
119 /* move the file descriptor to the end of the string */ 150 break;
120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0)
122 die("lseek");
123
124 if (str) {
125 size += i;
126 str = realloc(str, size);
127 if (!str)
128 die("malloc of size %d", size);
129 memcpy(str + (size - i), buf, i);
130 } else {
131 size = i;
132 str = malloc_or_die(i);
133 memcpy(str, buf, i);
134 } 151 }
135 152
153 if (calc_data_size)
154 calc_data_size += size;
155
156 str = malloc_or_die(size);
157 memcpy(str, buf, size);
158
136 return str; 159 return str;
137} 160}
138 161
@@ -174,7 +197,6 @@ static void read_ftrace_printk(void)
174static void read_header_files(void) 197static void read_header_files(void)
175{ 198{
176 unsigned long long size; 199 unsigned long long size;
177 char *header_page;
178 char *header_event; 200 char *header_event;
179 char buf[BUFSIZ]; 201 char buf[BUFSIZ];
180 202
@@ -184,10 +206,7 @@ static void read_header_files(void)
184 die("did not read header page"); 206 die("did not read header page");
185 207
186 size = read8(); 208 size = read8();
187 header_page = malloc_or_die(size); 209 skip(size);
188 read_or_die(header_page, size);
189 parse_header_page(header_page, size);
190 free(header_page);
191 210
192 /* 211 /*
193 * The size field in the page is of type long, 212 * The size field in the page is of type long,
@@ -282,8 +301,8 @@ static void update_cpu_data_index(int cpu)
282 301
283static void get_next_page(int cpu) 302static void get_next_page(int cpu)
284{ 303{
285 off64_t save_seek; 304 off_t save_seek;
286 off64_t ret; 305 off_t ret;
287 306
288 if (!cpu_data[cpu].page) 307 if (!cpu_data[cpu].page)
289 return; 308 return;
@@ -298,17 +317,17 @@ static void get_next_page(int cpu)
298 update_cpu_data_index(cpu); 317 update_cpu_data_index(cpu);
299 318
300 /* other parts of the code may expect the pointer to not move */ 319 /* other parts of the code may expect the pointer to not move */
301 save_seek = lseek64(input_fd, 0, SEEK_CUR); 320 save_seek = lseek(input_fd, 0, SEEK_CUR);
302 321
303 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 322 ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET);
304 if (ret < 0) 323 if (ret == (off_t)-1)
305 die("failed to lseek"); 324 die("failed to lseek");
306 ret = read(input_fd, cpu_data[cpu].page, page_size); 325 ret = read(input_fd, cpu_data[cpu].page, page_size);
307 if (ret < 0) 326 if (ret < 0)
308 die("failed to read page"); 327 die("failed to read page");
309 328
310 /* reset the file pointer back */ 329 /* reset the file pointer back */
311 lseek64(input_fd, save_seek, SEEK_SET); 330 lseek(input_fd, save_seek, SEEK_SET);
312 331
313 return; 332 return;
314 } 333 }
@@ -459,7 +478,7 @@ struct record *trace_read_data(int cpu)
459 return data; 478 return data;
460} 479}
461 480
462void trace_report(int fd) 481ssize_t trace_report(int fd, bool __repipe)
463{ 482{
464 char buf[BUFSIZ]; 483 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 }; 484 char test[] = { 23, 8, 68 };
@@ -467,6 +486,10 @@ void trace_report(int fd)
467 int show_version = 0; 486 int show_version = 0;
468 int show_funcs = 0; 487 int show_funcs = 0;
469 int show_printk = 0; 488 int show_printk = 0;
489 ssize_t size;
490
491 calc_data_size = 1;
492 repipe = __repipe;
470 493
471 input_fd = fd; 494 input_fd = fd;
472 495
@@ -499,14 +522,18 @@ void trace_report(int fd)
499 read_proc_kallsyms(); 522 read_proc_kallsyms();
500 read_ftrace_printk(); 523 read_ftrace_printk();
501 524
525 size = calc_data_size - 1;
526 calc_data_size = 0;
527 repipe = false;
528
502 if (show_funcs) { 529 if (show_funcs) {
503 print_funcs(); 530 print_funcs();
504 return; 531 return size;
505 } 532 }
506 if (show_printk) { 533 if (show_printk) {
507 print_printk(); 534 print_printk();
508 return; 535 return size;
509 } 536 }
510 537
511 return; 538 return size;
512} 539}
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
new file mode 100644
index 000000000000..f7af2fca965d
--- /dev/null
+++ b/tools/perf/util/trace-event-scripting.c
@@ -0,0 +1,167 @@
1/*
2 * trace-event-scripting. Scripting engine common and initialization code.
3 *
4 * Copyright (C) 2009-2010 Tom Zanussi <tzanussi@gmail.com>
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 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <ctype.h>
26#include <errno.h>
27
28#include "../perf.h"
29#include "util.h"
30#include "trace-event.h"
31
32struct scripting_context *scripting_context;
33
34static int stop_script_unsupported(void)
35{
36 return 0;
37}
38
39static void process_event_unsupported(int cpu __unused,
40 void *data __unused,
41 int size __unused,
42 unsigned long long nsecs __unused,
43 char *comm __unused)
44{
45}
46
47static void print_python_unsupported_msg(void)
48{
49 fprintf(stderr, "Python scripting not supported."
50 " Install libpython and rebuild perf to enable it.\n"
51 "For example:\n # apt-get install python-dev (ubuntu)"
52 "\n # yum install python-devel (Fedora)"
53 "\n etc.\n");
54}
55
56static int python_start_script_unsupported(const char *script __unused,
57 int argc __unused,
58 const char **argv __unused)
59{
60 print_python_unsupported_msg();
61
62 return -1;
63}
64
65static int python_generate_script_unsupported(const char *outfile __unused)
66{
67 print_python_unsupported_msg();
68
69 return -1;
70}
71
72struct scripting_ops python_scripting_unsupported_ops = {
73 .name = "Python",
74 .start_script = python_start_script_unsupported,
75 .stop_script = stop_script_unsupported,
76 .process_event = process_event_unsupported,
77 .generate_script = python_generate_script_unsupported,
78};
79
80static void register_python_scripting(struct scripting_ops *scripting_ops)
81{
82 int err;
83 err = script_spec_register("Python", scripting_ops);
84 if (err)
85 die("error registering Python script extension");
86
87 err = script_spec_register("py", scripting_ops);
88 if (err)
89 die("error registering py script extension");
90
91 scripting_context = malloc(sizeof(struct scripting_context));
92}
93
94#ifdef NO_LIBPYTHON
95void setup_python_scripting(void)
96{
97 register_python_scripting(&python_scripting_unsupported_ops);
98}
99#else
100extern struct scripting_ops python_scripting_ops;
101
102void setup_python_scripting(void)
103{
104 register_python_scripting(&python_scripting_ops);
105}
106#endif
107
108static void print_perl_unsupported_msg(void)
109{
110 fprintf(stderr, "Perl scripting not supported."
111 " Install libperl and rebuild perf to enable it.\n"
112 "For example:\n # apt-get install libperl-dev (ubuntu)"
113 "\n # yum install 'perl(ExtUtils::Embed)' (Fedora)"
114 "\n etc.\n");
115}
116
117static int perl_start_script_unsupported(const char *script __unused,
118 int argc __unused,
119 const char **argv __unused)
120{
121 print_perl_unsupported_msg();
122
123 return -1;
124}
125
126static int perl_generate_script_unsupported(const char *outfile __unused)
127{
128 print_perl_unsupported_msg();
129
130 return -1;
131}
132
133struct scripting_ops perl_scripting_unsupported_ops = {
134 .name = "Perl",
135 .start_script = perl_start_script_unsupported,
136 .stop_script = stop_script_unsupported,
137 .process_event = process_event_unsupported,
138 .generate_script = perl_generate_script_unsupported,
139};
140
141static void register_perl_scripting(struct scripting_ops *scripting_ops)
142{
143 int err;
144 err = script_spec_register("Perl", scripting_ops);
145 if (err)
146 die("error registering Perl script extension");
147
148 err = script_spec_register("pl", scripting_ops);
149 if (err)
150 die("error registering pl script extension");
151
152 scripting_context = malloc(sizeof(struct scripting_context));
153}
154
155#ifdef NO_LIBPERL
156void setup_perl_scripting(void)
157{
158 register_perl_scripting(&perl_scripting_unsupported_ops);
159}
160#else
161extern struct scripting_ops perl_scripting_ops;
162
163void setup_perl_scripting(void)
164{
165 register_perl_scripting(&perl_scripting_ops);
166}
167#endif
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 6ad405620c9b..b5f12ca24d99 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,6 +1,7 @@
1#ifndef __PERF_TRACE_EVENTS_H 1#ifndef __PERF_TRACE_EVENTS_H
2#define __PERF_TRACE_EVENTS_H 2#define __PERF_TRACE_EVENTS_H
3 3
4#include <stdbool.h>
4#include "parse-events.h" 5#include "parse-events.h"
5 6
6#define __unused __attribute__((unused)) 7#define __unused __attribute__((unused))
@@ -162,7 +163,7 @@ struct record *trace_read_data(int cpu);
162 163
163void parse_set_info(int nr_cpus, int long_sz); 164void parse_set_info(int nr_cpus, int long_sz);
164 165
165void trace_report(int fd); 166ssize_t trace_report(int fd, bool repipe);
166 167
167void *malloc_or_die(unsigned int size); 168void *malloc_or_die(unsigned int size);
168 169
@@ -232,7 +233,12 @@ static inline unsigned long long __data2host8(unsigned long long data)
232 233
233#define data2host2(ptr) __data2host2(*(unsigned short *)ptr) 234#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
234#define data2host4(ptr) __data2host4(*(unsigned int *)ptr) 235#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
235#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr) 236#define data2host8(ptr) ({ \
237 unsigned long long __val; \
238 \
239 memcpy(&__val, (ptr), sizeof(unsigned long long)); \
240 __data2host8(__val); \
241})
236 242
237extern int header_page_ts_offset; 243extern int header_page_ts_offset;
238extern int header_page_ts_size; 244extern int header_page_ts_size;
@@ -241,9 +247,8 @@ extern int header_page_size_size;
241extern int header_page_data_offset; 247extern int header_page_data_offset;
242extern int header_page_data_size; 248extern int header_page_data_size;
243 249
244extern int latency_format; 250extern bool latency_format;
245 251
246int parse_header_page(char *buf, unsigned long size);
247int trace_parse_common_type(void *data); 252int trace_parse_common_type(void *data);
248int trace_parse_common_pid(void *data); 253int trace_parse_common_pid(void *data);
249int parse_common_pc(void *data); 254int parse_common_pc(void *data);
@@ -257,7 +262,8 @@ raw_field_value(struct event *event, const char *name, void *data);
257void *raw_field_ptr(struct event *event, const char *name, void *data); 262void *raw_field_ptr(struct event *event, const char *name, void *data);
258unsigned long long eval_flag(const char *flag); 263unsigned long long eval_flag(const char *flag);
259 264
260int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events); 265int read_tracing_data(int fd, struct list_head *pattrs);
266ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
261 267
262/* taken from kernel/trace/trace.h */ 268/* taken from kernel/trace/trace.h */
263enum trace_flag_type { 269enum trace_flag_type {
@@ -279,7 +285,15 @@ struct scripting_ops {
279 285
280int script_spec_register(const char *spec, struct scripting_ops *ops); 286int script_spec_register(const char *spec, struct scripting_ops *ops);
281 287
282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void); 288void setup_perl_scripting(void);
289void setup_python_scripting(void);
290
291struct scripting_context {
292 void *event_data;
293};
294
295int common_pc(struct scripting_context *context);
296int common_flags(struct scripting_context *context);
297int common_lock_depth(struct scripting_context *context);
284 298
285#endif /* __PERF_TRACE_EVENTS_H */ 299#endif /* __PERF_TRACE_EVENTS_H */
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
new file mode 100644
index 000000000000..8bc010edca25
--- /dev/null
+++ b/tools/perf/util/ui/browser.c
@@ -0,0 +1,337 @@
1#include "libslang.h"
2#include <linux/compiler.h>
3#include <linux/list.h>
4#include <linux/rbtree.h>
5#include <stdlib.h>
6#include <sys/ttydefaults.h>
7#include "browser.h"
8#include "helpline.h"
9#include "../color.h"
10#include "../util.h"
11#include <stdio.h>
12
13static int ui_browser__percent_color(double percent, bool current)
14{
15 if (current)
16 return HE_COLORSET_SELECTED;
17 if (percent >= MIN_RED)
18 return HE_COLORSET_TOP;
19 if (percent >= MIN_GREEN)
20 return HE_COLORSET_MEDIUM;
21 return HE_COLORSET_NORMAL;
22}
23
24void ui_browser__set_color(struct ui_browser *self __used, int color)
25{
26 SLsmg_set_color(color);
27}
28
29void ui_browser__set_percent_color(struct ui_browser *self,
30 double percent, bool current)
31{
32 int color = ui_browser__percent_color(percent, current);
33 ui_browser__set_color(self, color);
34}
35
36void ui_browser__gotorc(struct ui_browser *self, int y, int x)
37{
38 SLsmg_gotorc(self->y + y, self->x + x);
39}
40
41void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
42{
43 struct list_head *head = self->entries;
44 struct list_head *pos;
45
46 switch (whence) {
47 case SEEK_SET:
48 pos = head->next;
49 break;
50 case SEEK_CUR:
51 pos = self->top;
52 break;
53 case SEEK_END:
54 pos = head->prev;
55 break;
56 default:
57 return;
58 }
59
60 if (offset > 0) {
61 while (offset-- != 0)
62 pos = pos->next;
63 } else {
64 while (offset++ != 0)
65 pos = pos->prev;
66 }
67
68 self->top = pos;
69}
70
71void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
72{
73 struct rb_root *root = self->entries;
74 struct rb_node *nd;
75
76 switch (whence) {
77 case SEEK_SET:
78 nd = rb_first(root);
79 break;
80 case SEEK_CUR:
81 nd = self->top;
82 break;
83 case SEEK_END:
84 nd = rb_last(root);
85 break;
86 default:
87 return;
88 }
89
90 if (offset > 0) {
91 while (offset-- != 0)
92 nd = rb_next(nd);
93 } else {
94 while (offset++ != 0)
95 nd = rb_prev(nd);
96 }
97
98 self->top = nd;
99}
100
101unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
102{
103 struct rb_node *nd;
104 int row = 0;
105
106 if (self->top == NULL)
107 self->top = rb_first(self->entries);
108
109 nd = self->top;
110
111 while (nd != NULL) {
112 ui_browser__gotorc(self, row, 0);
113 self->write(self, nd, row);
114 if (++row == self->height)
115 break;
116 nd = rb_next(nd);
117 }
118
119 return row;
120}
121
122bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
123{
124 return self->top_idx + row == self->index;
125}
126
127void ui_browser__refresh_dimensions(struct ui_browser *self)
128{
129 int cols, rows;
130 newtGetScreenSize(&cols, &rows);
131
132 self->width = cols - 1;
133 self->height = rows - 2;
134 self->y = 1;
135 self->x = 0;
136}
137
138void ui_browser__reset_index(struct ui_browser *self)
139{
140 self->index = self->top_idx = 0;
141 self->seek(self, 0, SEEK_SET);
142}
143
144void ui_browser__add_exit_key(struct ui_browser *self, int key)
145{
146 newtFormAddHotKey(self->form, key);
147}
148
149void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
150{
151 int i = 0;
152
153 while (keys[i] && i < 64) {
154 ui_browser__add_exit_key(self, keys[i]);
155 ++i;
156 }
157}
158
159int ui_browser__show(struct ui_browser *self, const char *title,
160 const char *helpline, ...)
161{
162 va_list ap;
163 int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP,
164 NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ',
165 NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 };
166
167 if (self->form != NULL)
168 newtFormDestroy(self->form);
169
170 ui_browser__refresh_dimensions(self);
171 self->form = newtForm(NULL, NULL, 0);
172 if (self->form == NULL)
173 return -1;
174
175 self->sb = newtVerticalScrollbar(self->width, 1, self->height,
176 HE_COLORSET_NORMAL,
177 HE_COLORSET_SELECTED);
178 if (self->sb == NULL)
179 return -1;
180
181 SLsmg_gotorc(0, 0);
182 ui_browser__set_color(self, NEWT_COLORSET_ROOT);
183 slsmg_write_nstring(title, self->width);
184
185 ui_browser__add_exit_keys(self, keys);
186 newtFormAddComponent(self->form, self->sb);
187
188 va_start(ap, helpline);
189 ui_helpline__vpush(helpline, ap);
190 va_end(ap);
191 return 0;
192}
193
194void ui_browser__hide(struct ui_browser *self)
195{
196 newtFormDestroy(self->form);
197 self->form = NULL;
198 ui_helpline__pop();
199}
200
201int ui_browser__refresh(struct ui_browser *self)
202{
203 int row;
204
205 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
206 row = self->refresh(self);
207 ui_browser__set_color(self, HE_COLORSET_NORMAL);
208 SLsmg_fill_region(self->y + row, self->x,
209 self->height - row, self->width, ' ');
210
211 return 0;
212}
213
214int ui_browser__run(struct ui_browser *self)
215{
216 struct newtExitStruct es;
217
218 if (ui_browser__refresh(self) < 0)
219 return -1;
220
221 while (1) {
222 off_t offset;
223
224 newtFormRun(self->form, &es);
225
226 if (es.reason != NEWT_EXIT_HOTKEY)
227 break;
228 switch (es.u.key) {
229 case NEWT_KEY_DOWN:
230 if (self->index == self->nr_entries - 1)
231 break;
232 ++self->index;
233 if (self->index == self->top_idx + self->height) {
234 ++self->top_idx;
235 self->seek(self, +1, SEEK_CUR);
236 }
237 break;
238 case NEWT_KEY_UP:
239 if (self->index == 0)
240 break;
241 --self->index;
242 if (self->index < self->top_idx) {
243 --self->top_idx;
244 self->seek(self, -1, SEEK_CUR);
245 }
246 break;
247 case NEWT_KEY_PGDN:
248 case ' ':
249 if (self->top_idx + self->height > self->nr_entries - 1)
250 break;
251
252 offset = self->height;
253 if (self->index + offset > self->nr_entries - 1)
254 offset = self->nr_entries - 1 - self->index;
255 self->index += offset;
256 self->top_idx += offset;
257 self->seek(self, +offset, SEEK_CUR);
258 break;
259 case NEWT_KEY_PGUP:
260 if (self->top_idx == 0)
261 break;
262
263 if (self->top_idx < self->height)
264 offset = self->top_idx;
265 else
266 offset = self->height;
267
268 self->index -= offset;
269 self->top_idx -= offset;
270 self->seek(self, -offset, SEEK_CUR);
271 break;
272 case NEWT_KEY_HOME:
273 ui_browser__reset_index(self);
274 break;
275 case NEWT_KEY_END:
276 offset = self->height - 1;
277 if (offset >= self->nr_entries)
278 offset = self->nr_entries - 1;
279
280 self->index = self->nr_entries - 1;
281 self->top_idx = self->index - offset;
282 self->seek(self, -offset, SEEK_END);
283 break;
284 default:
285 return es.u.key;
286 }
287 if (ui_browser__refresh(self) < 0)
288 return -1;
289 }
290 return -1;
291}
292
293unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
294{
295 struct list_head *pos;
296 struct list_head *head = self->entries;
297 int row = 0;
298
299 if (self->top == NULL || self->top == self->entries)
300 self->top = head->next;
301
302 pos = self->top;
303
304 list_for_each_from(pos, head) {
305 ui_browser__gotorc(self, row, 0);
306 self->write(self, pos, row);
307 if (++row == self->height)
308 break;
309 }
310
311 return row;
312}
313
314static struct newtPercentTreeColors {
315 const char *topColorFg, *topColorBg;
316 const char *mediumColorFg, *mediumColorBg;
317 const char *normalColorFg, *normalColorBg;
318 const char *selColorFg, *selColorBg;
319 const char *codeColorFg, *codeColorBg;
320} defaultPercentTreeColors = {
321 "red", "lightgray",
322 "green", "lightgray",
323 "black", "lightgray",
324 "lightgray", "magenta",
325 "blue", "lightgray",
326};
327
328void ui_browser__init(void)
329{
330 struct newtPercentTreeColors *c = &defaultPercentTreeColors;
331
332 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
333 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
334 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg);
335 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg);
336 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
337}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
new file mode 100644
index 000000000000..0dc7e4da36f5
--- /dev/null
+++ b/tools/perf/util/ui/browser.h
@@ -0,0 +1,51 @@
1#ifndef _PERF_UI_BROWSER_H_
2#define _PERF_UI_BROWSER_H_ 1
3
4#include <stdbool.h>
5#include <newt.h>
6#include <sys/types.h>
7#include "../types.h"
8
9#define HE_COLORSET_TOP 50
10#define HE_COLORSET_MEDIUM 51
11#define HE_COLORSET_NORMAL 52
12#define HE_COLORSET_SELECTED 53
13#define HE_COLORSET_CODE 54
14
15struct ui_browser {
16 newtComponent form, sb;
17 u64 index, top_idx;
18 void *top, *entries;
19 u16 y, x, width, height;
20 void *priv;
21 unsigned int (*refresh)(struct ui_browser *self);
22 void (*write)(struct ui_browser *self, void *entry, int row);
23 void (*seek)(struct ui_browser *self, off_t offset, int whence);
24 u32 nr_entries;
25};
26
27
28void ui_browser__set_color(struct ui_browser *self, int color);
29void ui_browser__set_percent_color(struct ui_browser *self,
30 double percent, bool current);
31bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
32void ui_browser__refresh_dimensions(struct ui_browser *self);
33void ui_browser__reset_index(struct ui_browser *self);
34
35void ui_browser__gotorc(struct ui_browser *self, int y, int x);
36void ui_browser__add_exit_key(struct ui_browser *self, int key);
37void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
38int ui_browser__show(struct ui_browser *self, const char *title,
39 const char *helpline, ...);
40void ui_browser__hide(struct ui_browser *self);
41int ui_browser__refresh(struct ui_browser *self);
42int ui_browser__run(struct ui_browser *self);
43
44void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
45unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
46
47void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence);
48unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
49
50void ui_browser__init(void);
51#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
new file mode 100644
index 000000000000..82b78f99251b
--- /dev/null
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -0,0 +1,237 @@
1#include "../browser.h"
2#include "../helpline.h"
3#include "../libslang.h"
4#include "../../hist.h"
5#include "../../sort.h"
6#include "../../symbol.h"
7
8static void ui__error_window(const char *fmt, ...)
9{
10 va_list ap;
11
12 va_start(ap, fmt);
13 newtWinMessagev((char *)"Error", (char *)"Ok", (char *)fmt, ap);
14 va_end(ap);
15}
16
17struct annotate_browser {
18 struct ui_browser b;
19 struct rb_root entries;
20 struct rb_node *curr_hot;
21};
22
23struct objdump_line_rb_node {
24 struct rb_node rb_node;
25 double percent;
26 u32 idx;
27};
28
29static inline
30struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
31{
32 return (struct objdump_line_rb_node *)(self + 1);
33}
34
35static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
36{
37 struct objdump_line *ol = rb_entry(entry, struct objdump_line, node);
38 bool current_entry = ui_browser__is_current_entry(self, row);
39 int width = self->width;
40
41 if (ol->offset != -1) {
42 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
43 ui_browser__set_percent_color(self, olrb->percent, current_entry);
44 slsmg_printf(" %7.2f ", olrb->percent);
45 if (!current_entry)
46 ui_browser__set_color(self, HE_COLORSET_CODE);
47 } else {
48 ui_browser__set_percent_color(self, 0, current_entry);
49 slsmg_write_nstring(" ", 9);
50 }
51
52 SLsmg_write_char(':');
53 slsmg_write_nstring(" ", 8);
54 if (!*ol->line)
55 slsmg_write_nstring(" ", width - 18);
56 else
57 slsmg_write_nstring(ol->line, width - 18);
58}
59
60static double objdump_line__calc_percent(struct objdump_line *self,
61 struct list_head *head,
62 struct symbol *sym)
63{
64 double percent = 0.0;
65
66 if (self->offset != -1) {
67 int len = sym->end - sym->start;
68 unsigned int hits = 0;
69 struct sym_priv *priv = symbol__priv(sym);
70 struct sym_ext *sym_ext = priv->ext;
71 struct sym_hist *h = priv->hist;
72 s64 offset = self->offset;
73 struct objdump_line *next = objdump__get_next_ip_line(head, self);
74
75
76 while (offset < (s64)len &&
77 (next == NULL || offset < next->offset)) {
78 if (sym_ext) {
79 percent += sym_ext[offset].percent;
80 } else
81 hits += h->ip[offset];
82
83 ++offset;
84 }
85
86 if (sym_ext == NULL && h->sum)
87 percent = 100.0 * hits / h->sum;
88 }
89
90 return percent;
91}
92
93static void objdump__insert_line(struct rb_root *self,
94 struct objdump_line_rb_node *line)
95{
96 struct rb_node **p = &self->rb_node;
97 struct rb_node *parent = NULL;
98 struct objdump_line_rb_node *l;
99
100 while (*p != NULL) {
101 parent = *p;
102 l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
103 if (line->percent < l->percent)
104 p = &(*p)->rb_left;
105 else
106 p = &(*p)->rb_right;
107 }
108 rb_link_node(&line->rb_node, parent, p);
109 rb_insert_color(&line->rb_node, self);
110}
111
112static void annotate_browser__set_top(struct annotate_browser *self,
113 struct rb_node *nd)
114{
115 struct objdump_line_rb_node *rbpos;
116 struct objdump_line *pos;
117 unsigned back;
118
119 ui_browser__refresh_dimensions(&self->b);
120 back = self->b.height / 2;
121 rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
122 pos = ((struct objdump_line *)rbpos) - 1;
123 self->b.top_idx = self->b.index = rbpos->idx;
124
125 while (self->b.top_idx != 0 && back != 0) {
126 pos = list_entry(pos->node.prev, struct objdump_line, node);
127
128 --self->b.top_idx;
129 --back;
130 }
131
132 self->b.top = pos;
133 self->curr_hot = nd;
134}
135
136static int annotate_browser__run(struct annotate_browser *self)
137{
138 struct rb_node *nd;
139 struct hist_entry *he = self->b.priv;
140 int key;
141
142 if (ui_browser__show(&self->b, he->ms.sym->name,
143 "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0)
144 return -1;
145 /*
146 * To allow builtin-annotate to cycle thru multiple symbols by
147 * examining the exit key for this function.
148 */
149 ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT);
150
151 nd = self->curr_hot;
152 if (nd) {
153 int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 };
154 ui_browser__add_exit_keys(&self->b, tabs);
155 }
156
157 while (1) {
158 key = ui_browser__run(&self->b);
159
160 switch (key) {
161 case NEWT_KEY_TAB:
162 nd = rb_prev(nd);
163 if (nd == NULL)
164 nd = rb_last(&self->entries);
165 annotate_browser__set_top(self, nd);
166 break;
167 case NEWT_KEY_UNTAB:
168 nd = rb_next(nd);
169 if (nd == NULL)
170 nd = rb_first(&self->entries);
171 annotate_browser__set_top(self, nd);
172 break;
173 default:
174 goto out;
175 }
176 }
177out:
178 ui_browser__hide(&self->b);
179 return key;
180}
181
182int hist_entry__tui_annotate(struct hist_entry *self)
183{
184 struct objdump_line *pos, *n;
185 struct objdump_line_rb_node *rbpos;
186 LIST_HEAD(head);
187 struct annotate_browser browser = {
188 .b = {
189 .entries = &head,
190 .refresh = ui_browser__list_head_refresh,
191 .seek = ui_browser__list_head_seek,
192 .write = annotate_browser__write,
193 .priv = self,
194 },
195 };
196 int ret;
197
198 if (self->ms.sym == NULL)
199 return -1;
200
201 if (self->ms.map->dso->annotate_warned)
202 return -1;
203
204 if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) {
205 ui__error_window(ui_helpline__last_msg);
206 return -1;
207 }
208
209 ui_helpline__push("Press <- or ESC to exit");
210
211 list_for_each_entry(pos, &head, node) {
212 size_t line_len = strlen(pos->line);
213 if (browser.b.width < line_len)
214 browser.b.width = line_len;
215 rbpos = objdump_line__rb(pos);
216 rbpos->idx = browser.b.nr_entries++;
217 rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym);
218 if (rbpos->percent < 0.01)
219 continue;
220 objdump__insert_line(&browser.entries, rbpos);
221 }
222
223 /*
224 * Position the browser at the hottest line.
225 */
226 browser.curr_hot = rb_last(&browser.entries);
227 if (browser.curr_hot)
228 annotate_browser__set_top(&browser, browser.curr_hot);
229
230 browser.b.width += 18; /* Percentage */
231 ret = annotate_browser__run(&browser);
232 list_for_each_entry_safe(pos, n, &head, node) {
233 list_del(&pos->node);
234 objdump_line__free(pos);
235 }
236 return ret;
237}
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
new file mode 100644
index 000000000000..ebda8c3fde9e
--- /dev/null
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -0,0 +1,1013 @@
1#define _GNU_SOURCE
2#include <stdio.h>
3#undef _GNU_SOURCE
4#include "../libslang.h"
5#include <stdlib.h>
6#include <string.h>
7#include <newt.h>
8#include <linux/rbtree.h>
9
10#include "../../hist.h"
11#include "../../pstack.h"
12#include "../../sort.h"
13#include "../../util.h"
14
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
18#include "map.h"
19
20struct hist_browser {
21 struct ui_browser b;
22 struct hists *hists;
23 struct hist_entry *he_selection;
24 struct map_symbol *selection;
25};
26
27static void hist_browser__refresh_dimensions(struct hist_browser *self)
28{
29 /* 3 == +/- toggle symbol before actual hist_entry rendering */
30 self->b.width = 3 + (hists__sort_list_width(self->hists) +
31 sizeof("[k]"));
32}
33
34static void hist_browser__reset(struct hist_browser *self)
35{
36 self->b.nr_entries = self->hists->nr_entries;
37 hist_browser__refresh_dimensions(self);
38 ui_browser__reset_index(&self->b);
39}
40
41static char tree__folded_sign(bool unfolded)
42{
43 return unfolded ? '-' : '+';
44}
45
46static char map_symbol__folded(const struct map_symbol *self)
47{
48 return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
49}
50
51static char hist_entry__folded(const struct hist_entry *self)
52{
53 return map_symbol__folded(&self->ms);
54}
55
56static char callchain_list__folded(const struct callchain_list *self)
57{
58 return map_symbol__folded(&self->ms);
59}
60
61static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
62{
63 self->unfolded = unfold ? self->has_children : false;
64}
65
66static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
67{
68 int n = 0;
69 struct rb_node *nd;
70
71 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
72 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
73 struct callchain_list *chain;
74 char folded_sign = ' '; /* No children */
75
76 list_for_each_entry(chain, &child->val, list) {
77 ++n;
78 /* We need this because we may not have children */
79 folded_sign = callchain_list__folded(chain);
80 if (folded_sign == '+')
81 break;
82 }
83
84 if (folded_sign == '-') /* Have children and they're unfolded */
85 n += callchain_node__count_rows_rb_tree(child);
86 }
87
88 return n;
89}
90
91static int callchain_node__count_rows(struct callchain_node *node)
92{
93 struct callchain_list *chain;
94 bool unfolded = false;
95 int n = 0;
96
97 list_for_each_entry(chain, &node->val, list) {
98 ++n;
99 unfolded = chain->ms.unfolded;
100 }
101
102 if (unfolded)
103 n += callchain_node__count_rows_rb_tree(node);
104
105 return n;
106}
107
108static int callchain__count_rows(struct rb_root *chain)
109{
110 struct rb_node *nd;
111 int n = 0;
112
113 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
114 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
115 n += callchain_node__count_rows(node);
116 }
117
118 return n;
119}
120
121static bool map_symbol__toggle_fold(struct map_symbol *self)
122{
123 if (!self->has_children)
124 return false;
125
126 self->unfolded = !self->unfolded;
127 return true;
128}
129
130static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
131{
132 struct rb_node *nd = rb_first(&self->rb_root);
133
134 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
135 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
136 struct callchain_list *chain;
137 bool first = true;
138
139 list_for_each_entry(chain, &child->val, list) {
140 if (first) {
141 first = false;
142 chain->ms.has_children = chain->list.next != &child->val ||
143 !RB_EMPTY_ROOT(&child->rb_root);
144 } else
145 chain->ms.has_children = chain->list.next == &child->val &&
146 !RB_EMPTY_ROOT(&child->rb_root);
147 }
148
149 callchain_node__init_have_children_rb_tree(child);
150 }
151}
152
153static void callchain_node__init_have_children(struct callchain_node *self)
154{
155 struct callchain_list *chain;
156
157 list_for_each_entry(chain, &self->val, list)
158 chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
159
160 callchain_node__init_have_children_rb_tree(self);
161}
162
163static void callchain__init_have_children(struct rb_root *self)
164{
165 struct rb_node *nd;
166
167 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
168 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
169 callchain_node__init_have_children(node);
170 }
171}
172
173static void hist_entry__init_have_children(struct hist_entry *self)
174{
175 if (!self->init_have_children) {
176 self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
177 callchain__init_have_children(&self->sorted_chain);
178 self->init_have_children = true;
179 }
180}
181
182static bool hist_browser__toggle_fold(struct hist_browser *self)
183{
184 if (map_symbol__toggle_fold(self->selection)) {
185 struct hist_entry *he = self->he_selection;
186
187 hist_entry__init_have_children(he);
188 self->hists->nr_entries -= he->nr_rows;
189
190 if (he->ms.unfolded)
191 he->nr_rows = callchain__count_rows(&he->sorted_chain);
192 else
193 he->nr_rows = 0;
194 self->hists->nr_entries += he->nr_rows;
195 self->b.nr_entries = self->hists->nr_entries;
196
197 return true;
198 }
199
200 /* If it doesn't have children, no toggling performed */
201 return false;
202}
203
204static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
205{
206 int n = 0;
207 struct rb_node *nd;
208
209 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
210 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
211 struct callchain_list *chain;
212 bool has_children = false;
213
214 list_for_each_entry(chain, &child->val, list) {
215 ++n;
216 map_symbol__set_folding(&chain->ms, unfold);
217 has_children = chain->ms.has_children;
218 }
219
220 if (has_children)
221 n += callchain_node__set_folding_rb_tree(child, unfold);
222 }
223
224 return n;
225}
226
227static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
228{
229 struct callchain_list *chain;
230 bool has_children = false;
231 int n = 0;
232
233 list_for_each_entry(chain, &node->val, list) {
234 ++n;
235 map_symbol__set_folding(&chain->ms, unfold);
236 has_children = chain->ms.has_children;
237 }
238
239 if (has_children)
240 n += callchain_node__set_folding_rb_tree(node, unfold);
241
242 return n;
243}
244
245static int callchain__set_folding(struct rb_root *chain, bool unfold)
246{
247 struct rb_node *nd;
248 int n = 0;
249
250 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
251 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
252 n += callchain_node__set_folding(node, unfold);
253 }
254
255 return n;
256}
257
258static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
259{
260 hist_entry__init_have_children(self);
261 map_symbol__set_folding(&self->ms, unfold);
262
263 if (self->ms.has_children) {
264 int n = callchain__set_folding(&self->sorted_chain, unfold);
265 self->nr_rows = unfold ? n : 0;
266 } else
267 self->nr_rows = 0;
268}
269
270static void hists__set_folding(struct hists *self, bool unfold)
271{
272 struct rb_node *nd;
273
274 self->nr_entries = 0;
275
276 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
277 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
278 hist_entry__set_folding(he, unfold);
279 self->nr_entries += 1 + he->nr_rows;
280 }
281}
282
283static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
284{
285 hists__set_folding(self->hists, unfold);
286 self->b.nr_entries = self->hists->nr_entries;
287 /* Go to the start, we may be way after valid entries after a collapse */
288 ui_browser__reset_index(&self->b);
289}
290
291static int hist_browser__run(struct hist_browser *self, const char *title)
292{
293 int key;
294 int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't',
295 NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, };
296
297 self->b.entries = &self->hists->entries;
298 self->b.nr_entries = self->hists->nr_entries;
299
300 hist_browser__refresh_dimensions(self);
301
302 if (ui_browser__show(&self->b, title,
303 "Press '?' for help on key bindings") < 0)
304 return -1;
305
306 ui_browser__add_exit_keys(&self->b, exit_keys);
307
308 while (1) {
309 key = ui_browser__run(&self->b);
310
311 switch (key) {
312 case 'D': { /* Debug */
313 static int seq;
314 struct hist_entry *h = rb_entry(self->b.top,
315 struct hist_entry, rb_node);
316 ui_helpline__pop();
317 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
318 seq++, self->b.nr_entries,
319 self->hists->nr_entries,
320 self->b.height,
321 self->b.index,
322 self->b.top_idx,
323 h->row_offset, h->nr_rows);
324 }
325 break;
326 case 'C':
327 /* Collapse the whole world. */
328 hist_browser__set_folding(self, false);
329 break;
330 case 'E':
331 /* Expand the whole world. */
332 hist_browser__set_folding(self, true);
333 break;
334 case NEWT_KEY_ENTER:
335 if (hist_browser__toggle_fold(self))
336 break;
337 /* fall thru */
338 default:
339 goto out;
340 }
341 }
342out:
343 ui_browser__hide(&self->b);
344 return key;
345}
346
347static char *callchain_list__sym_name(struct callchain_list *self,
348 char *bf, size_t bfsize)
349{
350 if (self->ms.sym)
351 return self->ms.sym->name;
352
353 snprintf(bf, bfsize, "%#Lx", self->ip);
354 return bf;
355}
356
357#define LEVEL_OFFSET_STEP 3
358
359static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
360 struct callchain_node *chain_node,
361 u64 total, int level,
362 unsigned short row,
363 off_t *row_offset,
364 bool *is_current_entry)
365{
366 struct rb_node *node;
367 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
368 u64 new_total, remaining;
369
370 if (callchain_param.mode == CHAIN_GRAPH_REL)
371 new_total = chain_node->children_hit;
372 else
373 new_total = total;
374
375 remaining = new_total;
376 node = rb_first(&chain_node->rb_root);
377 while (node) {
378 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
379 struct rb_node *next = rb_next(node);
380 u64 cumul = cumul_hits(child);
381 struct callchain_list *chain;
382 char folded_sign = ' ';
383 int first = true;
384 int extra_offset = 0;
385
386 remaining -= cumul;
387
388 list_for_each_entry(chain, &child->val, list) {
389 char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
390 const char *str;
391 int color;
392 bool was_first = first;
393
394 if (first)
395 first = false;
396 else
397 extra_offset = LEVEL_OFFSET_STEP;
398
399 folded_sign = callchain_list__folded(chain);
400 if (*row_offset != 0) {
401 --*row_offset;
402 goto do_next;
403 }
404
405 alloc_str = NULL;
406 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
407 if (was_first) {
408 double percent = cumul * 100.0 / new_total;
409
410 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
411 str = "Not enough memory!";
412 else
413 str = alloc_str;
414 }
415
416 color = HE_COLORSET_NORMAL;
417 width = self->b.width - (offset + extra_offset + 2);
418 if (ui_browser__is_current_entry(&self->b, row)) {
419 self->selection = &chain->ms;
420 color = HE_COLORSET_SELECTED;
421 *is_current_entry = true;
422 }
423
424 ui_browser__set_color(&self->b, color);
425 ui_browser__gotorc(&self->b, row, 0);
426 slsmg_write_nstring(" ", offset + extra_offset);
427 slsmg_printf("%c ", folded_sign);
428 slsmg_write_nstring(str, width);
429 free(alloc_str);
430
431 if (++row == self->b.height)
432 goto out;
433do_next:
434 if (folded_sign == '+')
435 break;
436 }
437
438 if (folded_sign == '-') {
439 const int new_level = level + (extra_offset ? 2 : 1);
440 row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
441 new_level, row, row_offset,
442 is_current_entry);
443 }
444 if (row == self->b.height)
445 goto out;
446 node = next;
447 }
448out:
449 return row - first_row;
450}
451
452static int hist_browser__show_callchain_node(struct hist_browser *self,
453 struct callchain_node *node,
454 int level, unsigned short row,
455 off_t *row_offset,
456 bool *is_current_entry)
457{
458 struct callchain_list *chain;
459 int first_row = row,
460 offset = level * LEVEL_OFFSET_STEP,
461 width = self->b.width - offset;
462 char folded_sign = ' ';
463
464 list_for_each_entry(chain, &node->val, list) {
465 char ipstr[BITS_PER_LONG / 4 + 1], *s;
466 int color;
467
468 folded_sign = callchain_list__folded(chain);
469
470 if (*row_offset != 0) {
471 --*row_offset;
472 continue;
473 }
474
475 color = HE_COLORSET_NORMAL;
476 if (ui_browser__is_current_entry(&self->b, row)) {
477 self->selection = &chain->ms;
478 color = HE_COLORSET_SELECTED;
479 *is_current_entry = true;
480 }
481
482 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
483 ui_browser__gotorc(&self->b, row, 0);
484 ui_browser__set_color(&self->b, color);
485 slsmg_write_nstring(" ", offset);
486 slsmg_printf("%c ", folded_sign);
487 slsmg_write_nstring(s, width - 2);
488
489 if (++row == self->b.height)
490 goto out;
491 }
492
493 if (folded_sign == '-')
494 row += hist_browser__show_callchain_node_rb_tree(self, node,
495 self->hists->stats.total_period,
496 level + 1, row,
497 row_offset,
498 is_current_entry);
499out:
500 return row - first_row;
501}
502
503static int hist_browser__show_callchain(struct hist_browser *self,
504 struct rb_root *chain,
505 int level, unsigned short row,
506 off_t *row_offset,
507 bool *is_current_entry)
508{
509 struct rb_node *nd;
510 int first_row = row;
511
512 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
513 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
514
515 row += hist_browser__show_callchain_node(self, node, level,
516 row, row_offset,
517 is_current_entry);
518 if (row == self->b.height)
519 break;
520 }
521
522 return row - first_row;
523}
524
525static int hist_browser__show_entry(struct hist_browser *self,
526 struct hist_entry *entry,
527 unsigned short row)
528{
529 char s[256];
530 double percent;
531 int printed = 0;
532 int color, width = self->b.width;
533 char folded_sign = ' ';
534 bool current_entry = ui_browser__is_current_entry(&self->b, row);
535 off_t row_offset = entry->row_offset;
536
537 if (current_entry) {
538 self->he_selection = entry;
539 self->selection = &entry->ms;
540 }
541
542 if (symbol_conf.use_callchain) {
543 hist_entry__init_have_children(entry);
544 folded_sign = hist_entry__folded(entry);
545 }
546
547 if (row_offset == 0) {
548 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false,
549 0, false, self->hists->stats.total_period);
550 percent = (entry->period * 100.0) / self->hists->stats.total_period;
551
552 color = HE_COLORSET_SELECTED;
553 if (!current_entry) {
554 if (percent >= MIN_RED)
555 color = HE_COLORSET_TOP;
556 else if (percent >= MIN_GREEN)
557 color = HE_COLORSET_MEDIUM;
558 else
559 color = HE_COLORSET_NORMAL;
560 }
561
562 ui_browser__set_color(&self->b, color);
563 ui_browser__gotorc(&self->b, row, 0);
564 if (symbol_conf.use_callchain) {
565 slsmg_printf("%c ", folded_sign);
566 width -= 2;
567 }
568 slsmg_write_nstring(s, width);
569 ++row;
570 ++printed;
571 } else
572 --row_offset;
573
574 if (folded_sign == '-' && row != self->b.height) {
575 printed += hist_browser__show_callchain(self, &entry->sorted_chain,
576 1, row, &row_offset,
577 &current_entry);
578 if (current_entry)
579 self->he_selection = entry;
580 }
581
582 return printed;
583}
584
585static unsigned int hist_browser__refresh(struct ui_browser *self)
586{
587 unsigned row = 0;
588 struct rb_node *nd;
589 struct hist_browser *hb = container_of(self, struct hist_browser, b);
590
591 if (self->top == NULL)
592 self->top = rb_first(&hb->hists->entries);
593
594 for (nd = self->top; nd; nd = rb_next(nd)) {
595 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
596
597 if (h->filtered)
598 continue;
599
600 row += hist_browser__show_entry(hb, h, row);
601 if (row == self->height)
602 break;
603 }
604
605 return row;
606}
607
608static struct rb_node *hists__filter_entries(struct rb_node *nd)
609{
610 while (nd != NULL) {
611 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
612 if (!h->filtered)
613 return nd;
614
615 nd = rb_next(nd);
616 }
617
618 return NULL;
619}
620
621static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
622{
623 while (nd != NULL) {
624 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
625 if (!h->filtered)
626 return nd;
627
628 nd = rb_prev(nd);
629 }
630
631 return NULL;
632}
633
634static void ui_browser__hists_seek(struct ui_browser *self,
635 off_t offset, int whence)
636{
637 struct hist_entry *h;
638 struct rb_node *nd;
639 bool first = true;
640
641 switch (whence) {
642 case SEEK_SET:
643 nd = hists__filter_entries(rb_first(self->entries));
644 break;
645 case SEEK_CUR:
646 nd = self->top;
647 goto do_offset;
648 case SEEK_END:
649 nd = hists__filter_prev_entries(rb_last(self->entries));
650 first = false;
651 break;
652 default:
653 return;
654 }
655
656 /*
657 * Moves not relative to the first visible entry invalidates its
658 * row_offset:
659 */
660 h = rb_entry(self->top, struct hist_entry, rb_node);
661 h->row_offset = 0;
662
663 /*
664 * Here we have to check if nd is expanded (+), if it is we can't go
665 * the next top level hist_entry, instead we must compute an offset of
666 * what _not_ to show and not change the first visible entry.
667 *
668 * This offset increments when we are going from top to bottom and
669 * decreases when we're going from bottom to top.
670 *
671 * As we don't have backpointers to the top level in the callchains
672 * structure, we need to always print the whole hist_entry callchain,
673 * skipping the first ones that are before the first visible entry
674 * and stop when we printed enough lines to fill the screen.
675 */
676do_offset:
677 if (offset > 0) {
678 do {
679 h = rb_entry(nd, struct hist_entry, rb_node);
680 if (h->ms.unfolded) {
681 u16 remaining = h->nr_rows - h->row_offset;
682 if (offset > remaining) {
683 offset -= remaining;
684 h->row_offset = 0;
685 } else {
686 h->row_offset += offset;
687 offset = 0;
688 self->top = nd;
689 break;
690 }
691 }
692 nd = hists__filter_entries(rb_next(nd));
693 if (nd == NULL)
694 break;
695 --offset;
696 self->top = nd;
697 } while (offset != 0);
698 } else if (offset < 0) {
699 while (1) {
700 h = rb_entry(nd, struct hist_entry, rb_node);
701 if (h->ms.unfolded) {
702 if (first) {
703 if (-offset > h->row_offset) {
704 offset += h->row_offset;
705 h->row_offset = 0;
706 } else {
707 h->row_offset += offset;
708 offset = 0;
709 self->top = nd;
710 break;
711 }
712 } else {
713 if (-offset > h->nr_rows) {
714 offset += h->nr_rows;
715 h->row_offset = 0;
716 } else {
717 h->row_offset = h->nr_rows + offset;
718 offset = 0;
719 self->top = nd;
720 break;
721 }
722 }
723 }
724
725 nd = hists__filter_prev_entries(rb_prev(nd));
726 if (nd == NULL)
727 break;
728 ++offset;
729 self->top = nd;
730 if (offset == 0) {
731 /*
732 * Last unfiltered hist_entry, check if it is
733 * unfolded, if it is then we should have
734 * row_offset at its last entry.
735 */
736 h = rb_entry(nd, struct hist_entry, rb_node);
737 if (h->ms.unfolded)
738 h->row_offset = h->nr_rows;
739 break;
740 }
741 first = false;
742 }
743 } else {
744 self->top = nd;
745 h = rb_entry(nd, struct hist_entry, rb_node);
746 h->row_offset = 0;
747 }
748}
749
750static struct hist_browser *hist_browser__new(struct hists *hists)
751{
752 struct hist_browser *self = zalloc(sizeof(*self));
753
754 if (self) {
755 self->hists = hists;
756 self->b.refresh = hist_browser__refresh;
757 self->b.seek = ui_browser__hists_seek;
758 }
759
760 return self;
761}
762
763static void hist_browser__delete(struct hist_browser *self)
764{
765 free(self);
766}
767
768static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
769{
770 return self->he_selection;
771}
772
773static struct thread *hist_browser__selected_thread(struct hist_browser *self)
774{
775 return self->he_selection->thread;
776}
777
778static int hists__browser_title(struct hists *self, char *bf, size_t size,
779 const char *ev_name, const struct dso *dso,
780 const struct thread *thread)
781{
782 char unit;
783 int printed;
784 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
785
786 nr_events = convert_unit(nr_events, &unit);
787 printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
788
789 if (thread)
790 printed += snprintf(bf + printed, size - printed,
791 ", Thread: %s(%d)",
792 (thread->comm_set ? thread->comm : ""),
793 thread->pid);
794 if (dso)
795 printed += snprintf(bf + printed, size - printed,
796 ", DSO: %s", dso->short_name);
797 return printed;
798}
799
800int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
801{
802 struct hist_browser *browser = hist_browser__new(self);
803 struct pstack *fstack;
804 const struct thread *thread_filter = NULL;
805 const struct dso *dso_filter = NULL;
806 char msg[160];
807 int key = -1;
808
809 if (browser == NULL)
810 return -1;
811
812 fstack = pstack__new(2);
813 if (fstack == NULL)
814 goto out;
815
816 ui_helpline__push(helpline);
817
818 hists__browser_title(self, msg, sizeof(msg), ev_name,
819 dso_filter, thread_filter);
820 while (1) {
821 const struct thread *thread;
822 const struct dso *dso;
823 char *options[16];
824 int nr_options = 0, choice = 0, i,
825 annotate = -2, zoom_dso = -2, zoom_thread = -2,
826 browse_map = -2;
827
828 key = hist_browser__run(browser, msg);
829
830 thread = hist_browser__selected_thread(browser);
831 dso = browser->selection->map ? browser->selection->map->dso : NULL;
832
833 switch (key) {
834 case NEWT_KEY_TAB:
835 case NEWT_KEY_UNTAB:
836 /*
837 * Exit the browser, let hists__browser_tree
838 * go to the next or previous
839 */
840 goto out_free_stack;
841 case 'a':
842 if (browser->selection->map == NULL &&
843 browser->selection->map->dso->annotate_warned)
844 continue;
845 goto do_annotate;
846 case 'd':
847 goto zoom_dso;
848 case 't':
849 goto zoom_thread;
850 case NEWT_KEY_F1:
851 case 'h':
852 case '?':
853 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
854 "<- Zoom out\n"
855 "a Annotate current symbol\n"
856 "h/?/F1 Show this window\n"
857 "C Collapse all callchains\n"
858 "E Expand all callchains\n"
859 "d Zoom into current DSO\n"
860 "t Zoom into current Thread\n"
861 "q/CTRL+C Exit browser");
862 continue;
863 case NEWT_KEY_ENTER:
864 case NEWT_KEY_RIGHT:
865 /* menu */
866 break;
867 case NEWT_KEY_LEFT: {
868 const void *top;
869
870 if (pstack__empty(fstack))
871 continue;
872 top = pstack__pop(fstack);
873 if (top == &dso_filter)
874 goto zoom_out_dso;
875 if (top == &thread_filter)
876 goto zoom_out_thread;
877 continue;
878 }
879 case NEWT_KEY_ESCAPE:
880 if (!ui__dialog_yesno("Do you really want to exit?"))
881 continue;
882 /* Fall thru */
883 default:
884 goto out_free_stack;
885 }
886
887 if (browser->selection->sym != NULL &&
888 !browser->selection->map->dso->annotate_warned &&
889 asprintf(&options[nr_options], "Annotate %s",
890 browser->selection->sym->name) > 0)
891 annotate = nr_options++;
892
893 if (thread != NULL &&
894 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
895 (thread_filter ? "out of" : "into"),
896 (thread->comm_set ? thread->comm : ""),
897 thread->pid) > 0)
898 zoom_thread = nr_options++;
899
900 if (dso != NULL &&
901 asprintf(&options[nr_options], "Zoom %s %s DSO",
902 (dso_filter ? "out of" : "into"),
903 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
904 zoom_dso = nr_options++;
905
906 if (browser->selection->map != NULL &&
907 asprintf(&options[nr_options], "Browse map details") > 0)
908 browse_map = nr_options++;
909
910 options[nr_options++] = (char *)"Exit";
911
912 choice = ui__popup_menu(nr_options, options);
913
914 for (i = 0; i < nr_options - 1; ++i)
915 free(options[i]);
916
917 if (choice == nr_options - 1)
918 break;
919
920 if (choice == -1)
921 continue;
922
923 if (choice == annotate) {
924 struct hist_entry *he;
925do_annotate:
926 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
927 browser->selection->map->dso->annotate_warned = 1;
928 ui_helpline__puts("No vmlinux file found, can't "
929 "annotate with just a "
930 "kallsyms file");
931 continue;
932 }
933
934 he = hist_browser__selected_entry(browser);
935 if (he == NULL)
936 continue;
937
938 hist_entry__tui_annotate(he);
939 } else if (choice == browse_map)
940 map__browse(browser->selection->map);
941 else if (choice == zoom_dso) {
942zoom_dso:
943 if (dso_filter) {
944 pstack__remove(fstack, &dso_filter);
945zoom_out_dso:
946 ui_helpline__pop();
947 dso_filter = NULL;
948 } else {
949 if (dso == NULL)
950 continue;
951 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
952 dso->kernel ? "the Kernel" : dso->short_name);
953 dso_filter = dso;
954 pstack__push(fstack, &dso_filter);
955 }
956 hists__filter_by_dso(self, dso_filter);
957 hists__browser_title(self, msg, sizeof(msg), ev_name,
958 dso_filter, thread_filter);
959 hist_browser__reset(browser);
960 } else if (choice == zoom_thread) {
961zoom_thread:
962 if (thread_filter) {
963 pstack__remove(fstack, &thread_filter);
964zoom_out_thread:
965 ui_helpline__pop();
966 thread_filter = NULL;
967 } else {
968 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
969 thread->comm_set ? thread->comm : "",
970 thread->pid);
971 thread_filter = thread;
972 pstack__push(fstack, &thread_filter);
973 }
974 hists__filter_by_thread(self, thread_filter);
975 hists__browser_title(self, msg, sizeof(msg), ev_name,
976 dso_filter, thread_filter);
977 hist_browser__reset(browser);
978 }
979 }
980out_free_stack:
981 pstack__delete(fstack);
982out:
983 hist_browser__delete(browser);
984 return key;
985}
986
987int hists__tui_browse_tree(struct rb_root *self, const char *help)
988{
989 struct rb_node *first = rb_first(self), *nd = first, *next;
990 int key = 0;
991
992 while (nd) {
993 struct hists *hists = rb_entry(nd, struct hists, rb_node);
994 const char *ev_name = __event_name(hists->type, hists->config);
995
996 key = hists__browse(hists, help, ev_name);
997 switch (key) {
998 case NEWT_KEY_TAB:
999 next = rb_next(nd);
1000 if (next)
1001 nd = next;
1002 break;
1003 case NEWT_KEY_UNTAB:
1004 if (nd == first)
1005 continue;
1006 nd = rb_prev(nd);
1007 default:
1008 return key;
1009 }
1010 }
1011
1012 return key;
1013}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
new file mode 100644
index 000000000000..e35437dfa5b4
--- /dev/null
+++ b/tools/perf/util/ui/browsers/map.c
@@ -0,0 +1,155 @@
1#include "../libslang.h"
2#include <elf.h>
3#include <sys/ttydefaults.h>
4#include <ctype.h>
5#include <string.h>
6#include <linux/bitops.h>
7#include "../../debug.h"
8#include "../../symbol.h"
9#include "../browser.h"
10#include "../helpline.h"
11#include "map.h"
12
13static int ui_entry__read(const char *title, char *bf, size_t size, int width)
14{
15 struct newtExitStruct es;
16 newtComponent form, entry;
17 const char *result;
18 int err = -1;
19
20 newtCenteredWindow(width, 1, title);
21 form = newtForm(NULL, NULL, 0);
22 if (form == NULL)
23 return -1;
24
25 entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
26 if (entry == NULL)
27 goto out_free_form;
28
29 newtFormAddComponent(form, entry);
30 newtFormAddHotKey(form, NEWT_KEY_ENTER);
31 newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
32 newtFormAddHotKey(form, NEWT_KEY_LEFT);
33 newtFormAddHotKey(form, CTRL('c'));
34 newtFormRun(form, &es);
35
36 if (result != NULL) {
37 strncpy(bf, result, size);
38 err = 0;
39 }
40out_free_form:
41 newtPopWindow();
42 newtFormDestroy(form);
43 return 0;
44}
45
46struct map_browser {
47 struct ui_browser b;
48 struct map *map;
49 u8 addrlen;
50};
51
52static void map_browser__write(struct ui_browser *self, void *nd, int row)
53{
54 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
55 struct map_browser *mb = container_of(self, struct map_browser, b);
56 bool current_entry = ui_browser__is_current_entry(self, row);
57 int width;
58
59 ui_browser__set_percent_color(self, 0, current_entry);
60 slsmg_printf("%*llx %*llx %c ",
61 mb->addrlen, sym->start, mb->addrlen, sym->end,
62 sym->binding == STB_GLOBAL ? 'g' :
63 sym->binding == STB_LOCAL ? 'l' : 'w');
64 width = self->width - ((mb->addrlen * 2) + 4);
65 if (width > 0)
66 slsmg_write_nstring(sym->name, width);
67}
68
69/* FIXME uber-kludgy, see comment on cmd_report... */
70static u32 *symbol__browser_index(struct symbol *self)
71{
72 return ((void *)self) - sizeof(struct rb_node) - sizeof(u32);
73}
74
75static int map_browser__search(struct map_browser *self)
76{
77 char target[512];
78 struct symbol *sym;
79 int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
80
81 if (err)
82 return err;
83
84 if (target[0] == '0' && tolower(target[1]) == 'x') {
85 u64 addr = strtoull(target, NULL, 16);
86 sym = map__find_symbol(self->map, addr, NULL);
87 } else
88 sym = map__find_symbol_by_name(self->map, target, NULL);
89
90 if (sym != NULL) {
91 u32 *idx = symbol__browser_index(sym);
92
93 self->b.top = &sym->rb_node;
94 self->b.index = self->b.top_idx = *idx;
95 } else
96 ui_helpline__fpush("%s not found!", target);
97
98 return 0;
99}
100
101static int map_browser__run(struct map_browser *self)
102{
103 int key;
104
105 if (ui_browser__show(&self->b, self->map->dso->long_name,
106 "Press <- or ESC to exit, %s / to search",
107 verbose ? "" : "restart with -v to use") < 0)
108 return -1;
109
110 if (verbose)
111 ui_browser__add_exit_key(&self->b, '/');
112
113 while (1) {
114 key = ui_browser__run(&self->b);
115
116 if (verbose && key == '/')
117 map_browser__search(self);
118 else
119 break;
120 }
121
122 ui_browser__hide(&self->b);
123 return key;
124}
125
126int map__browse(struct map *self)
127{
128 struct map_browser mb = {
129 .b = {
130 .entries = &self->dso->symbols[self->type],
131 .refresh = ui_browser__rb_tree_refresh,
132 .seek = ui_browser__rb_tree_seek,
133 .write = map_browser__write,
134 },
135 .map = self,
136 };
137 struct rb_node *nd;
138 char tmp[BITS_PER_LONG / 4];
139 u64 maxaddr = 0;
140
141 for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
142 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
143
144 if (maxaddr < pos->end)
145 maxaddr = pos->end;
146 if (verbose) {
147 u32 *idx = symbol__browser_index(pos);
148 *idx = mb.b.nr_entries;
149 }
150 ++mb.b.nr_entries;
151 }
152
153 mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr);
154 return map_browser__run(&mb);
155}
diff --git a/tools/perf/util/ui/browsers/map.h b/tools/perf/util/ui/browsers/map.h
new file mode 100644
index 000000000000..df8581a43e17
--- /dev/null
+++ b/tools/perf/util/ui/browsers/map.h
@@ -0,0 +1,6 @@
1#ifndef _PERF_UI_MAP_BROWSER_H_
2#define _PERF_UI_MAP_BROWSER_H_ 1
3struct map;
4
5int map__browse(struct map *self);
6#endif /* _PERF_UI_MAP_BROWSER_H_ */
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
new file mode 100644
index 000000000000..8d79daa4458a
--- /dev/null
+++ b/tools/perf/util/ui/helpline.c
@@ -0,0 +1,69 @@
1#define _GNU_SOURCE
2#include <stdio.h>
3#include <stdlib.h>
4#include <newt.h>
5
6#include "../debug.h"
7#include "helpline.h"
8
9void ui_helpline__pop(void)
10{
11 newtPopHelpLine();
12}
13
14void ui_helpline__push(const char *msg)
15{
16 newtPushHelpLine(msg);
17}
18
19void ui_helpline__vpush(const char *fmt, va_list ap)
20{
21 char *s;
22
23 if (vasprintf(&s, fmt, ap) < 0)
24 vfprintf(stderr, fmt, ap);
25 else {
26 ui_helpline__push(s);
27 free(s);
28 }
29}
30
31void ui_helpline__fpush(const char *fmt, ...)
32{
33 va_list ap;
34
35 va_start(ap, fmt);
36 ui_helpline__vpush(fmt, ap);
37 va_end(ap);
38}
39
40void ui_helpline__puts(const char *msg)
41{
42 ui_helpline__pop();
43 ui_helpline__push(msg);
44}
45
46void ui_helpline__init(void)
47{
48 ui_helpline__puts(" ");
49}
50
51char ui_helpline__last_msg[1024];
52
53int ui_helpline__show_help(const char *format, va_list ap)
54{
55 int ret;
56 static int backlog;
57
58 ret = vsnprintf(ui_helpline__last_msg + backlog,
59 sizeof(ui_helpline__last_msg) - backlog, format, ap);
60 backlog += ret;
61
62 if (ui_helpline__last_msg[backlog - 1] == '\n') {
63 ui_helpline__puts(ui_helpline__last_msg);
64 newtRefresh();
65 backlog = 0;
66 }
67
68 return ret;
69}
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h
new file mode 100644
index 000000000000..ab6028d0c401
--- /dev/null
+++ b/tools/perf/util/ui/helpline.h
@@ -0,0 +1,11 @@
1#ifndef _PERF_UI_HELPLINE_H_
2#define _PERF_UI_HELPLINE_H_ 1
3
4void ui_helpline__init(void);
5void ui_helpline__pop(void);
6void ui_helpline__push(const char *msg);
7void ui_helpline__vpush(const char *fmt, va_list ap);
8void ui_helpline__fpush(const char *fmt, ...);
9void ui_helpline__puts(const char *msg);
10
11#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
new file mode 100644
index 000000000000..5623da8e8080
--- /dev/null
+++ b/tools/perf/util/ui/libslang.h
@@ -0,0 +1,27 @@
1#ifndef _PERF_UI_SLANG_H_
2#define _PERF_UI_SLANG_H_ 1
3/*
4 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
5 * the build if it isn't defined. Use the equivalent one that glibc
6 * has on features.h.
7 */
8#include <features.h>
9#ifndef HAVE_LONG_LONG
10#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
11#endif
12#include <slang.h>
13
14#if SLANG_VERSION < 20104
15#define slsmg_printf(msg, args...) \
16 SLsmg_printf((char *)msg, ##args)
17#define slsmg_write_nstring(msg, len) \
18 SLsmg_write_nstring((char *)msg, len)
19#define sltt_set_color(obj, name, fg, bg) \
20 SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg)
21#else
22#define slsmg_printf SLsmg_printf
23#define slsmg_write_nstring SLsmg_write_nstring
24#define sltt_set_color SLtt_set_color
25#endif
26
27#endif /* _PERF_UI_SLANG_H_ */
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c
new file mode 100644
index 000000000000..d7fc399d36b3
--- /dev/null
+++ b/tools/perf/util/ui/progress.c
@@ -0,0 +1,60 @@
1#include <stdlib.h>
2#include <newt.h>
3#include "../cache.h"
4#include "progress.h"
5
6struct ui_progress {
7 newtComponent form, scale;
8};
9
10struct ui_progress *ui_progress__new(const char *title, u64 total)
11{
12 struct ui_progress *self = malloc(sizeof(*self));
13
14 if (self != NULL) {
15 int cols;
16
17 if (use_browser <= 0)
18 return self;
19 newtGetScreenSize(&cols, NULL);
20 cols -= 4;
21 newtCenteredWindow(cols, 1, title);
22 self->form = newtForm(NULL, NULL, 0);
23 if (self->form == NULL)
24 goto out_free_self;
25 self->scale = newtScale(0, 0, cols, total);
26 if (self->scale == NULL)
27 goto out_free_form;
28 newtFormAddComponent(self->form, self->scale);
29 newtRefresh();
30 }
31
32 return self;
33
34out_free_form:
35 newtFormDestroy(self->form);
36out_free_self:
37 free(self);
38 return NULL;
39}
40
41void ui_progress__update(struct ui_progress *self, u64 curr)
42{
43 /*
44 * FIXME: We should have a per UI backend way of showing progress,
45 * stdio will just show a percentage as NN%, etc.
46 */
47 if (use_browser <= 0)
48 return;
49 newtScaleSet(self->scale, curr);
50 newtRefresh();
51}
52
53void ui_progress__delete(struct ui_progress *self)
54{
55 if (use_browser > 0) {
56 newtFormDestroy(self->form);
57 newtPopWindow();
58 }
59 free(self);
60}
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/util/ui/progress.h
new file mode 100644
index 000000000000..a3820a0beb5b
--- /dev/null
+++ b/tools/perf/util/ui/progress.h
@@ -0,0 +1,11 @@
1#ifndef _PERF_UI_PROGRESS_H_
2#define _PERF_UI_PROGRESS_H_ 1
3
4struct ui_progress;
5
6struct ui_progress *ui_progress__new(const char *title, u64 total);
7void ui_progress__delete(struct ui_progress *self);
8
9void ui_progress__update(struct ui_progress *self, u64 curr);
10
11#endif
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
new file mode 100644
index 000000000000..662085032eb7
--- /dev/null
+++ b/tools/perf/util/ui/setup.c
@@ -0,0 +1,42 @@
1#include <newt.h>
2#include <signal.h>
3#include <stdbool.h>
4
5#include "../cache.h"
6#include "../debug.h"
7#include "browser.h"
8#include "helpline.h"
9
10static void newt_suspend(void *d __used)
11{
12 newtSuspend();
13 raise(SIGTSTP);
14 newtResume();
15}
16
17void setup_browser(void)
18{
19 if (!isatty(1) || !use_browser || dump_trace) {
20 use_browser = 0;
21 setup_pager();
22 return;
23 }
24
25 use_browser = 1;
26 newtInit();
27 newtCls();
28 newtSetSuspendCallback(newt_suspend, NULL);
29 ui_helpline__init();
30 ui_browser__init();
31}
32
33void exit_browser(bool wait_for_ok)
34{
35 if (use_browser > 0) {
36 if (wait_for_ok) {
37 char title[] = "Fatal Error", ok[] = "Ok";
38 newtWinMessage(title, ok, ui_helpline__last_msg);
39 }
40 newtFinished();
41 }
42}
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
new file mode 100644
index 000000000000..7b5a8926624e
--- /dev/null
+++ b/tools/perf/util/ui/util.c
@@ -0,0 +1,127 @@
1#include <newt.h>
2#include <signal.h>
3#include <stdio.h>
4#include <stdbool.h>
5#include <string.h>
6#include <sys/ttydefaults.h>
7
8#include "../cache.h"
9#include "../debug.h"
10#include "browser.h"
11#include "helpline.h"
12#include "util.h"
13
14static void newt_form__set_exit_keys(newtComponent self)
15{
16 newtFormAddHotKey(self, NEWT_KEY_LEFT);
17 newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
18 newtFormAddHotKey(self, 'Q');
19 newtFormAddHotKey(self, 'q');
20 newtFormAddHotKey(self, CTRL('c'));
21}
22
23static newtComponent newt_form__new(void)
24{
25 newtComponent self = newtForm(NULL, NULL, 0);
26 if (self)
27 newt_form__set_exit_keys(self);
28 return self;
29}
30
31int ui__popup_menu(int argc, char * const argv[])
32{
33 struct newtExitStruct es;
34 int i, rc = -1, max_len = 5;
35 newtComponent listbox, form = newt_form__new();
36
37 if (form == NULL)
38 return -1;
39
40 listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT);
41 if (listbox == NULL)
42 goto out_destroy_form;
43
44 newtFormAddComponent(form, listbox);
45
46 for (i = 0; i < argc; ++i) {
47 int len = strlen(argv[i]);
48 if (len > max_len)
49 max_len = len;
50 if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i))
51 goto out_destroy_form;
52 }
53
54 newtCenteredWindow(max_len, argc, NULL);
55 newtFormRun(form, &es);
56 rc = newtListboxGetCurrent(listbox) - NULL;
57 if (es.reason == NEWT_EXIT_HOTKEY)
58 rc = -1;
59 newtPopWindow();
60out_destroy_form:
61 newtFormDestroy(form);
62 return rc;
63}
64
65int ui__help_window(const char *text)
66{
67 struct newtExitStruct es;
68 newtComponent tb, form = newt_form__new();
69 int rc = -1;
70 int max_len = 0, nr_lines = 0;
71 const char *t;
72
73 if (form == NULL)
74 return -1;
75
76 t = text;
77 while (1) {
78 const char *sep = strchr(t, '\n');
79 int len;
80
81 if (sep == NULL)
82 sep = strchr(t, '\0');
83 len = sep - t;
84 if (max_len < len)
85 max_len = len;
86 ++nr_lines;
87 if (*sep == '\0')
88 break;
89 t = sep + 1;
90 }
91
92 tb = newtTextbox(0, 0, max_len, nr_lines, 0);
93 if (tb == NULL)
94 goto out_destroy_form;
95
96 newtTextboxSetText(tb, text);
97 newtFormAddComponent(form, tb);
98 newtCenteredWindow(max_len, nr_lines, NULL);
99 newtFormRun(form, &es);
100 newtPopWindow();
101 rc = 0;
102out_destroy_form:
103 newtFormDestroy(form);
104 return rc;
105}
106
107static const char yes[] = "Yes", no[] = "No",
108 warning_str[] = "Warning!", ok[] = "Ok";
109
110bool ui__dialog_yesno(const char *msg)
111{
112 /* newtWinChoice should really be accepting const char pointers... */
113 return newtWinChoice(NULL, (char *)yes, (char *)no, (char *)msg) == 1;
114}
115
116void ui__warning(const char *format, ...)
117{
118 va_list args;
119
120 va_start(args, format);
121 if (use_browser > 0)
122 newtWinMessagev((char *)warning_str, (char *)ok,
123 (char *)format, args);
124 else
125 vfprintf(stderr, format, args);
126 va_end(args);
127}
diff --git a/tools/perf/util/ui/util.h b/tools/perf/util/ui/util.h
new file mode 100644
index 000000000000..afcbc1d99531
--- /dev/null
+++ b/tools/perf/util/ui/util.h
@@ -0,0 +1,10 @@
1#ifndef _PERF_UI_UTIL_H_
2#define _PERF_UI_UTIL_H_ 1
3
4#include <stdbool.h>
5
6int ui__popup_menu(int argc, char * const argv[]);
7int ui__help_window(const char *text);
8bool ui__dialog_yesno(const char *msg);
9
10#endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
new file mode 100644
index 000000000000..5b3ea49aa63e
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,133 @@
1#include "util.h"
2#include <sys/mman.h>
3
4int mkdir_p(char *path, mode_t mode)
5{
6 struct stat st;
7 int err;
8 char *d = path;
9
10 if (*d != '/')
11 return -1;
12
13 if (stat(path, &st) == 0)
14 return 0;
15
16 while (*++d == '/');
17
18 while ((d = strchr(d, '/'))) {
19 *d = '\0';
20 err = stat(path, &st) && mkdir(path, mode);
21 *d++ = '/';
22 if (err)
23 return -1;
24 while (*d == '/')
25 ++d;
26 }
27 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
28}
29
30static int slow_copyfile(const char *from, const char *to)
31{
32 int err = 0;
33 char *line = NULL;
34 size_t n;
35 FILE *from_fp = fopen(from, "r"), *to_fp;
36
37 if (from_fp == NULL)
38 goto out;
39
40 to_fp = fopen(to, "w");
41 if (to_fp == NULL)
42 goto out_fclose_from;
43
44 while (getline(&line, &n, from_fp) > 0)
45 if (fputs(line, to_fp) == EOF)
46 goto out_fclose_to;
47 err = 0;
48out_fclose_to:
49 fclose(to_fp);
50 free(line);
51out_fclose_from:
52 fclose(from_fp);
53out:
54 return err;
55}
56
57int copyfile(const char *from, const char *to)
58{
59 int fromfd, tofd;
60 struct stat st;
61 void *addr;
62 int err = -1;
63
64 if (stat(from, &st))
65 goto out;
66
67 if (st.st_size == 0) /* /proc? do it slowly... */
68 return slow_copyfile(from, to);
69
70 fromfd = open(from, O_RDONLY);
71 if (fromfd < 0)
72 goto out;
73
74 tofd = creat(to, 0755);
75 if (tofd < 0)
76 goto out_close_from;
77
78 addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0);
79 if (addr == MAP_FAILED)
80 goto out_close_to;
81
82 if (write(tofd, addr, st.st_size) == st.st_size)
83 err = 0;
84
85 munmap(addr, st.st_size);
86out_close_to:
87 close(tofd);
88 if (err)
89 unlink(to);
90out_close_from:
91 close(fromfd);
92out:
93 return err;
94}
95
96unsigned long convert_unit(unsigned long value, char *unit)
97{
98 *unit = ' ';
99
100 if (value > 1000) {
101 value /= 1000;
102 *unit = 'K';
103 }
104
105 if (value > 1000) {
106 value /= 1000;
107 *unit = 'M';
108 }
109
110 if (value > 1000) {
111 value /= 1000;
112 *unit = 'G';
113 }
114
115 return value;
116}
117
118int readn(int fd, void *buf, size_t n)
119{
120 void *buf_start = buf;
121
122 while (n) {
123 int ret = read(fd, buf, n);
124
125 if (ret <= 0)
126 return ret;
127
128 n -= ret;
129 buf += ret;
130 }
131
132 return buf - buf_start;
133}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c673d8825883..e833f26f3bfc 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -42,12 +42,14 @@
42#define _ALL_SOURCE 1 42#define _ALL_SOURCE 1
43#define _GNU_SOURCE 1 43#define _GNU_SOURCE 1
44#define _BSD_SOURCE 1 44#define _BSD_SOURCE 1
45#define HAS_BOOL
45 46
46#include <unistd.h> 47#include <unistd.h>
47#include <stdio.h> 48#include <stdio.h>
48#include <sys/stat.h> 49#include <sys/stat.h>
49#include <sys/statfs.h> 50#include <sys/statfs.h>
50#include <fcntl.h> 51#include <fcntl.h>
52#include <stdbool.h>
51#include <stddef.h> 53#include <stddef.h>
52#include <stdlib.h> 54#include <stdlib.h>
53#include <stdarg.h> 55#include <stdarg.h>
@@ -78,7 +80,8 @@
78#include <pwd.h> 80#include <pwd.h>
79#include <inttypes.h> 81#include <inttypes.h>
80#include "../../../include/linux/magic.h" 82#include "../../../include/linux/magic.h"
81 83#include "types.h"
84#include <sys/ttydefaults.h>
82 85
83#ifndef NO_ICONV 86#ifndef NO_ICONV
84#include <iconv.h> 87#include <iconv.h>
@@ -86,6 +89,7 @@
86 89
87extern const char *graph_line; 90extern const char *graph_line;
88extern const char *graph_dotted_line; 91extern const char *graph_dotted_line;
92extern char buildid_dir[];
89 93
90/* On most systems <limits.h> would have given us this, but 94/* On most systems <limits.h> would have given us this, but
91 * not on some systems (e.g. GNU/Hurd). 95 * not on some systems (e.g. GNU/Hurd).
@@ -149,7 +153,8 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)))
149extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); 153extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
150 154
151extern int prefixcmp(const char *str, const char *prefix); 155extern int prefixcmp(const char *str, const char *prefix);
152extern time_t tm_to_time_t(const struct tm *tm); 156extern void set_buildid_dir(void);
157extern void disable_buildid_cache(void);
153 158
154static inline const char *skip_prefix(const char *str, const char *prefix) 159static inline const char *skip_prefix(const char *str, const char *prefix)
155{ 160{
@@ -157,119 +162,6 @@ static inline const char *skip_prefix(const char *str, const char *prefix)
157 return strncmp(str, prefix, len) ? NULL : str + len; 162 return strncmp(str, prefix, len) ? NULL : str + len;
158} 163}
159 164
160#if defined(NO_MMAP) || defined(USE_WIN32_MMAP)
161
162#ifndef PROT_READ
163#define PROT_READ 1
164#define PROT_WRITE 2
165#define MAP_PRIVATE 1
166#define MAP_FAILED ((void*)-1)
167#endif
168
169#define mmap git_mmap
170#define munmap git_munmap
171extern void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
172extern int git_munmap(void *start, size_t length);
173
174#else /* NO_MMAP || USE_WIN32_MMAP */
175
176#include <sys/mman.h>
177
178#endif /* NO_MMAP || USE_WIN32_MMAP */
179
180#ifdef NO_MMAP
181
182/* This value must be multiple of (pagesize * 2) */
183#define DEFAULT_PACKED_GIT_WINDOW_SIZE (1 * 1024 * 1024)
184
185#else /* NO_MMAP */
186
187/* This value must be multiple of (pagesize * 2) */
188#define DEFAULT_PACKED_GIT_WINDOW_SIZE \
189 (sizeof(void*) >= 8 \
190 ? 1 * 1024 * 1024 * 1024 \
191 : 32 * 1024 * 1024)
192
193#endif /* NO_MMAP */
194
195#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
196#define on_disk_bytes(st) ((st).st_size)
197#else
198#define on_disk_bytes(st) ((st).st_blocks * 512)
199#endif
200
201#define DEFAULT_PACKED_GIT_LIMIT \
202 ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
203
204#ifdef NO_PREAD
205#define pread git_pread
206extern ssize_t git_pread(int fd, void *buf, size_t count, off_t offset);
207#endif
208/*
209 * Forward decl that will remind us if its twin in cache.h changes.
210 * This function is used in compat/pread.c. But we can't include
211 * cache.h there.
212 */
213extern ssize_t read_in_full(int fd, void *buf, size_t count);
214
215#ifdef NO_SETENV
216#define setenv gitsetenv
217extern int gitsetenv(const char *, const char *, int);
218#endif
219
220#ifdef NO_MKDTEMP
221#define mkdtemp gitmkdtemp
222extern char *gitmkdtemp(char *);
223#endif
224
225#ifdef NO_UNSETENV
226#define unsetenv gitunsetenv
227extern void gitunsetenv(const char *);
228#endif
229
230#ifdef NO_STRCASESTR
231#define strcasestr gitstrcasestr
232extern char *gitstrcasestr(const char *haystack, const char *needle);
233#endif
234
235#ifdef NO_STRLCPY
236#define strlcpy gitstrlcpy
237extern size_t gitstrlcpy(char *, const char *, size_t);
238#endif
239
240#ifdef NO_STRTOUMAX
241#define strtoumax gitstrtoumax
242extern uintmax_t gitstrtoumax(const char *, char **, int);
243#endif
244
245#ifdef NO_HSTRERROR
246#define hstrerror githstrerror
247extern const char *githstrerror(int herror);
248#endif
249
250#ifdef NO_MEMMEM
251#define memmem gitmemmem
252void *gitmemmem(const void *haystack, size_t haystacklen,
253 const void *needle, size_t needlelen);
254#endif
255
256#ifdef FREAD_READS_DIRECTORIES
257#ifdef fopen
258#undef fopen
259#endif
260#define fopen(a,b) git_fopen(a,b)
261extern FILE *git_fopen(const char*, const char*);
262#endif
263
264#ifdef SNPRINTF_RETURNS_BOGUS
265#define snprintf git_snprintf
266extern int git_snprintf(char *str, size_t maxsize,
267 const char *format, ...);
268#define vsnprintf git_vsnprintf
269extern int git_vsnprintf(char *str, size_t maxsize,
270 const char *format, va_list ap);
271#endif
272
273#ifdef __GLIBC_PREREQ 165#ifdef __GLIBC_PREREQ
274#if __GLIBC_PREREQ(2, 1) 166#if __GLIBC_PREREQ(2, 1)
275#define HAVE_STRCHRNUL 167#define HAVE_STRCHRNUL
@@ -290,25 +182,19 @@ static inline char *gitstrchrnul(const char *s, int c)
290 * Wrappers: 182 * Wrappers:
291 */ 183 */
292extern char *xstrdup(const char *str); 184extern char *xstrdup(const char *str);
293extern void *xmalloc(size_t size) __attribute__((weak));
294extern void *xmemdupz(const void *data, size_t len);
295extern char *xstrndup(const char *str, size_t len);
296extern void *xrealloc(void *ptr, size_t size) __attribute__((weak)); 185extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
297 186
187
298static inline void *zalloc(size_t size) 188static inline void *zalloc(size_t size)
299{ 189{
300 return calloc(1, size); 190 return calloc(1, size);
301} 191}
302 192
303static inline size_t xsize_t(off_t len)
304{
305 return (size_t)len;
306}
307
308static inline int has_extension(const char *filename, const char *ext) 193static inline int has_extension(const char *filename, const char *ext)
309{ 194{
310 size_t len = strlen(filename); 195 size_t len = strlen(filename);
311 size_t extlen = strlen(ext); 196 size_t extlen = strlen(ext);
197
312 return len > extlen && !memcmp(filename + len - extlen, ext, extlen); 198 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
313} 199}
314 200
@@ -322,6 +208,7 @@ static inline int has_extension(const char *filename, const char *ext)
322#undef isalnum 208#undef isalnum
323#undef tolower 209#undef tolower
324#undef toupper 210#undef toupper
211
325extern unsigned char sane_ctype[256]; 212extern unsigned char sane_ctype[256];
326#define GIT_SPACE 0x01 213#define GIT_SPACE 0x01
327#define GIT_DIGIT 0x02 214#define GIT_DIGIT 0x02
@@ -339,8 +226,6 @@ extern unsigned char sane_ctype[256];
339#define isalpha(x) sane_istest(x,GIT_ALPHA) 226#define isalpha(x) sane_istest(x,GIT_ALPHA)
340#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 227#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
341#define isprint(x) sane_istest(x,GIT_PRINT) 228#define isprint(x) sane_istest(x,GIT_PRINT)
342#define is_glob_special(x) sane_istest(x,GIT_GLOB_SPECIAL)
343#define is_regex_special(x) sane_istest(x,GIT_GLOB_SPECIAL | GIT_REGEX_SPECIAL)
344#define tolower(x) sane_case((unsigned char)(x), 0x20) 229#define tolower(x) sane_case((unsigned char)(x), 0x20)
345#define toupper(x) sane_case((unsigned char)(x), 0) 230#define toupper(x) sane_case((unsigned char)(x), 0)
346 231
@@ -351,38 +236,6 @@ static inline int sane_case(int x, int high)
351 return x; 236 return x;
352} 237}
353 238
354static inline int strtoul_ui(char const *s, int base, unsigned int *result)
355{
356 unsigned long ul;
357 char *p;
358
359 errno = 0;
360 ul = strtoul(s, &p, base);
361 if (errno || *p || p == s || (unsigned int) ul != ul)
362 return -1;
363 *result = ul;
364 return 0;
365}
366
367static inline int strtol_i(char const *s, int base, int *result)
368{
369 long ul;
370 char *p;
371
372 errno = 0;
373 ul = strtol(s, &p, base);
374 if (errno || *p || p == s || (int) ul != ul)
375 return -1;
376 *result = ul;
377 return 0;
378}
379
380#ifdef INTERNAL_QSORT
381void git_qsort(void *base, size_t nmemb, size_t size,
382 int(*compar)(const void *, const void *));
383#define qsort git_qsort
384#endif
385
386#ifndef DIR_HAS_BSD_GROUP_SEMANTICS 239#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
387# define FORCE_DIR_SET_GID S_ISGID 240# define FORCE_DIR_SET_GID S_ISGID
388#else 241#else
@@ -403,4 +256,18 @@ void git_qsort(void *base, size_t nmemb, size_t size,
403#endif 256#endif
404#endif 257#endif
405 258
259int mkdir_p(char *path, mode_t mode);
260int copyfile(const char *from, const char *to);
261
262s64 perf_atoll(const char *str);
263char **argv_split(const char *str, int *argcp);
264void argv_free(char **argv);
265bool strglobmatch(const char *str, const char *pat);
266bool strlazymatch(const char *str, const char *pat);
267unsigned long convert_unit(unsigned long value, char *unit);
268int readn(int fd, void *buf, size_t size);
269
270#define _STR(x) #x
271#define STR(x) _STR(x)
272
406#endif 273#endif
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
index 1c15e39f99e3..cfa55d686e3b 100644
--- a/tools/perf/util/values.c
+++ b/tools/perf/util/values.c
@@ -169,6 +169,7 @@ static void perf_read_values__display_pretty(FILE *fp,
169 counterwidth[j], values->value[i][j]); 169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n"); 170 fprintf(fp, "\n");
171 } 171 }
172 free(counterwidth);
172} 173}
173 174
174static void perf_read_values__display_raw(FILE *fp, 175static void perf_read_values__display_raw(FILE *fp,
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index bf44ca85d23b..73e900edb5a2 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -23,46 +23,6 @@ char *xstrdup(const char *str)
23 return ret; 23 return ret;
24} 24}
25 25
26void *xmalloc(size_t size)
27{
28 void *ret = malloc(size);
29 if (!ret && !size)
30 ret = malloc(1);
31 if (!ret) {
32 release_pack_memory(size, -1);
33 ret = malloc(size);
34 if (!ret && !size)
35 ret = malloc(1);
36 if (!ret)
37 die("Out of memory, malloc failed");
38 }
39#ifdef XMALLOC_POISON
40 memset(ret, 0xA5, size);
41#endif
42 return ret;
43}
44
45/*
46 * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of
47 * "data" to the allocated memory, zero terminates the allocated memory,
48 * and returns a pointer to the allocated memory. If the allocation fails,
49 * the program dies.
50 */
51void *xmemdupz(const void *data, size_t len)
52{
53 char *p = xmalloc(len + 1);
54 memcpy(p, data, len);
55 p[len] = '\0';
56 return p;
57}
58
59char *xstrndup(const char *str, size_t len)
60{
61 char *p = memchr(str, '\0', len);
62
63 return xmemdupz(str, p ? (size_t)(p - str) : len);
64}
65
66void *xrealloc(void *ptr, size_t size) 26void *xrealloc(void *ptr, size_t size)
67{ 27{
68 void *ret = realloc(ptr, size); 28 void *ret = realloc(ptr, size);
@@ -78,73 +38,3 @@ void *xrealloc(void *ptr, size_t size)
78 } 38 }
79 return ret; 39 return ret;
80} 40}
81
82/*
83 * xread() is the same a read(), but it automatically restarts read()
84 * operations with a recoverable error (EAGAIN and EINTR). xread()
85 * DOES NOT GUARANTEE that "len" bytes is read even if the data is available.
86 */
87static ssize_t xread(int fd, void *buf, size_t len)
88{
89 ssize_t nr;
90 while (1) {
91 nr = read(fd, buf, len);
92 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
93 continue;
94 return nr;
95 }
96}
97
98/*
99 * xwrite() is the same a write(), but it automatically restarts write()
100 * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT
101 * GUARANTEE that "len" bytes is written even if the operation is successful.
102 */
103static ssize_t xwrite(int fd, const void *buf, size_t len)
104{
105 ssize_t nr;
106 while (1) {
107 nr = write(fd, buf, len);
108 if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
109 continue;
110 return nr;
111 }
112}
113
114ssize_t read_in_full(int fd, void *buf, size_t count)
115{
116 char *p = buf;
117 ssize_t total = 0;
118
119 while (count > 0) {
120 ssize_t loaded = xread(fd, p, count);
121 if (loaded <= 0)
122 return total ? total : loaded;
123 count -= loaded;
124 p += loaded;
125 total += loaded;
126 }
127
128 return total;
129}
130
131ssize_t write_in_full(int fd, const void *buf, size_t count)
132{
133 const char *p = buf;
134 ssize_t total = 0;
135
136 while (count > 0) {
137 ssize_t written = xwrite(fd, p, count);
138 if (written < 0)
139 return -1;
140 if (!written) {
141 errno = ENOSPC;
142 return -1;
143 }
144 count -= written;
145 p += written;
146 total += written;
147 }
148
149 return total;
150}
diff --git a/tools/perf/util/xyarray.c b/tools/perf/util/xyarray.c
new file mode 100644
index 000000000000..22afbf6c536a
--- /dev/null
+++ b/tools/perf/util/xyarray.c
@@ -0,0 +1,20 @@
1#include "xyarray.h"
2#include "util.h"
3
4struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size)
5{
6 size_t row_size = ylen * entry_size;
7 struct xyarray *xy = zalloc(sizeof(*xy) + xlen * row_size);
8
9 if (xy != NULL) {
10 xy->entry_size = entry_size;
11 xy->row_size = row_size;
12 }
13
14 return xy;
15}
16
17void xyarray__delete(struct xyarray *xy)
18{
19 free(xy);
20}
diff --git a/tools/perf/util/xyarray.h b/tools/perf/util/xyarray.h
new file mode 100644
index 000000000000..c488a07275dd
--- /dev/null
+++ b/tools/perf/util/xyarray.h
@@ -0,0 +1,20 @@
1#ifndef _PERF_XYARRAY_H_
2#define _PERF_XYARRAY_H_ 1
3
4#include <sys/types.h>
5
6struct xyarray {
7 size_t row_size;
8 size_t entry_size;
9 char contents[];
10};
11
12struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size);
13void xyarray__delete(struct xyarray *xy);
14
15static inline void *xyarray__entry(struct xyarray *xy, int x, int y)
16{
17 return &xy->contents[x * xy->row_size + y * xy->entry_size];
18}
19
20#endif /* _PERF_XYARRAY_H_ */
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile
new file mode 100644
index 000000000000..fd8e1f1297aa
--- /dev/null
+++ b/tools/power/x86/turbostat/Makefile
@@ -0,0 +1,8 @@
1turbostat : turbostat.c
2
3clean :
4 rm -f turbostat
5
6install :
7 install turbostat /usr/bin/turbostat
8 install turbostat.8 /usr/share/man/man8
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
new file mode 100644
index 000000000000..ff75125deed0
--- /dev/null
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -0,0 +1,172 @@
1.TH TURBOSTAT 8
2.SH NAME
3turbostat \- Report processor frequency and idle statistics
4.SH SYNOPSIS
5.ft B
6.B turbostat
7.RB [ "\-v" ]
8.RB [ "\-M MSR#" ]
9.RB command
10.br
11.B turbostat
12.RB [ "\-v" ]
13.RB [ "\-M MSR#" ]
14.RB [ "\-i interval_sec" ]
15.SH DESCRIPTION
16\fBturbostat \fP reports processor topology, frequency
17and idle power state statistics on modern X86 processors.
18Either \fBcommand\fP is forked and statistics are printed
19upon its completion, or statistics are printed periodically.
20
21\fBturbostat \fP
22requires that the processor
23supports an "invariant" TSC, plus the APERF and MPERF MSRs.
24\fBturbostat \fP will report idle cpu power state residency
25on processors that additionally support C-state residency counters.
26
27.SS Options
28The \fB-v\fP option increases verbosity.
29.PP
30The \fB-M MSR#\fP option dumps the specified MSR,
31in addition to the usual frequency and idle statistics.
32.PP
33The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
34The default is 5 seconds.
35.PP
36The \fBcommand\fP parameter forks \fBcommand\fP and upon its exit,
37displays the statistics gathered since it was forked.
38.PP
39.SH FIELD DESCRIPTIONS
40.nf
41\fBpkg\fP processor package number.
42\fBcore\fP processor core number.
43\fBCPU\fP Linux CPU (logical processor) number.
44\fB%c0\fP percent of the interval that the CPU retired instructions.
45\fBGHz\fP average clock rate while the CPU was in c0 state.
46\fBTSC\fP average GHz that the TSC ran during the entire interval.
47\fB%c1, %c3, %c6\fP show the percentage residency in hardware core idle states.
48\fB%pc3, %pc6\fP percentage residency in hardware package idle states.
49.fi
50.PP
51.SH EXAMPLE
52Without any parameters, turbostat prints out counters ever 5 seconds.
53(override interval with "-i sec" option, or specify a command
54for turbostat to fork).
55
56The first row of statistics reflect the average for the entire system.
57Subsequent rows show per-CPU statistics.
58
59.nf
60[root@x980]# ./turbostat
61core CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
62 0.04 1.62 3.38 0.11 0.00 99.85 0.00 95.07
63 0 0 0.04 1.62 3.38 0.06 0.00 99.90 0.00 95.07
64 0 6 0.02 1.62 3.38 0.08 0.00 99.90 0.00 95.07
65 1 2 0.10 1.62 3.38 0.29 0.00 99.61 0.00 95.07
66 1 8 0.11 1.62 3.38 0.28 0.00 99.61 0.00 95.07
67 2 4 0.01 1.62 3.38 0.01 0.00 99.98 0.00 95.07
68 2 10 0.01 1.61 3.38 0.02 0.00 99.98 0.00 95.07
69 8 1 0.07 1.62 3.38 0.15 0.00 99.78 0.00 95.07
70 8 7 0.03 1.62 3.38 0.19 0.00 99.78 0.00 95.07
71 9 3 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07
72 9 9 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07
73 10 5 0.01 1.62 3.38 0.13 0.00 99.86 0.00 95.07
74 10 11 0.08 1.62 3.38 0.05 0.00 99.86 0.00 95.07
75.fi
76.SH VERBOSE EXAMPLE
77The "-v" option adds verbosity to the output:
78
79.nf
80GenuineIntel 11 CPUID levels; family:model:stepping 0x6:2c:2 (6:44:2)
8112 * 133 = 1600 MHz max efficiency
8225 * 133 = 3333 MHz TSC frequency
8326 * 133 = 3467 MHz max turbo 4 active cores
8426 * 133 = 3467 MHz max turbo 3 active cores
8527 * 133 = 3600 MHz max turbo 2 active cores
8627 * 133 = 3600 MHz max turbo 1 active cores
87
88.fi
89The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency
90available at the minimum package voltage. The \fBTSC frequency\fP is the nominal
91maximum frequency of the processor if turbo-mode were not available. This frequency
92should be sustainable on all CPUs indefinitely, given nominal power and cooling.
93The remaining rows show what maximum turbo frequency is possible
94depending on the number of idle cores. Note that this information is
95not available on all processors.
96.SH FORK EXAMPLE
97If turbostat is invoked with a command, it will fork that command
98and output the statistics gathered when the command exits.
99eg. Here a cycle soaker is run on 1 CPU (see %c0) for a few seconds
100until ^C while the other CPUs are mostly idle:
101
102.nf
103[root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null
104
105^Ccore CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6
106 8.49 3.63 3.38 16.23 0.66 74.63 0.00 0.00
107 0 0 1.22 3.62 3.38 32.18 0.00 66.60 0.00 0.00
108 0 6 0.40 3.61 3.38 33.00 0.00 66.60 0.00 0.00
109 1 2 0.11 3.14 3.38 0.19 3.95 95.75 0.00 0.00
110 1 8 0.05 2.88 3.38 0.25 3.95 95.75 0.00 0.00
111 2 4 0.00 3.13 3.38 0.02 0.00 99.98 0.00 0.00
112 2 10 0.00 3.09 3.38 0.02 0.00 99.98 0.00 0.00
113 8 1 0.04 3.50 3.38 14.43 0.00 85.54 0.00 0.00
114 8 7 0.03 2.98 3.38 14.43 0.00 85.54 0.00 0.00
115 9 3 0.00 3.16 3.38 100.00 0.00 0.00 0.00 0.00
116 9 9 99.93 3.63 3.38 0.06 0.00 0.00 0.00 0.00
117 10 5 0.01 2.82 3.38 0.08 0.00 99.91 0.00 0.00
118 10 11 0.02 3.36 3.38 0.06 0.00 99.91 0.00 0.00
1196.950866 sec
120
121.fi
122Above the cycle soaker drives cpu9 up 3.6 Ghz turbo limit
123while the other processors are generally in various states of idle.
124
125Note that cpu3 is an HT sibling sharing core9
126with cpu9, and thus it is unable to get to an idle state
127deeper than c1 while cpu9 is busy.
128
129Note that turbostat reports average GHz of 3.61, while
130the arithmetic average of the GHz column above is 3.24.
131This is a weighted average, where the weight is %c0. ie. it is the total number of
132un-halted cycles elapsed per time divided by the number of CPUs.
133.SH NOTES
134
135.B "turbostat "
136must be run as root.
137
138.B "turbostat "
139reads hardware counters, but doesn't write them.
140So it will not interfere with the OS or other programs, including
141multiple invocations of itself.
142
143\fBturbostat \fP
144may work poorly on Linux-2.6.20 through 2.6.29,
145as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF
146in those kernels.
147
148The APERF, MPERF MSRs are defined to count non-halted cycles.
149Although it is not guaranteed by the architecture, turbostat assumes
150that they count at TSC rate, which is true on all processors tested to date.
151
152.SH REFERENCES
153"Intel® Turbo Boost Technology
154in Intel® Core™ Microarchitecture (Nehalem) Based Processors"
155http://download.intel.com/design/processor/applnots/320354.pdf
156
157"Intel® 64 and IA-32 Architectures Software Developer's Manual
158Volume 3B: System Programming Guide"
159http://www.intel.com/products/processor/manuals/
160
161.SH FILES
162.ta
163.nf
164/dev/cpu/*/msr
165.fi
166
167.SH "SEE ALSO"
168msr(4), vmstat(8)
169.PP
170.SH AUTHORS
171.nf
172Written by Len Brown <len.brown@intel.com>
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
new file mode 100644
index 000000000000..4c6983de6fd9
--- /dev/null
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -0,0 +1,1048 @@
1/*
2 * turbostat -- show CPU frequency and C-state residency
3 * on modern Intel turbo-capable processors.
4 *
5 * Copyright (c) 2010, Intel Corporation.
6 * Len Brown <len.brown@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#include <stdio.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26#include <sys/stat.h>
27#include <sys/resource.h>
28#include <fcntl.h>
29#include <signal.h>
30#include <sys/time.h>
31#include <stdlib.h>
32#include <dirent.h>
33#include <string.h>
34#include <ctype.h>
35
36#define MSR_TSC 0x10
37#define MSR_NEHALEM_PLATFORM_INFO 0xCE
38#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD
39#define MSR_APERF 0xE8
40#define MSR_MPERF 0xE7
41#define MSR_PKG_C2_RESIDENCY 0x60D /* SNB only */
42#define MSR_PKG_C3_RESIDENCY 0x3F8
43#define MSR_PKG_C6_RESIDENCY 0x3F9
44#define MSR_PKG_C7_RESIDENCY 0x3FA /* SNB only */
45#define MSR_CORE_C3_RESIDENCY 0x3FC
46#define MSR_CORE_C6_RESIDENCY 0x3FD
47#define MSR_CORE_C7_RESIDENCY 0x3FE /* SNB only */
48
49char *proc_stat = "/proc/stat";
50unsigned int interval_sec = 5; /* set with -i interval_sec */
51unsigned int verbose; /* set with -v */
52unsigned int skip_c0;
53unsigned int skip_c1;
54unsigned int do_nhm_cstates;
55unsigned int do_snb_cstates;
56unsigned int has_aperf;
57unsigned int units = 1000000000; /* Ghz etc */
58unsigned int genuine_intel;
59unsigned int has_invariant_tsc;
60unsigned int do_nehalem_platform_info;
61unsigned int do_nehalem_turbo_ratio_limit;
62unsigned int extra_msr_offset;
63double bclk;
64unsigned int show_pkg;
65unsigned int show_core;
66unsigned int show_cpu;
67
68int aperf_mperf_unstable;
69int backwards_count;
70char *progname;
71int need_reinitialize;
72
73int num_cpus;
74
75typedef struct per_cpu_counters {
76 unsigned long long tsc; /* per thread */
77 unsigned long long aperf; /* per thread */
78 unsigned long long mperf; /* per thread */
79 unsigned long long c1; /* per thread (calculated) */
80 unsigned long long c3; /* per core */
81 unsigned long long c6; /* per core */
82 unsigned long long c7; /* per core */
83 unsigned long long pc2; /* per package */
84 unsigned long long pc3; /* per package */
85 unsigned long long pc6; /* per package */
86 unsigned long long pc7; /* per package */
87 unsigned long long extra_msr; /* per thread */
88 int pkg;
89 int core;
90 int cpu;
91 struct per_cpu_counters *next;
92} PCC;
93
94PCC *pcc_even;
95PCC *pcc_odd;
96PCC *pcc_delta;
97PCC *pcc_average;
98struct timeval tv_even;
99struct timeval tv_odd;
100struct timeval tv_delta;
101
102unsigned long long get_msr(int cpu, off_t offset)
103{
104 ssize_t retval;
105 unsigned long long msr;
106 char pathname[32];
107 int fd;
108
109 sprintf(pathname, "/dev/cpu/%d/msr", cpu);
110 fd = open(pathname, O_RDONLY);
111 if (fd < 0) {
112 perror(pathname);
113 need_reinitialize = 1;
114 return 0;
115 }
116
117 retval = pread(fd, &msr, sizeof msr, offset);
118 if (retval != sizeof msr) {
119 fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n",
120 cpu, offset, retval);
121 exit(-2);
122 }
123
124 close(fd);
125 return msr;
126}
127
128void print_header()
129{
130 if (show_pkg)
131 fprintf(stderr, "pkg ");
132 if (show_core)
133 fprintf(stderr, "core");
134 if (show_cpu)
135 fprintf(stderr, " CPU");
136 if (do_nhm_cstates)
137 fprintf(stderr, " %%c0 ");
138 if (has_aperf)
139 fprintf(stderr, " GHz");
140 fprintf(stderr, " TSC");
141 if (do_nhm_cstates)
142 fprintf(stderr, " %%c1 ");
143 if (do_nhm_cstates)
144 fprintf(stderr, " %%c3 ");
145 if (do_nhm_cstates)
146 fprintf(stderr, " %%c6 ");
147 if (do_snb_cstates)
148 fprintf(stderr, " %%c7 ");
149 if (do_snb_cstates)
150 fprintf(stderr, " %%pc2 ");
151 if (do_nhm_cstates)
152 fprintf(stderr, " %%pc3 ");
153 if (do_nhm_cstates)
154 fprintf(stderr, " %%pc6 ");
155 if (do_snb_cstates)
156 fprintf(stderr, " %%pc7 ");
157 if (extra_msr_offset)
158 fprintf(stderr, " MSR 0x%x ", extra_msr_offset);
159
160 putc('\n', stderr);
161}
162
163void dump_pcc(PCC *pcc)
164{
165 fprintf(stderr, "package: %d ", pcc->pkg);
166 fprintf(stderr, "core:: %d ", pcc->core);
167 fprintf(stderr, "CPU: %d ", pcc->cpu);
168 fprintf(stderr, "TSC: %016llX\n", pcc->tsc);
169 fprintf(stderr, "c3: %016llX\n", pcc->c3);
170 fprintf(stderr, "c6: %016llX\n", pcc->c6);
171 fprintf(stderr, "c7: %016llX\n", pcc->c7);
172 fprintf(stderr, "aperf: %016llX\n", pcc->aperf);
173 fprintf(stderr, "pc2: %016llX\n", pcc->pc2);
174 fprintf(stderr, "pc3: %016llX\n", pcc->pc3);
175 fprintf(stderr, "pc6: %016llX\n", pcc->pc6);
176 fprintf(stderr, "pc7: %016llX\n", pcc->pc7);
177 fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, pcc->extra_msr);
178}
179
180void dump_list(PCC *pcc)
181{
182 printf("dump_list 0x%p\n", pcc);
183
184 for (; pcc; pcc = pcc->next)
185 dump_pcc(pcc);
186}
187
188void print_pcc(PCC *p)
189{
190 double interval_float;
191
192 interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
193
194 /* topology columns, print blanks on 1st (average) line */
195 if (p == pcc_average) {
196 if (show_pkg)
197 fprintf(stderr, " ");
198 if (show_core)
199 fprintf(stderr, " ");
200 if (show_cpu)
201 fprintf(stderr, " ");
202 } else {
203 if (show_pkg)
204 fprintf(stderr, "%4d", p->pkg);
205 if (show_core)
206 fprintf(stderr, "%4d", p->core);
207 if (show_cpu)
208 fprintf(stderr, "%4d", p->cpu);
209 }
210
211 /* %c0 */
212 if (do_nhm_cstates) {
213 if (!skip_c0)
214 fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc);
215 else
216 fprintf(stderr, " ****");
217 }
218
219 /* GHz */
220 if (has_aperf) {
221 if (!aperf_mperf_unstable) {
222 fprintf(stderr, "%5.2f",
223 1.0 * p->tsc / units * p->aperf /
224 p->mperf / interval_float);
225 } else {
226 if (p->aperf > p->tsc || p->mperf > p->tsc) {
227 fprintf(stderr, " ****");
228 } else {
229 fprintf(stderr, "%4.1f*",
230 1.0 * p->tsc /
231 units * p->aperf /
232 p->mperf / interval_float);
233 }
234 }
235 }
236
237 /* TSC */
238 fprintf(stderr, "%5.2f", 1.0 * p->tsc/units/interval_float);
239
240 if (do_nhm_cstates) {
241 if (!skip_c1)
242 fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc);
243 else
244 fprintf(stderr, " ****");
245 }
246 if (do_nhm_cstates)
247 fprintf(stderr, "%7.2f", 100.0 * p->c3/p->tsc);
248 if (do_nhm_cstates)
249 fprintf(stderr, "%7.2f", 100.0 * p->c6/p->tsc);
250 if (do_snb_cstates)
251 fprintf(stderr, "%7.2f", 100.0 * p->c7/p->tsc);
252 if (do_snb_cstates)
253 fprintf(stderr, "%7.2f", 100.0 * p->pc2/p->tsc);
254 if (do_nhm_cstates)
255 fprintf(stderr, "%7.2f", 100.0 * p->pc3/p->tsc);
256 if (do_nhm_cstates)
257 fprintf(stderr, "%7.2f", 100.0 * p->pc6/p->tsc);
258 if (do_snb_cstates)
259 fprintf(stderr, "%7.2f", 100.0 * p->pc7/p->tsc);
260 if (extra_msr_offset)
261 fprintf(stderr, " 0x%016llx", p->extra_msr);
262 putc('\n', stderr);
263}
264
265void print_counters(PCC *cnt)
266{
267 PCC *pcc;
268
269 print_header();
270
271 if (num_cpus > 1)
272 print_pcc(pcc_average);
273
274 for (pcc = cnt; pcc != NULL; pcc = pcc->next)
275 print_pcc(pcc);
276
277}
278
279#define SUBTRACT_COUNTER(after, before, delta) (delta = (after - before), (before > after))
280
281
282int compute_delta(PCC *after, PCC *before, PCC *delta)
283{
284 int errors = 0;
285 int perf_err = 0;
286
287 skip_c0 = skip_c1 = 0;
288
289 for ( ; after && before && delta;
290 after = after->next, before = before->next, delta = delta->next) {
291 if (before->cpu != after->cpu) {
292 printf("cpu configuration changed: %d != %d\n",
293 before->cpu, after->cpu);
294 return -1;
295 }
296
297 if (SUBTRACT_COUNTER(after->tsc, before->tsc, delta->tsc)) {
298 fprintf(stderr, "cpu%d TSC went backwards %llX to %llX\n",
299 before->cpu, before->tsc, after->tsc);
300 errors++;
301 }
302 /* check for TSC < 1 Mcycles over interval */
303 if (delta->tsc < (1000 * 1000)) {
304 fprintf(stderr, "Insanely slow TSC rate,"
305 " TSC stops in idle?\n");
306 fprintf(stderr, "You can disable all c-states"
307 " by booting with \"idle=poll\"\n");
308 fprintf(stderr, "or just the deep ones with"
309 " \"processor.max_cstate=1\"\n");
310 exit(-3);
311 }
312 if (SUBTRACT_COUNTER(after->c3, before->c3, delta->c3)) {
313 fprintf(stderr, "cpu%d c3 counter went backwards %llX to %llX\n",
314 before->cpu, before->c3, after->c3);
315 errors++;
316 }
317 if (SUBTRACT_COUNTER(after->c6, before->c6, delta->c6)) {
318 fprintf(stderr, "cpu%d c6 counter went backwards %llX to %llX\n",
319 before->cpu, before->c6, after->c6);
320 errors++;
321 }
322 if (SUBTRACT_COUNTER(after->c7, before->c7, delta->c7)) {
323 fprintf(stderr, "cpu%d c7 counter went backwards %llX to %llX\n",
324 before->cpu, before->c7, after->c7);
325 errors++;
326 }
327 if (SUBTRACT_COUNTER(after->pc2, before->pc2, delta->pc2)) {
328 fprintf(stderr, "cpu%d pc2 counter went backwards %llX to %llX\n",
329 before->cpu, before->pc2, after->pc2);
330 errors++;
331 }
332 if (SUBTRACT_COUNTER(after->pc3, before->pc3, delta->pc3)) {
333 fprintf(stderr, "cpu%d pc3 counter went backwards %llX to %llX\n",
334 before->cpu, before->pc3, after->pc3);
335 errors++;
336 }
337 if (SUBTRACT_COUNTER(after->pc6, before->pc6, delta->pc6)) {
338 fprintf(stderr, "cpu%d pc6 counter went backwards %llX to %llX\n",
339 before->cpu, before->pc6, after->pc6);
340 errors++;
341 }
342 if (SUBTRACT_COUNTER(after->pc7, before->pc7, delta->pc7)) {
343 fprintf(stderr, "cpu%d pc7 counter went backwards %llX to %llX\n",
344 before->cpu, before->pc7, after->pc7);
345 errors++;
346 }
347
348 perf_err = SUBTRACT_COUNTER(after->aperf, before->aperf, delta->aperf);
349 if (perf_err) {
350 fprintf(stderr, "cpu%d aperf counter went backwards %llX to %llX\n",
351 before->cpu, before->aperf, after->aperf);
352 }
353 perf_err |= SUBTRACT_COUNTER(after->mperf, before->mperf, delta->mperf);
354 if (perf_err) {
355 fprintf(stderr, "cpu%d mperf counter went backwards %llX to %llX\n",
356 before->cpu, before->mperf, after->mperf);
357 }
358 if (perf_err) {
359 if (!aperf_mperf_unstable) {
360 fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname);
361 fprintf(stderr, "* Frequency results do not cover entire interval *\n");
362 fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n");
363
364 aperf_mperf_unstable = 1;
365 }
366 /*
367 * mperf delta is likely a huge "positive" number
368 * can not use it for calculating c0 time
369 */
370 skip_c0 = 1;
371 skip_c1 = 1;
372 }
373
374 /*
375 * As mperf and tsc collection are not atomic,
376 * it is possible for mperf's non-halted cycles
377 * to exceed TSC's all cycles: show c1 = 0% in that case.
378 */
379 if (delta->mperf > delta->tsc)
380 delta->c1 = 0;
381 else /* normal case, derive c1 */
382 delta->c1 = delta->tsc - delta->mperf
383 - delta->c3 - delta->c6 - delta->c7;
384
385 if (delta->mperf == 0)
386 delta->mperf = 1; /* divide by 0 protection */
387
388 /*
389 * for "extra msr", just copy the latest w/o subtracting
390 */
391 delta->extra_msr = after->extra_msr;
392 if (errors) {
393 fprintf(stderr, "ERROR cpu%d before:\n", before->cpu);
394 dump_pcc(before);
395 fprintf(stderr, "ERROR cpu%d after:\n", before->cpu);
396 dump_pcc(after);
397 errors = 0;
398 }
399 }
400 return 0;
401}
402
403void compute_average(PCC *delta, PCC *avg)
404{
405 PCC *sum;
406
407 sum = calloc(1, sizeof(PCC));
408 if (sum == NULL) {
409 perror("calloc sum");
410 exit(1);
411 }
412
413 for (; delta; delta = delta->next) {
414 sum->tsc += delta->tsc;
415 sum->c1 += delta->c1;
416 sum->c3 += delta->c3;
417 sum->c6 += delta->c6;
418 sum->c7 += delta->c7;
419 sum->aperf += delta->aperf;
420 sum->mperf += delta->mperf;
421 sum->pc2 += delta->pc2;
422 sum->pc3 += delta->pc3;
423 sum->pc6 += delta->pc6;
424 sum->pc7 += delta->pc7;
425 }
426 avg->tsc = sum->tsc/num_cpus;
427 avg->c1 = sum->c1/num_cpus;
428 avg->c3 = sum->c3/num_cpus;
429 avg->c6 = sum->c6/num_cpus;
430 avg->c7 = sum->c7/num_cpus;
431 avg->aperf = sum->aperf/num_cpus;
432 avg->mperf = sum->mperf/num_cpus;
433 avg->pc2 = sum->pc2/num_cpus;
434 avg->pc3 = sum->pc3/num_cpus;
435 avg->pc6 = sum->pc6/num_cpus;
436 avg->pc7 = sum->pc7/num_cpus;
437
438 free(sum);
439}
440
441void get_counters(PCC *pcc)
442{
443 for ( ; pcc; pcc = pcc->next) {
444 pcc->tsc = get_msr(pcc->cpu, MSR_TSC);
445 if (do_nhm_cstates)
446 pcc->c3 = get_msr(pcc->cpu, MSR_CORE_C3_RESIDENCY);
447 if (do_nhm_cstates)
448 pcc->c6 = get_msr(pcc->cpu, MSR_CORE_C6_RESIDENCY);
449 if (do_snb_cstates)
450 pcc->c7 = get_msr(pcc->cpu, MSR_CORE_C7_RESIDENCY);
451 if (has_aperf)
452 pcc->aperf = get_msr(pcc->cpu, MSR_APERF);
453 if (has_aperf)
454 pcc->mperf = get_msr(pcc->cpu, MSR_MPERF);
455 if (do_snb_cstates)
456 pcc->pc2 = get_msr(pcc->cpu, MSR_PKG_C2_RESIDENCY);
457 if (do_nhm_cstates)
458 pcc->pc3 = get_msr(pcc->cpu, MSR_PKG_C3_RESIDENCY);
459 if (do_nhm_cstates)
460 pcc->pc6 = get_msr(pcc->cpu, MSR_PKG_C6_RESIDENCY);
461 if (do_snb_cstates)
462 pcc->pc7 = get_msr(pcc->cpu, MSR_PKG_C7_RESIDENCY);
463 if (extra_msr_offset)
464 pcc->extra_msr = get_msr(pcc->cpu, extra_msr_offset);
465 }
466}
467
468
469void print_nehalem_info()
470{
471 unsigned long long msr;
472 unsigned int ratio;
473
474 if (!do_nehalem_platform_info)
475 return;
476
477 msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO);
478
479 ratio = (msr >> 40) & 0xFF;
480 fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
481 ratio, bclk, ratio * bclk);
482
483 ratio = (msr >> 8) & 0xFF;
484 fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n",
485 ratio, bclk, ratio * bclk);
486
487 if (verbose > 1)
488 fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
489
490 if (!do_nehalem_turbo_ratio_limit)
491 return;
492
493 msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT);
494
495 ratio = (msr >> 24) & 0xFF;
496 if (ratio)
497 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
498 ratio, bclk, ratio * bclk);
499
500 ratio = (msr >> 16) & 0xFF;
501 if (ratio)
502 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n",
503 ratio, bclk, ratio * bclk);
504
505 ratio = (msr >> 8) & 0xFF;
506 if (ratio)
507 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n",
508 ratio, bclk, ratio * bclk);
509
510 ratio = (msr >> 0) & 0xFF;
511 if (ratio)
512 fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
513 ratio, bclk, ratio * bclk);
514
515}
516
517void free_counter_list(PCC *list)
518{
519 PCC *p;
520
521 for (p = list; p; ) {
522 PCC *free_me;
523
524 free_me = p;
525 p = p->next;
526 free(free_me);
527 }
528 return;
529}
530
531void free_all_counters(void)
532{
533 free_counter_list(pcc_even);
534 pcc_even = NULL;
535
536 free_counter_list(pcc_odd);
537 pcc_odd = NULL;
538
539 free_counter_list(pcc_delta);
540 pcc_delta = NULL;
541
542 free_counter_list(pcc_average);
543 pcc_average = NULL;
544}
545
546void insert_cpu_counters(PCC **list, PCC *new)
547{
548 PCC *prev;
549
550 /*
551 * list was empty
552 */
553 if (*list == NULL) {
554 new->next = *list;
555 *list = new;
556 return;
557 }
558
559 show_cpu = 1; /* there is more than one CPU */
560
561 /*
562 * insert on front of list.
563 * It is sorted by ascending package#, core#, cpu#
564 */
565 if (((*list)->pkg > new->pkg) ||
566 (((*list)->pkg == new->pkg) && ((*list)->core > new->core)) ||
567 (((*list)->pkg == new->pkg) && ((*list)->core == new->core) && ((*list)->cpu > new->cpu))) {
568 new->next = *list;
569 *list = new;
570 return;
571 }
572
573 prev = *list;
574
575 while (prev->next && (prev->next->pkg < new->pkg)) {
576 prev = prev->next;
577 show_pkg = 1; /* there is more than 1 package */
578 }
579
580 while (prev->next && (prev->next->pkg == new->pkg)
581 && (prev->next->core < new->core)) {
582 prev = prev->next;
583 show_core = 1; /* there is more than 1 core */
584 }
585
586 while (prev->next && (prev->next->pkg == new->pkg)
587 && (prev->next->core == new->core)
588 && (prev->next->cpu < new->cpu)) {
589 prev = prev->next;
590 }
591
592 /*
593 * insert after "prev"
594 */
595 new->next = prev->next;
596 prev->next = new;
597
598 return;
599}
600
601void alloc_new_cpu_counters(int pkg, int core, int cpu)
602{
603 PCC *new;
604
605 if (verbose > 1)
606 printf("pkg%d core%d, cpu%d\n", pkg, core, cpu);
607
608 new = (PCC *)calloc(1, sizeof(PCC));
609 if (new == NULL) {
610 perror("calloc");
611 exit(1);
612 }
613 new->pkg = pkg;
614 new->core = core;
615 new->cpu = cpu;
616 insert_cpu_counters(&pcc_odd, new);
617
618 new = (PCC *)calloc(1, sizeof(PCC));
619 if (new == NULL) {
620 perror("calloc");
621 exit(1);
622 }
623 new->pkg = pkg;
624 new->core = core;
625 new->cpu = cpu;
626 insert_cpu_counters(&pcc_even, new);
627
628 new = (PCC *)calloc(1, sizeof(PCC));
629 if (new == NULL) {
630 perror("calloc");
631 exit(1);
632 }
633 new->pkg = pkg;
634 new->core = core;
635 new->cpu = cpu;
636 insert_cpu_counters(&pcc_delta, new);
637
638 new = (PCC *)calloc(1, sizeof(PCC));
639 if (new == NULL) {
640 perror("calloc");
641 exit(1);
642 }
643 new->pkg = pkg;
644 new->core = core;
645 new->cpu = cpu;
646 pcc_average = new;
647}
648
649int get_physical_package_id(int cpu)
650{
651 char path[64];
652 FILE *filep;
653 int pkg;
654
655 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
656 filep = fopen(path, "r");
657 if (filep == NULL) {
658 perror(path);
659 exit(1);
660 }
661 fscanf(filep, "%d", &pkg);
662 fclose(filep);
663 return pkg;
664}
665
666int get_core_id(int cpu)
667{
668 char path[64];
669 FILE *filep;
670 int core;
671
672 sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
673 filep = fopen(path, "r");
674 if (filep == NULL) {
675 perror(path);
676 exit(1);
677 }
678 fscanf(filep, "%d", &core);
679 fclose(filep);
680 return core;
681}
682
683/*
684 * run func(index, cpu) on every cpu in /proc/stat
685 */
686
687int for_all_cpus(void (func)(int, int, int))
688{
689 FILE *fp;
690 int cpu_count;
691 int retval;
692
693 fp = fopen(proc_stat, "r");
694 if (fp == NULL) {
695 perror(proc_stat);
696 exit(1);
697 }
698
699 retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
700 if (retval != 0) {
701 perror("/proc/stat format");
702 exit(1);
703 }
704
705 for (cpu_count = 0; ; cpu_count++) {
706 int cpu;
707
708 retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu);
709 if (retval != 1)
710 break;
711
712 func(get_physical_package_id(cpu), get_core_id(cpu), cpu);
713 }
714 fclose(fp);
715 return cpu_count;
716}
717
718void re_initialize(void)
719{
720 printf("turbostat: topology changed, re-initializing.\n");
721 free_all_counters();
722 num_cpus = for_all_cpus(alloc_new_cpu_counters);
723 need_reinitialize = 0;
724 printf("num_cpus is now %d\n", num_cpus);
725}
726
727void dummy(int pkg, int core, int cpu) { return; }
728/*
729 * check to see if a cpu came on-line
730 */
731void verify_num_cpus()
732{
733 int new_num_cpus;
734
735 new_num_cpus = for_all_cpus(dummy);
736
737 if (new_num_cpus != num_cpus) {
738 if (verbose)
739 printf("num_cpus was %d, is now %d\n",
740 num_cpus, new_num_cpus);
741 need_reinitialize = 1;
742 }
743
744 return;
745}
746
747void turbostat_loop()
748{
749restart:
750 get_counters(pcc_even);
751 gettimeofday(&tv_even, (struct timezone *)NULL);
752
753 while (1) {
754 verify_num_cpus();
755 if (need_reinitialize) {
756 re_initialize();
757 goto restart;
758 }
759 sleep(interval_sec);
760 get_counters(pcc_odd);
761 gettimeofday(&tv_odd, (struct timezone *)NULL);
762
763 compute_delta(pcc_odd, pcc_even, pcc_delta);
764 timersub(&tv_odd, &tv_even, &tv_delta);
765 compute_average(pcc_delta, pcc_average);
766 print_counters(pcc_delta);
767 if (need_reinitialize) {
768 re_initialize();
769 goto restart;
770 }
771 sleep(interval_sec);
772 get_counters(pcc_even);
773 gettimeofday(&tv_even, (struct timezone *)NULL);
774 compute_delta(pcc_even, pcc_odd, pcc_delta);
775 timersub(&tv_even, &tv_odd, &tv_delta);
776 compute_average(pcc_delta, pcc_average);
777 print_counters(pcc_delta);
778 }
779}
780
781void check_dev_msr()
782{
783 struct stat sb;
784
785 if (stat("/dev/cpu/0/msr", &sb)) {
786 fprintf(stderr, "no /dev/cpu/0/msr\n");
787 fprintf(stderr, "Try \"# modprobe msr\"\n");
788 exit(-5);
789 }
790}
791
792void check_super_user()
793{
794 if (getuid() != 0) {
795 fprintf(stderr, "must be root\n");
796 exit(-6);
797 }
798}
799
800int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
801{
802 if (!genuine_intel)
803 return 0;
804
805 if (family != 6)
806 return 0;
807
808 switch (model) {
809 case 0x1A: /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
810 case 0x1E: /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
811 case 0x1F: /* Core i7 and i5 Processor - Nehalem */
812 case 0x25: /* Westmere Client - Clarkdale, Arrandale */
813 case 0x2C: /* Westmere EP - Gulftown */
814 case 0x2A: /* SNB */
815 case 0x2D: /* SNB Xeon */
816 return 1;
817 case 0x2E: /* Nehalem-EX Xeon - Beckton */
818 case 0x2F: /* Westmere-EX Xeon - Eagleton */
819 default:
820 return 0;
821 }
822}
823
824int is_snb(unsigned int family, unsigned int model)
825{
826 if (!genuine_intel)
827 return 0;
828
829 switch (model) {
830 case 0x2A:
831 case 0x2D:
832 return 1;
833 }
834 return 0;
835}
836
837double discover_bclk(unsigned int family, unsigned int model)
838{
839 if (is_snb(family, model))
840 return 100.00;
841 else
842 return 133.33;
843}
844
845void check_cpuid()
846{
847 unsigned int eax, ebx, ecx, edx, max_level;
848 unsigned int fms, family, model, stepping;
849
850 eax = ebx = ecx = edx = 0;
851
852 asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0));
853
854 if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
855 genuine_intel = 1;
856
857 if (verbose)
858 fprintf(stderr, "%.4s%.4s%.4s ",
859 (char *)&ebx, (char *)&edx, (char *)&ecx);
860
861 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
862 family = (fms >> 8) & 0xf;
863 model = (fms >> 4) & 0xf;
864 stepping = fms & 0xf;
865 if (family == 6 || family == 0xf)
866 model += ((fms >> 16) & 0xf) << 4;
867
868 if (verbose)
869 fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
870 max_level, family, model, stepping, family, model, stepping);
871
872 if (!(edx & (1 << 5))) {
873 fprintf(stderr, "CPUID: no MSR\n");
874 exit(1);
875 }
876
877 /*
878 * check max extended function levels of CPUID.
879 * This is needed to check for invariant TSC.
880 * This check is valid for both Intel and AMD.
881 */
882 ebx = ecx = edx = 0;
883 asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000));
884
885 if (max_level < 0x80000007) {
886 fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level);
887 exit(1);
888 }
889
890 /*
891 * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8
892 * this check is valid for both Intel and AMD
893 */
894 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007));
895 has_invariant_tsc = edx && (1 << 8);
896
897 if (!has_invariant_tsc) {
898 fprintf(stderr, "No invariant TSC\n");
899 exit(1);
900 }
901
902 /*
903 * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0
904 * this check is valid for both Intel and AMD
905 */
906
907 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6));
908 has_aperf = ecx && (1 << 0);
909 if (!has_aperf) {
910 fprintf(stderr, "No APERF MSR\n");
911 exit(1);
912 }
913
914 do_nehalem_platform_info = genuine_intel && has_invariant_tsc;
915 do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */
916 do_snb_cstates = is_snb(family, model);
917 bclk = discover_bclk(family, model);
918
919 do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
920}
921
922
923void usage()
924{
925 fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",
926 progname);
927 exit(1);
928}
929
930
931/*
932 * in /dev/cpu/ return success for names that are numbers
933 * ie. filter out ".", "..", "microcode".
934 */
935int dir_filter(const struct dirent *dirp)
936{
937 if (isdigit(dirp->d_name[0]))
938 return 1;
939 else
940 return 0;
941}
942
943int open_dev_cpu_msr(int dummy1)
944{
945 return 0;
946}
947
948void turbostat_init()
949{
950 check_cpuid();
951
952 check_dev_msr();
953 check_super_user();
954
955 num_cpus = for_all_cpus(alloc_new_cpu_counters);
956
957 if (verbose)
958 print_nehalem_info();
959}
960
961int fork_it(char **argv)
962{
963 int retval;
964 pid_t child_pid;
965 get_counters(pcc_even);
966 gettimeofday(&tv_even, (struct timezone *)NULL);
967
968 child_pid = fork();
969 if (!child_pid) {
970 /* child */
971 execvp(argv[0], argv);
972 } else {
973 int status;
974
975 /* parent */
976 if (child_pid == -1) {
977 perror("fork");
978 exit(1);
979 }
980
981 signal(SIGINT, SIG_IGN);
982 signal(SIGQUIT, SIG_IGN);
983 if (waitpid(child_pid, &status, 0) == -1) {
984 perror("wait");
985 exit(1);
986 }
987 }
988 get_counters(pcc_odd);
989 gettimeofday(&tv_odd, (struct timezone *)NULL);
990 retval = compute_delta(pcc_odd, pcc_even, pcc_delta);
991
992 timersub(&tv_odd, &tv_even, &tv_delta);
993 compute_average(pcc_delta, pcc_average);
994 if (!retval)
995 print_counters(pcc_delta);
996
997 fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);;
998
999 return 0;
1000}
1001
1002void cmdline(int argc, char **argv)
1003{
1004 int opt;
1005
1006 progname = argv[0];
1007
1008 while ((opt = getopt(argc, argv, "+vi:M:")) != -1) {
1009 switch (opt) {
1010 case 'v':
1011 verbose++;
1012 break;
1013 case 'i':
1014 interval_sec = atoi(optarg);
1015 break;
1016 case 'M':
1017 sscanf(optarg, "%x", &extra_msr_offset);
1018 if (verbose > 1)
1019 fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
1020 break;
1021 default:
1022 usage();
1023 }
1024 }
1025}
1026
1027int main(int argc, char **argv)
1028{
1029 cmdline(argc, argv);
1030
1031 if (verbose > 1)
1032 fprintf(stderr, "turbostat Dec 6, 2010"
1033 " - Len Brown <lenb@kernel.org>\n");
1034 if (verbose > 1)
1035 fprintf(stderr, "http://userweb.kernel.org/~lenb/acpi/utils/pmtools/turbostat/\n");
1036
1037 turbostat_init();
1038
1039 /*
1040 * if any params left, it must be a command to fork
1041 */
1042 if (argc - optind)
1043 return fork_it(argv + optind);
1044 else
1045 turbostat_loop();
1046
1047 return 0;
1048}
diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile
new file mode 100644
index 000000000000..f458237fdd79
--- /dev/null
+++ b/tools/power/x86/x86_energy_perf_policy/Makefile
@@ -0,0 +1,8 @@
1x86_energy_perf_policy : x86_energy_perf_policy.c
2
3clean :
4 rm -f x86_energy_perf_policy
5
6install :
7 install x86_energy_perf_policy /usr/bin/
8 install x86_energy_perf_policy.8 /usr/share/man/man8/
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8
new file mode 100644
index 000000000000..8eaaad648cdb
--- /dev/null
+++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8
@@ -0,0 +1,104 @@
1.\" This page Copyright (C) 2010 Len Brown <len.brown@intel.com>
2.\" Distributed under the GPL, Copyleft 1994.
3.TH X86_ENERGY_PERF_POLICY 8
4.SH NAME
5x86_energy_perf_policy \- read or write MSR_IA32_ENERGY_PERF_BIAS
6.SH SYNOPSIS
7.ft B
8.B x86_energy_perf_policy
9.RB [ "\-c cpu" ]
10.RB [ "\-v" ]
11.RB "\-r"
12.br
13.B x86_energy_perf_policy
14.RB [ "\-c cpu" ]
15.RB [ "\-v" ]
16.RB 'performance'
17.br
18.B x86_energy_perf_policy
19.RB [ "\-c cpu" ]
20.RB [ "\-v" ]
21.RB 'normal'
22.br
23.B x86_energy_perf_policy
24.RB [ "\-c cpu" ]
25.RB [ "\-v" ]
26.RB 'powersave'
27.br
28.B x86_energy_perf_policy
29.RB [ "\-c cpu" ]
30.RB [ "\-v" ]
31.RB n
32.br
33.SH DESCRIPTION
34\fBx86_energy_perf_policy\fP
35allows software to convey
36its policy for the relative importance of performance
37versus energy savings to the processor.
38
39The processor uses this information in model-specific ways
40when it must select trade-offs between performance and
41energy efficiency.
42
43This policy hint does not supersede Processor Performance states
44(P-states) or CPU Idle power states (C-states), but allows
45software to have influence where it would otherwise be unable
46to express a preference.
47
48For example, this setting may tell the hardware how
49aggressively or conservatively to control frequency
50in the "turbo range" above the explicitly OS-controlled
51P-state frequency range. It may also tell the hardware
52how aggressively is should enter the OS requested C-states.
53
54Support for this feature is indicated by CPUID.06H.ECX.bit3
55per the Intel Architectures Software Developer's Manual.
56
57.SS Options
58\fB-c\fP limits operation to a single CPU.
59The default is to operate on all CPUs.
60Note that MSR_IA32_ENERGY_PERF_BIAS is defined per
61logical processor, but that the initial implementations
62of the MSR were shared among all processors in each package.
63.PP
64\fB-v\fP increases verbosity. By default
65x86_energy_perf_policy is silent.
66.PP
67\fB-r\fP is for "read-only" mode - the unchanged state
68is read and displayed.
69.PP
70.I performance
71Set a policy where performance is paramount.
72The processor will be unwilling to sacrifice any performance
73for the sake of energy saving. This is the hardware default.
74.PP
75.I normal
76Set a policy with a normal balance between performance and energy efficiency.
77The processor will tolerate minor performance compromise
78for potentially significant energy savings.
79This reasonable default for most desktops and servers.
80.PP
81.I powersave
82Set a policy where the processor can accept
83a measurable performance hit to maximize energy efficiency.
84.PP
85.I n
86Set MSR_IA32_ENERGY_PERF_BIAS to the specified number.
87The range of valid numbers is 0-15, where 0 is maximum
88performance and 15 is maximum energy efficiency.
89
90.SH NOTES
91.B "x86_energy_perf_policy "
92runs only as root.
93.SH FILES
94.ta
95.nf
96/dev/cpu/*/msr
97.fi
98
99.SH "SEE ALSO"
100msr(4)
101.PP
102.SH AUTHORS
103.nf
104Written by Len Brown <len.brown@intel.com>
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
new file mode 100644
index 000000000000..d9678a34dd70
--- /dev/null
+++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
@@ -0,0 +1,325 @@
1/*
2 * x86_energy_perf_policy -- set the energy versus performance
3 * policy preference bias on recent X86 processors.
4 */
5/*
6 * Copyright (c) 2010, Intel Corporation.
7 * Len Brown <len.brown@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include <stdio.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/resource.h>
28#include <fcntl.h>
29#include <signal.h>
30#include <sys/time.h>
31#include <stdlib.h>
32#include <string.h>
33
34unsigned int verbose; /* set with -v */
35unsigned int read_only; /* set with -r */
36char *progname;
37unsigned long long new_bias;
38int cpu = -1;
39
40/*
41 * Usage:
42 *
43 * -c cpu: limit action to a single CPU (default is all CPUs)
44 * -v: verbose output (can invoke more than once)
45 * -r: read-only, don't change any settings
46 *
47 * performance
48 * Performance is paramount.
49 * Unwilling to sacrafice any performance
50 * for the sake of energy saving. (hardware default)
51 *
52 * normal
53 * Can tolerate minor performance compromise
54 * for potentially significant energy savings.
55 * (reasonable default for most desktops and servers)
56 *
57 * powersave
58 * Can tolerate significant performance hit
59 * to maximize energy savings.
60 *
61 * n
62 * a numerical value to write to the underlying MSR.
63 */
64void usage(void)
65{
66 printf("%s: [-c cpu] [-v] "
67 "(-r | 'performance' | 'normal' | 'powersave' | n)\n",
68 progname);
69 exit(1);
70}
71
72#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0
73
74#define BIAS_PERFORMANCE 0
75#define BIAS_BALANCE 6
76#define BIAS_POWERSAVE 15
77
78void cmdline(int argc, char **argv)
79{
80 int opt;
81
82 progname = argv[0];
83
84 while ((opt = getopt(argc, argv, "+rvc:")) != -1) {
85 switch (opt) {
86 case 'c':
87 cpu = atoi(optarg);
88 break;
89 case 'r':
90 read_only = 1;
91 break;
92 case 'v':
93 verbose++;
94 break;
95 default:
96 usage();
97 }
98 }
99 /* if -r, then should be no additional optind */
100 if (read_only && (argc > optind))
101 usage();
102
103 /*
104 * if no -r , then must be one additional optind
105 */
106 if (!read_only) {
107
108 if (argc != optind + 1) {
109 printf("must supply -r or policy param\n");
110 usage();
111 }
112
113 if (!strcmp("performance", argv[optind])) {
114 new_bias = BIAS_PERFORMANCE;
115 } else if (!strcmp("normal", argv[optind])) {
116 new_bias = BIAS_BALANCE;
117 } else if (!strcmp("powersave", argv[optind])) {
118 new_bias = BIAS_POWERSAVE;
119 } else {
120 char *endptr;
121
122 new_bias = strtoull(argv[optind], &endptr, 0);
123 if (endptr == argv[optind] ||
124 new_bias > BIAS_POWERSAVE) {
125 fprintf(stderr, "invalid value: %s\n",
126 argv[optind]);
127 usage();
128 }
129 }
130 }
131}
132
133/*
134 * validate_cpuid()
135 * returns on success, quietly exits on failure (make verbose with -v)
136 */
137void validate_cpuid(void)
138{
139 unsigned int eax, ebx, ecx, edx, max_level;
140 char brand[16];
141 unsigned int fms, family, model, stepping;
142
143 eax = ebx = ecx = edx = 0;
144
145 asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx),
146 "=d" (edx) : "a" (0));
147
148 if (ebx != 0x756e6547 || edx != 0x49656e69 || ecx != 0x6c65746e) {
149 if (verbose)
150 fprintf(stderr, "%.4s%.4s%.4s != GenuineIntel",
151 (char *)&ebx, (char *)&edx, (char *)&ecx);
152 exit(1);
153 }
154
155 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
156 family = (fms >> 8) & 0xf;
157 model = (fms >> 4) & 0xf;
158 stepping = fms & 0xf;
159 if (family == 6 || family == 0xf)
160 model += ((fms >> 16) & 0xf) << 4;
161
162 if (verbose > 1)
163 printf("CPUID %s %d levels family:model:stepping "
164 "0x%x:%x:%x (%d:%d:%d)\n", brand, max_level,
165 family, model, stepping, family, model, stepping);
166
167 if (!(edx & (1 << 5))) {
168 if (verbose)
169 printf("CPUID: no MSR\n");
170 exit(1);
171 }
172
173 /*
174 * Support for MSR_IA32_ENERGY_PERF_BIAS
175 * is indicated by CPUID.06H.ECX.bit3
176 */
177 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (6));
178 if (verbose)
179 printf("CPUID.06H.ECX: 0x%x\n", ecx);
180 if (!(ecx & (1 << 3))) {
181 if (verbose)
182 printf("CPUID: No MSR_IA32_ENERGY_PERF_BIAS\n");
183 exit(1);
184 }
185 return; /* success */
186}
187
188unsigned long long get_msr(int cpu, int offset)
189{
190 unsigned long long msr;
191 char msr_path[32];
192 int retval;
193 int fd;
194
195 sprintf(msr_path, "/dev/cpu/%d/msr", cpu);
196 fd = open(msr_path, O_RDONLY);
197 if (fd < 0) {
198 printf("Try \"# modprobe msr\"\n");
199 perror(msr_path);
200 exit(1);
201 }
202
203 retval = pread(fd, &msr, sizeof msr, offset);
204
205 if (retval != sizeof msr) {
206 printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval);
207 exit(-2);
208 }
209 close(fd);
210 return msr;
211}
212
213unsigned long long put_msr(int cpu, unsigned long long new_msr, int offset)
214{
215 unsigned long long old_msr;
216 char msr_path[32];
217 int retval;
218 int fd;
219
220 sprintf(msr_path, "/dev/cpu/%d/msr", cpu);
221 fd = open(msr_path, O_RDWR);
222 if (fd < 0) {
223 perror(msr_path);
224 exit(1);
225 }
226
227 retval = pread(fd, &old_msr, sizeof old_msr, offset);
228 if (retval != sizeof old_msr) {
229 perror("pwrite");
230 printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval);
231 exit(-2);
232 }
233
234 retval = pwrite(fd, &new_msr, sizeof new_msr, offset);
235 if (retval != sizeof new_msr) {
236 perror("pwrite");
237 printf("pwrite cpu%d 0x%x = %d\n", cpu, offset, retval);
238 exit(-2);
239 }
240
241 close(fd);
242
243 return old_msr;
244}
245
246void print_msr(int cpu)
247{
248 printf("cpu%d: 0x%016llx\n",
249 cpu, get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS));
250}
251
252void update_msr(int cpu)
253{
254 unsigned long long previous_msr;
255
256 previous_msr = put_msr(cpu, new_bias, MSR_IA32_ENERGY_PERF_BIAS);
257
258 if (verbose)
259 printf("cpu%d msr0x%x 0x%016llx -> 0x%016llx\n",
260 cpu, MSR_IA32_ENERGY_PERF_BIAS, previous_msr, new_bias);
261
262 return;
263}
264
265char *proc_stat = "/proc/stat";
266/*
267 * run func() on every cpu in /dev/cpu
268 */
269void for_every_cpu(void (func)(int))
270{
271 FILE *fp;
272 int retval;
273
274 fp = fopen(proc_stat, "r");
275 if (fp == NULL) {
276 perror(proc_stat);
277 exit(1);
278 }
279
280 retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
281 if (retval != 0) {
282 perror("/proc/stat format");
283 exit(1);
284 }
285
286 while (1) {
287 int cpu;
288
289 retval = fscanf(fp,
290 "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n",
291 &cpu);
292 if (retval != 1)
293 return;
294
295 func(cpu);
296 }
297 fclose(fp);
298}
299
300int main(int argc, char **argv)
301{
302 cmdline(argc, argv);
303
304 if (verbose > 1)
305 printf("x86_energy_perf_policy Nov 24, 2010"
306 " - Len Brown <lenb@kernel.org>\n");
307 if (verbose > 1 && !read_only)
308 printf("new_bias %lld\n", new_bias);
309
310 validate_cpuid();
311
312 if (cpu != -1) {
313 if (read_only)
314 print_msr(cpu);
315 else
316 update_msr(cpu);
317 } else {
318 if (read_only)
319 for_every_cpu(print_msr);
320 else
321 for_every_cpu(update_msr);
322 }
323
324 return 0;
325}
diff --git a/tools/slub/slabinfo.c b/tools/slub/slabinfo.c
new file mode 100644
index 000000000000..516551c9f172
--- /dev/null
+++ b/tools/slub/slabinfo.c
@@ -0,0 +1,1364 @@
1/*
2 * Slabinfo: Tool to get reports about slabs
3 *
4 * (C) 2007 sgi, Christoph Lameter
5 *
6 * Compile by:
7 *
8 * gcc -o slabinfo slabinfo.c
9 */
10#include <stdio.h>
11#include <stdlib.h>
12#include <sys/types.h>
13#include <dirent.h>
14#include <strings.h>
15#include <string.h>
16#include <unistd.h>
17#include <stdarg.h>
18#include <getopt.h>
19#include <regex.h>
20#include <errno.h>
21
22#define MAX_SLABS 500
23#define MAX_ALIASES 500
24#define MAX_NODES 1024
25
26struct slabinfo {
27 char *name;
28 int alias;
29 int refs;
30 int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
31 int hwcache_align, object_size, objs_per_slab;
32 int sanity_checks, slab_size, store_user, trace;
33 int order, poison, reclaim_account, red_zone;
34 unsigned long partial, objects, slabs, objects_partial, objects_total;
35 unsigned long alloc_fastpath, alloc_slowpath;
36 unsigned long free_fastpath, free_slowpath;
37 unsigned long free_frozen, free_add_partial, free_remove_partial;
38 unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
39 unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
40 unsigned long deactivate_to_head, deactivate_to_tail;
41 unsigned long deactivate_remote_frees, order_fallback;
42 int numa[MAX_NODES];
43 int numa_partial[MAX_NODES];
44} slabinfo[MAX_SLABS];
45
46struct aliasinfo {
47 char *name;
48 char *ref;
49 struct slabinfo *slab;
50} aliasinfo[MAX_ALIASES];
51
52int slabs = 0;
53int actual_slabs = 0;
54int aliases = 0;
55int alias_targets = 0;
56int highest_node = 0;
57
58char buffer[4096];
59
60int show_empty = 0;
61int show_report = 0;
62int show_alias = 0;
63int show_slab = 0;
64int skip_zero = 1;
65int show_numa = 0;
66int show_track = 0;
67int show_first_alias = 0;
68int validate = 0;
69int shrink = 0;
70int show_inverted = 0;
71int show_single_ref = 0;
72int show_totals = 0;
73int sort_size = 0;
74int sort_active = 0;
75int set_debug = 0;
76int show_ops = 0;
77int show_activity = 0;
78
79/* Debug options */
80int sanity = 0;
81int redzone = 0;
82int poison = 0;
83int tracking = 0;
84int tracing = 0;
85
86int page_size;
87
88regex_t pattern;
89
90static void fatal(const char *x, ...)
91{
92 va_list ap;
93
94 va_start(ap, x);
95 vfprintf(stderr, x, ap);
96 va_end(ap);
97 exit(EXIT_FAILURE);
98}
99
100static void usage(void)
101{
102 printf("slabinfo 5/7/2007. (c) 2007 sgi.\n\n"
103 "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
104 "-a|--aliases Show aliases\n"
105 "-A|--activity Most active slabs first\n"
106 "-d<options>|--debug=<options> Set/Clear Debug options\n"
107 "-D|--display-active Switch line format to activity\n"
108 "-e|--empty Show empty slabs\n"
109 "-f|--first-alias Show first alias\n"
110 "-h|--help Show usage information\n"
111 "-i|--inverted Inverted list\n"
112 "-l|--slabs Show slabs\n"
113 "-n|--numa Show NUMA information\n"
114 "-o|--ops Show kmem_cache_ops\n"
115 "-s|--shrink Shrink slabs\n"
116 "-r|--report Detailed report on single slabs\n"
117 "-S|--Size Sort by size\n"
118 "-t|--tracking Show alloc/free information\n"
119 "-T|--Totals Show summary information\n"
120 "-v|--validate Validate slabs\n"
121 "-z|--zero Include empty slabs\n"
122 "-1|--1ref Single reference\n"
123 "\nValid debug options (FZPUT may be combined)\n"
124 "a / A Switch on all debug options (=FZUP)\n"
125 "- Switch off all debug options\n"
126 "f / F Sanity Checks (SLAB_DEBUG_FREE)\n"
127 "z / Z Redzoning\n"
128 "p / P Poisoning\n"
129 "u / U Tracking\n"
130 "t / T Tracing\n"
131 );
132}
133
134static unsigned long read_obj(const char *name)
135{
136 FILE *f = fopen(name, "r");
137
138 if (!f)
139 buffer[0] = 0;
140 else {
141 if (!fgets(buffer, sizeof(buffer), f))
142 buffer[0] = 0;
143 fclose(f);
144 if (buffer[strlen(buffer)] == '\n')
145 buffer[strlen(buffer)] = 0;
146 }
147 return strlen(buffer);
148}
149
150
151/*
152 * Get the contents of an attribute
153 */
154static unsigned long get_obj(const char *name)
155{
156 if (!read_obj(name))
157 return 0;
158
159 return atol(buffer);
160}
161
162static unsigned long get_obj_and_str(const char *name, char **x)
163{
164 unsigned long result = 0;
165 char *p;
166
167 *x = NULL;
168
169 if (!read_obj(name)) {
170 x = NULL;
171 return 0;
172 }
173 result = strtoul(buffer, &p, 10);
174 while (*p == ' ')
175 p++;
176 if (*p)
177 *x = strdup(p);
178 return result;
179}
180
181static void set_obj(struct slabinfo *s, const char *name, int n)
182{
183 char x[100];
184 FILE *f;
185
186 snprintf(x, 100, "%s/%s", s->name, name);
187 f = fopen(x, "w");
188 if (!f)
189 fatal("Cannot write to %s\n", x);
190
191 fprintf(f, "%d\n", n);
192 fclose(f);
193}
194
195static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
196{
197 char x[100];
198 FILE *f;
199 size_t l;
200
201 snprintf(x, 100, "%s/%s", s->name, name);
202 f = fopen(x, "r");
203 if (!f) {
204 buffer[0] = 0;
205 l = 0;
206 } else {
207 l = fread(buffer, 1, sizeof(buffer), f);
208 buffer[l] = 0;
209 fclose(f);
210 }
211 return l;
212}
213
214
215/*
216 * Put a size string together
217 */
218static int store_size(char *buffer, unsigned long value)
219{
220 unsigned long divisor = 1;
221 char trailer = 0;
222 int n;
223
224 if (value > 1000000000UL) {
225 divisor = 100000000UL;
226 trailer = 'G';
227 } else if (value > 1000000UL) {
228 divisor = 100000UL;
229 trailer = 'M';
230 } else if (value > 1000UL) {
231 divisor = 100;
232 trailer = 'K';
233 }
234
235 value /= divisor;
236 n = sprintf(buffer, "%ld",value);
237 if (trailer) {
238 buffer[n] = trailer;
239 n++;
240 buffer[n] = 0;
241 }
242 if (divisor != 1) {
243 memmove(buffer + n - 2, buffer + n - 3, 4);
244 buffer[n-2] = '.';
245 n++;
246 }
247 return n;
248}
249
250static void decode_numa_list(int *numa, char *t)
251{
252 int node;
253 int nr;
254
255 memset(numa, 0, MAX_NODES * sizeof(int));
256
257 if (!t)
258 return;
259
260 while (*t == 'N') {
261 t++;
262 node = strtoul(t, &t, 10);
263 if (*t == '=') {
264 t++;
265 nr = strtoul(t, &t, 10);
266 numa[node] = nr;
267 if (node > highest_node)
268 highest_node = node;
269 }
270 while (*t == ' ')
271 t++;
272 }
273}
274
275static void slab_validate(struct slabinfo *s)
276{
277 if (strcmp(s->name, "*") == 0)
278 return;
279
280 set_obj(s, "validate", 1);
281}
282
283static void slab_shrink(struct slabinfo *s)
284{
285 if (strcmp(s->name, "*") == 0)
286 return;
287
288 set_obj(s, "shrink", 1);
289}
290
291int line = 0;
292
293static void first_line(void)
294{
295 if (show_activity)
296 printf("Name Objects Alloc Free %%Fast Fallb O\n");
297 else
298 printf("Name Objects Objsize Space "
299 "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
300}
301
302/*
303 * Find the shortest alias of a slab
304 */
305static struct aliasinfo *find_one_alias(struct slabinfo *find)
306{
307 struct aliasinfo *a;
308 struct aliasinfo *best = NULL;
309
310 for(a = aliasinfo;a < aliasinfo + aliases; a++) {
311 if (a->slab == find &&
312 (!best || strlen(best->name) < strlen(a->name))) {
313 best = a;
314 if (strncmp(a->name,"kmall", 5) == 0)
315 return best;
316 }
317 }
318 return best;
319}
320
321static unsigned long slab_size(struct slabinfo *s)
322{
323 return s->slabs * (page_size << s->order);
324}
325
326static unsigned long slab_activity(struct slabinfo *s)
327{
328 return s->alloc_fastpath + s->free_fastpath +
329 s->alloc_slowpath + s->free_slowpath;
330}
331
332static void slab_numa(struct slabinfo *s, int mode)
333{
334 int node;
335
336 if (strcmp(s->name, "*") == 0)
337 return;
338
339 if (!highest_node) {
340 printf("\n%s: No NUMA information available.\n", s->name);
341 return;
342 }
343
344 if (skip_zero && !s->slabs)
345 return;
346
347 if (!line) {
348 printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
349 for(node = 0; node <= highest_node; node++)
350 printf(" %4d", node);
351 printf("\n----------------------");
352 for(node = 0; node <= highest_node; node++)
353 printf("-----");
354 printf("\n");
355 }
356 printf("%-21s ", mode ? "All slabs" : s->name);
357 for(node = 0; node <= highest_node; node++) {
358 char b[20];
359
360 store_size(b, s->numa[node]);
361 printf(" %4s", b);
362 }
363 printf("\n");
364 if (mode) {
365 printf("%-21s ", "Partial slabs");
366 for(node = 0; node <= highest_node; node++) {
367 char b[20];
368
369 store_size(b, s->numa_partial[node]);
370 printf(" %4s", b);
371 }
372 printf("\n");
373 }
374 line++;
375}
376
377static void show_tracking(struct slabinfo *s)
378{
379 printf("\n%s: Kernel object allocation\n", s->name);
380 printf("-----------------------------------------------------------------------\n");
381 if (read_slab_obj(s, "alloc_calls"))
382 printf(buffer);
383 else
384 printf("No Data\n");
385
386 printf("\n%s: Kernel object freeing\n", s->name);
387 printf("------------------------------------------------------------------------\n");
388 if (read_slab_obj(s, "free_calls"))
389 printf(buffer);
390 else
391 printf("No Data\n");
392
393}
394
395static void ops(struct slabinfo *s)
396{
397 if (strcmp(s->name, "*") == 0)
398 return;
399
400 if (read_slab_obj(s, "ops")) {
401 printf("\n%s: kmem_cache operations\n", s->name);
402 printf("--------------------------------------------\n");
403 printf(buffer);
404 } else
405 printf("\n%s has no kmem_cache operations\n", s->name);
406}
407
408static const char *onoff(int x)
409{
410 if (x)
411 return "On ";
412 return "Off";
413}
414
415static void slab_stats(struct slabinfo *s)
416{
417 unsigned long total_alloc;
418 unsigned long total_free;
419 unsigned long total;
420
421 if (!s->alloc_slab)
422 return;
423
424 total_alloc = s->alloc_fastpath + s->alloc_slowpath;
425 total_free = s->free_fastpath + s->free_slowpath;
426
427 if (!total_alloc)
428 return;
429
430 printf("\n");
431 printf("Slab Perf Counter Alloc Free %%Al %%Fr\n");
432 printf("--------------------------------------------------\n");
433 printf("Fastpath %8lu %8lu %3lu %3lu\n",
434 s->alloc_fastpath, s->free_fastpath,
435 s->alloc_fastpath * 100 / total_alloc,
436 s->free_fastpath * 100 / total_free);
437 printf("Slowpath %8lu %8lu %3lu %3lu\n",
438 total_alloc - s->alloc_fastpath, s->free_slowpath,
439 (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
440 s->free_slowpath * 100 / total_free);
441 printf("Page Alloc %8lu %8lu %3lu %3lu\n",
442 s->alloc_slab, s->free_slab,
443 s->alloc_slab * 100 / total_alloc,
444 s->free_slab * 100 / total_free);
445 printf("Add partial %8lu %8lu %3lu %3lu\n",
446 s->deactivate_to_head + s->deactivate_to_tail,
447 s->free_add_partial,
448 (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
449 s->free_add_partial * 100 / total_free);
450 printf("Remove partial %8lu %8lu %3lu %3lu\n",
451 s->alloc_from_partial, s->free_remove_partial,
452 s->alloc_from_partial * 100 / total_alloc,
453 s->free_remove_partial * 100 / total_free);
454
455 printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
456 s->deactivate_remote_frees, s->free_frozen,
457 s->deactivate_remote_frees * 100 / total_alloc,
458 s->free_frozen * 100 / total_free);
459
460 printf("Total %8lu %8lu\n\n", total_alloc, total_free);
461
462 if (s->cpuslab_flush)
463 printf("Flushes %8lu\n", s->cpuslab_flush);
464
465 if (s->alloc_refill)
466 printf("Refill %8lu\n", s->alloc_refill);
467
468 total = s->deactivate_full + s->deactivate_empty +
469 s->deactivate_to_head + s->deactivate_to_tail;
470
471 if (total)
472 printf("Deactivate Full=%lu(%lu%%) Empty=%lu(%lu%%) "
473 "ToHead=%lu(%lu%%) ToTail=%lu(%lu%%)\n",
474 s->deactivate_full, (s->deactivate_full * 100) / total,
475 s->deactivate_empty, (s->deactivate_empty * 100) / total,
476 s->deactivate_to_head, (s->deactivate_to_head * 100) / total,
477 s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
478}
479
480static void report(struct slabinfo *s)
481{
482 if (strcmp(s->name, "*") == 0)
483 return;
484
485 printf("\nSlabcache: %-20s Aliases: %2d Order : %2d Objects: %lu\n",
486 s->name, s->aliases, s->order, s->objects);
487 if (s->hwcache_align)
488 printf("** Hardware cacheline aligned\n");
489 if (s->cache_dma)
490 printf("** Memory is allocated in a special DMA zone\n");
491 if (s->destroy_by_rcu)
492 printf("** Slabs are destroyed via RCU\n");
493 if (s->reclaim_account)
494 printf("** Reclaim accounting active\n");
495
496 printf("\nSizes (bytes) Slabs Debug Memory\n");
497 printf("------------------------------------------------------------------------\n");
498 printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n",
499 s->object_size, s->slabs, onoff(s->sanity_checks),
500 s->slabs * (page_size << s->order));
501 printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n",
502 s->slab_size, s->slabs - s->partial - s->cpu_slabs,
503 onoff(s->red_zone), s->objects * s->object_size);
504 printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n",
505 page_size << s->order, s->partial, onoff(s->poison),
506 s->slabs * (page_size << s->order) - s->objects * s->object_size);
507 printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n",
508 s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
509 (s->slab_size - s->object_size) * s->objects);
510 printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n",
511 s->align, s->objs_per_slab, onoff(s->trace),
512 ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
513 s->slabs);
514
515 ops(s);
516 show_tracking(s);
517 slab_numa(s, 1);
518 slab_stats(s);
519}
520
521static void slabcache(struct slabinfo *s)
522{
523 char size_str[20];
524 char dist_str[40];
525 char flags[20];
526 char *p = flags;
527
528 if (strcmp(s->name, "*") == 0)
529 return;
530
531 if (actual_slabs == 1) {
532 report(s);
533 return;
534 }
535
536 if (skip_zero && !show_empty && !s->slabs)
537 return;
538
539 if (show_empty && s->slabs)
540 return;
541
542 store_size(size_str, slab_size(s));
543 snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
544 s->partial, s->cpu_slabs);
545
546 if (!line++)
547 first_line();
548
549 if (s->aliases)
550 *p++ = '*';
551 if (s->cache_dma)
552 *p++ = 'd';
553 if (s->hwcache_align)
554 *p++ = 'A';
555 if (s->poison)
556 *p++ = 'P';
557 if (s->reclaim_account)
558 *p++ = 'a';
559 if (s->red_zone)
560 *p++ = 'Z';
561 if (s->sanity_checks)
562 *p++ = 'F';
563 if (s->store_user)
564 *p++ = 'U';
565 if (s->trace)
566 *p++ = 'T';
567
568 *p = 0;
569 if (show_activity) {
570 unsigned long total_alloc;
571 unsigned long total_free;
572
573 total_alloc = s->alloc_fastpath + s->alloc_slowpath;
574 total_free = s->free_fastpath + s->free_slowpath;
575
576 printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d\n",
577 s->name, s->objects,
578 total_alloc, total_free,
579 total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
580 total_free ? (s->free_fastpath * 100 / total_free) : 0,
581 s->order_fallback, s->order);
582 }
583 else
584 printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
585 s->name, s->objects, s->object_size, size_str, dist_str,
586 s->objs_per_slab, s->order,
587 s->slabs ? (s->partial * 100) / s->slabs : 100,
588 s->slabs ? (s->objects * s->object_size * 100) /
589 (s->slabs * (page_size << s->order)) : 100,
590 flags);
591}
592
593/*
594 * Analyze debug options. Return false if something is amiss.
595 */
596static int debug_opt_scan(char *opt)
597{
598 if (!opt || !opt[0] || strcmp(opt, "-") == 0)
599 return 1;
600
601 if (strcasecmp(opt, "a") == 0) {
602 sanity = 1;
603 poison = 1;
604 redzone = 1;
605 tracking = 1;
606 return 1;
607 }
608
609 for ( ; *opt; opt++)
610 switch (*opt) {
611 case 'F' : case 'f':
612 if (sanity)
613 return 0;
614 sanity = 1;
615 break;
616 case 'P' : case 'p':
617 if (poison)
618 return 0;
619 poison = 1;
620 break;
621
622 case 'Z' : case 'z':
623 if (redzone)
624 return 0;
625 redzone = 1;
626 break;
627
628 case 'U' : case 'u':
629 if (tracking)
630 return 0;
631 tracking = 1;
632 break;
633
634 case 'T' : case 't':
635 if (tracing)
636 return 0;
637 tracing = 1;
638 break;
639 default:
640 return 0;
641 }
642 return 1;
643}
644
645static int slab_empty(struct slabinfo *s)
646{
647 if (s->objects > 0)
648 return 0;
649
650 /*
651 * We may still have slabs even if there are no objects. Shrinking will
652 * remove them.
653 */
654 if (s->slabs != 0)
655 set_obj(s, "shrink", 1);
656
657 return 1;
658}
659
660static void slab_debug(struct slabinfo *s)
661{
662 if (strcmp(s->name, "*") == 0)
663 return;
664
665 if (sanity && !s->sanity_checks) {
666 set_obj(s, "sanity", 1);
667 }
668 if (!sanity && s->sanity_checks) {
669 if (slab_empty(s))
670 set_obj(s, "sanity", 0);
671 else
672 fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
673 }
674 if (redzone && !s->red_zone) {
675 if (slab_empty(s))
676 set_obj(s, "red_zone", 1);
677 else
678 fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
679 }
680 if (!redzone && s->red_zone) {
681 if (slab_empty(s))
682 set_obj(s, "red_zone", 0);
683 else
684 fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
685 }
686 if (poison && !s->poison) {
687 if (slab_empty(s))
688 set_obj(s, "poison", 1);
689 else
690 fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
691 }
692 if (!poison && s->poison) {
693 if (slab_empty(s))
694 set_obj(s, "poison", 0);
695 else
696 fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
697 }
698 if (tracking && !s->store_user) {
699 if (slab_empty(s))
700 set_obj(s, "store_user", 1);
701 else
702 fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
703 }
704 if (!tracking && s->store_user) {
705 if (slab_empty(s))
706 set_obj(s, "store_user", 0);
707 else
708 fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
709 }
710 if (tracing && !s->trace) {
711 if (slabs == 1)
712 set_obj(s, "trace", 1);
713 else
714 fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
715 }
716 if (!tracing && s->trace)
717 set_obj(s, "trace", 1);
718}
719
720static void totals(void)
721{
722 struct slabinfo *s;
723
724 int used_slabs = 0;
725 char b1[20], b2[20], b3[20], b4[20];
726 unsigned long long max = 1ULL << 63;
727
728 /* Object size */
729 unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
730
731 /* Number of partial slabs in a slabcache */
732 unsigned long long min_partial = max, max_partial = 0,
733 avg_partial, total_partial = 0;
734
735 /* Number of slabs in a slab cache */
736 unsigned long long min_slabs = max, max_slabs = 0,
737 avg_slabs, total_slabs = 0;
738
739 /* Size of the whole slab */
740 unsigned long long min_size = max, max_size = 0,
741 avg_size, total_size = 0;
742
743 /* Bytes used for object storage in a slab */
744 unsigned long long min_used = max, max_used = 0,
745 avg_used, total_used = 0;
746
747 /* Waste: Bytes used for alignment and padding */
748 unsigned long long min_waste = max, max_waste = 0,
749 avg_waste, total_waste = 0;
750 /* Number of objects in a slab */
751 unsigned long long min_objects = max, max_objects = 0,
752 avg_objects, total_objects = 0;
753 /* Waste per object */
754 unsigned long long min_objwaste = max,
755 max_objwaste = 0, avg_objwaste,
756 total_objwaste = 0;
757
758 /* Memory per object */
759 unsigned long long min_memobj = max,
760 max_memobj = 0, avg_memobj,
761 total_objsize = 0;
762
763 /* Percentage of partial slabs per slab */
764 unsigned long min_ppart = 100, max_ppart = 0,
765 avg_ppart, total_ppart = 0;
766
767 /* Number of objects in partial slabs */
768 unsigned long min_partobj = max, max_partobj = 0,
769 avg_partobj, total_partobj = 0;
770
771 /* Percentage of partial objects of all objects in a slab */
772 unsigned long min_ppartobj = 100, max_ppartobj = 0,
773 avg_ppartobj, total_ppartobj = 0;
774
775
776 for (s = slabinfo; s < slabinfo + slabs; s++) {
777 unsigned long long size;
778 unsigned long used;
779 unsigned long long wasted;
780 unsigned long long objwaste;
781 unsigned long percentage_partial_slabs;
782 unsigned long percentage_partial_objs;
783
784 if (!s->slabs || !s->objects)
785 continue;
786
787 used_slabs++;
788
789 size = slab_size(s);
790 used = s->objects * s->object_size;
791 wasted = size - used;
792 objwaste = s->slab_size - s->object_size;
793
794 percentage_partial_slabs = s->partial * 100 / s->slabs;
795 if (percentage_partial_slabs > 100)
796 percentage_partial_slabs = 100;
797
798 percentage_partial_objs = s->objects_partial * 100
799 / s->objects;
800
801 if (percentage_partial_objs > 100)
802 percentage_partial_objs = 100;
803
804 if (s->object_size < min_objsize)
805 min_objsize = s->object_size;
806 if (s->partial < min_partial)
807 min_partial = s->partial;
808 if (s->slabs < min_slabs)
809 min_slabs = s->slabs;
810 if (size < min_size)
811 min_size = size;
812 if (wasted < min_waste)
813 min_waste = wasted;
814 if (objwaste < min_objwaste)
815 min_objwaste = objwaste;
816 if (s->objects < min_objects)
817 min_objects = s->objects;
818 if (used < min_used)
819 min_used = used;
820 if (s->objects_partial < min_partobj)
821 min_partobj = s->objects_partial;
822 if (percentage_partial_slabs < min_ppart)
823 min_ppart = percentage_partial_slabs;
824 if (percentage_partial_objs < min_ppartobj)
825 min_ppartobj = percentage_partial_objs;
826 if (s->slab_size < min_memobj)
827 min_memobj = s->slab_size;
828
829 if (s->object_size > max_objsize)
830 max_objsize = s->object_size;
831 if (s->partial > max_partial)
832 max_partial = s->partial;
833 if (s->slabs > max_slabs)
834 max_slabs = s->slabs;
835 if (size > max_size)
836 max_size = size;
837 if (wasted > max_waste)
838 max_waste = wasted;
839 if (objwaste > max_objwaste)
840 max_objwaste = objwaste;
841 if (s->objects > max_objects)
842 max_objects = s->objects;
843 if (used > max_used)
844 max_used = used;
845 if (s->objects_partial > max_partobj)
846 max_partobj = s->objects_partial;
847 if (percentage_partial_slabs > max_ppart)
848 max_ppart = percentage_partial_slabs;
849 if (percentage_partial_objs > max_ppartobj)
850 max_ppartobj = percentage_partial_objs;
851 if (s->slab_size > max_memobj)
852 max_memobj = s->slab_size;
853
854 total_partial += s->partial;
855 total_slabs += s->slabs;
856 total_size += size;
857 total_waste += wasted;
858
859 total_objects += s->objects;
860 total_used += used;
861 total_partobj += s->objects_partial;
862 total_ppart += percentage_partial_slabs;
863 total_ppartobj += percentage_partial_objs;
864
865 total_objwaste += s->objects * objwaste;
866 total_objsize += s->objects * s->slab_size;
867 }
868
869 if (!total_objects) {
870 printf("No objects\n");
871 return;
872 }
873 if (!used_slabs) {
874 printf("No slabs\n");
875 return;
876 }
877
878 /* Per slab averages */
879 avg_partial = total_partial / used_slabs;
880 avg_slabs = total_slabs / used_slabs;
881 avg_size = total_size / used_slabs;
882 avg_waste = total_waste / used_slabs;
883
884 avg_objects = total_objects / used_slabs;
885 avg_used = total_used / used_slabs;
886 avg_partobj = total_partobj / used_slabs;
887 avg_ppart = total_ppart / used_slabs;
888 avg_ppartobj = total_ppartobj / used_slabs;
889
890 /* Per object object sizes */
891 avg_objsize = total_used / total_objects;
892 avg_objwaste = total_objwaste / total_objects;
893 avg_partobj = total_partobj * 100 / total_objects;
894 avg_memobj = total_objsize / total_objects;
895
896 printf("Slabcache Totals\n");
897 printf("----------------\n");
898 printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n",
899 slabs, aliases, alias_targets, used_slabs);
900
901 store_size(b1, total_size);store_size(b2, total_waste);
902 store_size(b3, total_waste * 100 / total_used);
903 printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1, b2, b3);
904
905 store_size(b1, total_objects);store_size(b2, total_partobj);
906 store_size(b3, total_partobj * 100 / total_objects);
907 printf("# Objects : %6s # PartObj: %6s ORatio:%6s%%\n", b1, b2, b3);
908
909 printf("\n");
910 printf("Per Cache Average Min Max Total\n");
911 printf("---------------------------------------------------------\n");
912
913 store_size(b1, avg_objects);store_size(b2, min_objects);
914 store_size(b3, max_objects);store_size(b4, total_objects);
915 printf("#Objects %10s %10s %10s %10s\n",
916 b1, b2, b3, b4);
917
918 store_size(b1, avg_slabs);store_size(b2, min_slabs);
919 store_size(b3, max_slabs);store_size(b4, total_slabs);
920 printf("#Slabs %10s %10s %10s %10s\n",
921 b1, b2, b3, b4);
922
923 store_size(b1, avg_partial);store_size(b2, min_partial);
924 store_size(b3, max_partial);store_size(b4, total_partial);
925 printf("#PartSlab %10s %10s %10s %10s\n",
926 b1, b2, b3, b4);
927 store_size(b1, avg_ppart);store_size(b2, min_ppart);
928 store_size(b3, max_ppart);
929 store_size(b4, total_partial * 100 / total_slabs);
930 printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n",
931 b1, b2, b3, b4);
932
933 store_size(b1, avg_partobj);store_size(b2, min_partobj);
934 store_size(b3, max_partobj);
935 store_size(b4, total_partobj);
936 printf("PartObjs %10s %10s %10s %10s\n",
937 b1, b2, b3, b4);
938
939 store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
940 store_size(b3, max_ppartobj);
941 store_size(b4, total_partobj * 100 / total_objects);
942 printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n",
943 b1, b2, b3, b4);
944
945 store_size(b1, avg_size);store_size(b2, min_size);
946 store_size(b3, max_size);store_size(b4, total_size);
947 printf("Memory %10s %10s %10s %10s\n",
948 b1, b2, b3, b4);
949
950 store_size(b1, avg_used);store_size(b2, min_used);
951 store_size(b3, max_used);store_size(b4, total_used);
952 printf("Used %10s %10s %10s %10s\n",
953 b1, b2, b3, b4);
954
955 store_size(b1, avg_waste);store_size(b2, min_waste);
956 store_size(b3, max_waste);store_size(b4, total_waste);
957 printf("Loss %10s %10s %10s %10s\n",
958 b1, b2, b3, b4);
959
960 printf("\n");
961 printf("Per Object Average Min Max\n");
962 printf("---------------------------------------------\n");
963
964 store_size(b1, avg_memobj);store_size(b2, min_memobj);
965 store_size(b3, max_memobj);
966 printf("Memory %10s %10s %10s\n",
967 b1, b2, b3);
968 store_size(b1, avg_objsize);store_size(b2, min_objsize);
969 store_size(b3, max_objsize);
970 printf("User %10s %10s %10s\n",
971 b1, b2, b3);
972
973 store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
974 store_size(b3, max_objwaste);
975 printf("Loss %10s %10s %10s\n",
976 b1, b2, b3);
977}
978
979static void sort_slabs(void)
980{
981 struct slabinfo *s1,*s2;
982
983 for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
984 for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
985 int result;
986
987 if (sort_size)
988 result = slab_size(s1) < slab_size(s2);
989 else if (sort_active)
990 result = slab_activity(s1) < slab_activity(s2);
991 else
992 result = strcasecmp(s1->name, s2->name);
993
994 if (show_inverted)
995 result = -result;
996
997 if (result > 0) {
998 struct slabinfo t;
999
1000 memcpy(&t, s1, sizeof(struct slabinfo));
1001 memcpy(s1, s2, sizeof(struct slabinfo));
1002 memcpy(s2, &t, sizeof(struct slabinfo));
1003 }
1004 }
1005 }
1006}
1007
1008static void sort_aliases(void)
1009{
1010 struct aliasinfo *a1,*a2;
1011
1012 for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
1013 for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
1014 char *n1, *n2;
1015
1016 n1 = a1->name;
1017 n2 = a2->name;
1018 if (show_alias && !show_inverted) {
1019 n1 = a1->ref;
1020 n2 = a2->ref;
1021 }
1022 if (strcasecmp(n1, n2) > 0) {
1023 struct aliasinfo t;
1024
1025 memcpy(&t, a1, sizeof(struct aliasinfo));
1026 memcpy(a1, a2, sizeof(struct aliasinfo));
1027 memcpy(a2, &t, sizeof(struct aliasinfo));
1028 }
1029 }
1030 }
1031}
1032
1033static void link_slabs(void)
1034{
1035 struct aliasinfo *a;
1036 struct slabinfo *s;
1037
1038 for (a = aliasinfo; a < aliasinfo + aliases; a++) {
1039
1040 for (s = slabinfo; s < slabinfo + slabs; s++)
1041 if (strcmp(a->ref, s->name) == 0) {
1042 a->slab = s;
1043 s->refs++;
1044 break;
1045 }
1046 if (s == slabinfo + slabs)
1047 fatal("Unresolved alias %s\n", a->ref);
1048 }
1049}
1050
1051static void alias(void)
1052{
1053 struct aliasinfo *a;
1054 char *active = NULL;
1055
1056 sort_aliases();
1057 link_slabs();
1058
1059 for(a = aliasinfo; a < aliasinfo + aliases; a++) {
1060
1061 if (!show_single_ref && a->slab->refs == 1)
1062 continue;
1063
1064 if (!show_inverted) {
1065 if (active) {
1066 if (strcmp(a->slab->name, active) == 0) {
1067 printf(" %s", a->name);
1068 continue;
1069 }
1070 }
1071 printf("\n%-12s <- %s", a->slab->name, a->name);
1072 active = a->slab->name;
1073 }
1074 else
1075 printf("%-20s -> %s\n", a->name, a->slab->name);
1076 }
1077 if (active)
1078 printf("\n");
1079}
1080
1081
1082static void rename_slabs(void)
1083{
1084 struct slabinfo *s;
1085 struct aliasinfo *a;
1086
1087 for (s = slabinfo; s < slabinfo + slabs; s++) {
1088 if (*s->name != ':')
1089 continue;
1090
1091 if (s->refs > 1 && !show_first_alias)
1092 continue;
1093
1094 a = find_one_alias(s);
1095
1096 if (a)
1097 s->name = a->name;
1098 else {
1099 s->name = "*";
1100 actual_slabs--;
1101 }
1102 }
1103}
1104
1105static int slab_mismatch(char *slab)
1106{
1107 return regexec(&pattern, slab, 0, NULL, 0);
1108}
1109
1110static void read_slab_dir(void)
1111{
1112 DIR *dir;
1113 struct dirent *de;
1114 struct slabinfo *slab = slabinfo;
1115 struct aliasinfo *alias = aliasinfo;
1116 char *p;
1117 char *t;
1118 int count;
1119
1120 if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
1121 fatal("SYSFS support for SLUB not active\n");
1122
1123 dir = opendir(".");
1124 while ((de = readdir(dir))) {
1125 if (de->d_name[0] == '.' ||
1126 (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
1127 continue;
1128 switch (de->d_type) {
1129 case DT_LNK:
1130 alias->name = strdup(de->d_name);
1131 count = readlink(de->d_name, buffer, sizeof(buffer));
1132
1133 if (count < 0)
1134 fatal("Cannot read symlink %s\n", de->d_name);
1135
1136 buffer[count] = 0;
1137 p = buffer + count;
1138 while (p > buffer && p[-1] != '/')
1139 p--;
1140 alias->ref = strdup(p);
1141 alias++;
1142 break;
1143 case DT_DIR:
1144 if (chdir(de->d_name))
1145 fatal("Unable to access slab %s\n", slab->name);
1146 slab->name = strdup(de->d_name);
1147 slab->alias = 0;
1148 slab->refs = 0;
1149 slab->aliases = get_obj("aliases");
1150 slab->align = get_obj("align");
1151 slab->cache_dma = get_obj("cache_dma");
1152 slab->cpu_slabs = get_obj("cpu_slabs");
1153 slab->destroy_by_rcu = get_obj("destroy_by_rcu");
1154 slab->hwcache_align = get_obj("hwcache_align");
1155 slab->object_size = get_obj("object_size");
1156 slab->objects = get_obj("objects");
1157 slab->objects_partial = get_obj("objects_partial");
1158 slab->objects_total = get_obj("objects_total");
1159 slab->objs_per_slab = get_obj("objs_per_slab");
1160 slab->order = get_obj("order");
1161 slab->partial = get_obj("partial");
1162 slab->partial = get_obj_and_str("partial", &t);
1163 decode_numa_list(slab->numa_partial, t);
1164 free(t);
1165 slab->poison = get_obj("poison");
1166 slab->reclaim_account = get_obj("reclaim_account");
1167 slab->red_zone = get_obj("red_zone");
1168 slab->sanity_checks = get_obj("sanity_checks");
1169 slab->slab_size = get_obj("slab_size");
1170 slab->slabs = get_obj_and_str("slabs", &t);
1171 decode_numa_list(slab->numa, t);
1172 free(t);
1173 slab->store_user = get_obj("store_user");
1174 slab->trace = get_obj("trace");
1175 slab->alloc_fastpath = get_obj("alloc_fastpath");
1176 slab->alloc_slowpath = get_obj("alloc_slowpath");
1177 slab->free_fastpath = get_obj("free_fastpath");
1178 slab->free_slowpath = get_obj("free_slowpath");
1179 slab->free_frozen= get_obj("free_frozen");
1180 slab->free_add_partial = get_obj("free_add_partial");
1181 slab->free_remove_partial = get_obj("free_remove_partial");
1182 slab->alloc_from_partial = get_obj("alloc_from_partial");
1183 slab->alloc_slab = get_obj("alloc_slab");
1184 slab->alloc_refill = get_obj("alloc_refill");
1185 slab->free_slab = get_obj("free_slab");
1186 slab->cpuslab_flush = get_obj("cpuslab_flush");
1187 slab->deactivate_full = get_obj("deactivate_full");
1188 slab->deactivate_empty = get_obj("deactivate_empty");
1189 slab->deactivate_to_head = get_obj("deactivate_to_head");
1190 slab->deactivate_to_tail = get_obj("deactivate_to_tail");
1191 slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
1192 slab->order_fallback = get_obj("order_fallback");
1193 chdir("..");
1194 if (slab->name[0] == ':')
1195 alias_targets++;
1196 slab++;
1197 break;
1198 default :
1199 fatal("Unknown file type %lx\n", de->d_type);
1200 }
1201 }
1202 closedir(dir);
1203 slabs = slab - slabinfo;
1204 actual_slabs = slabs;
1205 aliases = alias - aliasinfo;
1206 if (slabs > MAX_SLABS)
1207 fatal("Too many slabs\n");
1208 if (aliases > MAX_ALIASES)
1209 fatal("Too many aliases\n");
1210}
1211
1212static void output_slabs(void)
1213{
1214 struct slabinfo *slab;
1215
1216 for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
1217
1218 if (slab->alias)
1219 continue;
1220
1221
1222 if (show_numa)
1223 slab_numa(slab, 0);
1224 else if (show_track)
1225 show_tracking(slab);
1226 else if (validate)
1227 slab_validate(slab);
1228 else if (shrink)
1229 slab_shrink(slab);
1230 else if (set_debug)
1231 slab_debug(slab);
1232 else if (show_ops)
1233 ops(slab);
1234 else if (show_slab)
1235 slabcache(slab);
1236 else if (show_report)
1237 report(slab);
1238 }
1239}
1240
1241struct option opts[] = {
1242 { "aliases", 0, NULL, 'a' },
1243 { "activity", 0, NULL, 'A' },
1244 { "debug", 2, NULL, 'd' },
1245 { "display-activity", 0, NULL, 'D' },
1246 { "empty", 0, NULL, 'e' },
1247 { "first-alias", 0, NULL, 'f' },
1248 { "help", 0, NULL, 'h' },
1249 { "inverted", 0, NULL, 'i'},
1250 { "numa", 0, NULL, 'n' },
1251 { "ops", 0, NULL, 'o' },
1252 { "report", 0, NULL, 'r' },
1253 { "shrink", 0, NULL, 's' },
1254 { "slabs", 0, NULL, 'l' },
1255 { "track", 0, NULL, 't'},
1256 { "validate", 0, NULL, 'v' },
1257 { "zero", 0, NULL, 'z' },
1258 { "1ref", 0, NULL, '1'},
1259 { NULL, 0, NULL, 0 }
1260};
1261
1262int main(int argc, char *argv[])
1263{
1264 int c;
1265 int err;
1266 char *pattern_source;
1267
1268 page_size = getpagesize();
1269
1270 while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
1271 opts, NULL)) != -1)
1272 switch (c) {
1273 case '1':
1274 show_single_ref = 1;
1275 break;
1276 case 'a':
1277 show_alias = 1;
1278 break;
1279 case 'A':
1280 sort_active = 1;
1281 break;
1282 case 'd':
1283 set_debug = 1;
1284 if (!debug_opt_scan(optarg))
1285 fatal("Invalid debug option '%s'\n", optarg);
1286 break;
1287 case 'D':
1288 show_activity = 1;
1289 break;
1290 case 'e':
1291 show_empty = 1;
1292 break;
1293 case 'f':
1294 show_first_alias = 1;
1295 break;
1296 case 'h':
1297 usage();
1298 return 0;
1299 case 'i':
1300 show_inverted = 1;
1301 break;
1302 case 'n':
1303 show_numa = 1;
1304 break;
1305 case 'o':
1306 show_ops = 1;
1307 break;
1308 case 'r':
1309 show_report = 1;
1310 break;
1311 case 's':
1312 shrink = 1;
1313 break;
1314 case 'l':
1315 show_slab = 1;
1316 break;
1317 case 't':
1318 show_track = 1;
1319 break;
1320 case 'v':
1321 validate = 1;
1322 break;
1323 case 'z':
1324 skip_zero = 0;
1325 break;
1326 case 'T':
1327 show_totals = 1;
1328 break;
1329 case 'S':
1330 sort_size = 1;
1331 break;
1332
1333 default:
1334 fatal("%s: Invalid option '%c'\n", argv[0], optopt);
1335
1336 }
1337
1338 if (!show_slab && !show_alias && !show_track && !show_report
1339 && !validate && !shrink && !set_debug && !show_ops)
1340 show_slab = 1;
1341
1342 if (argc > optind)
1343 pattern_source = argv[optind];
1344 else
1345 pattern_source = ".*";
1346
1347 err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
1348 if (err)
1349 fatal("%s: Invalid pattern '%s' code %d\n",
1350 argv[0], pattern_source, err);
1351 read_slab_dir();
1352 if (show_alias)
1353 alias();
1354 else
1355 if (show_totals)
1356 totals();
1357 else {
1358 link_slabs();
1359 rename_slabs();
1360 sort_slabs();
1361 output_slabs();
1362 }
1363 return 0;
1364}
diff --git a/tools/testing/ktest/compare-ktest-sample.pl b/tools/testing/ktest/compare-ktest-sample.pl
new file mode 100755
index 000000000000..9a571e71683c
--- /dev/null
+++ b/tools/testing/ktest/compare-ktest-sample.pl
@@ -0,0 +1,30 @@
1#!/usr/bin/perl
2
3open (IN,"ktest.pl");
4while (<IN>) {
5 if (/\$opt\{"?([A-Z].*?)(\[.*\])?"?\}/ ||
6 /set_test_option\("(.*?)"/) {
7 $opt{$1} = 1;
8 }
9}
10close IN;
11
12open (IN, "sample.conf");
13while (<IN>) {
14 if (/^\s*#?\s*(\S+)\s*=/) {
15 $samp{$1} = 1;
16 }
17}
18close IN;
19
20foreach $opt (keys %opt) {
21 if (!defined($samp{$opt})) {
22 print "opt = $opt\n";
23 }
24}
25
26foreach $samp (keys %samp) {
27 if (!defined($opt{$samp})) {
28 print "samp = $samp\n";
29 }
30}
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
new file mode 100755
index 000000000000..e1c62eeb88f5
--- /dev/null
+++ b/tools/testing/ktest/ktest.pl
@@ -0,0 +1,2023 @@
1#!/usr/bin/perl -w
2#
3# Copywrite 2010 - Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
4# Licensed under the terms of the GNU GPL License version 2
5#
6
7use strict;
8use IPC::Open2;
9use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
10use File::Path qw(mkpath);
11use File::Copy qw(cp);
12use FileHandle;
13
14my $VERSION = "0.2";
15
16$| = 1;
17
18my %opt;
19my %repeat_tests;
20my %repeats;
21my %default;
22
23#default opts
24$default{"NUM_TESTS"} = 1;
25$default{"REBOOT_TYPE"} = "grub";
26$default{"TEST_TYPE"} = "test";
27$default{"BUILD_TYPE"} = "randconfig";
28$default{"MAKE_CMD"} = "make";
29$default{"TIMEOUT"} = 120;
30$default{"TMP_DIR"} = "/tmp/ktest";
31$default{"SLEEP_TIME"} = 60; # sleep time between tests
32$default{"BUILD_NOCLEAN"} = 0;
33$default{"REBOOT_ON_ERROR"} = 0;
34$default{"POWEROFF_ON_ERROR"} = 0;
35$default{"REBOOT_ON_SUCCESS"} = 1;
36$default{"POWEROFF_ON_SUCCESS"} = 0;
37$default{"BUILD_OPTIONS"} = "";
38$default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects
39$default{"CLEAR_LOG"} = 0;
40$default{"SUCCESS_LINE"} = "login:";
41$default{"BOOTED_TIMEOUT"} = 1;
42$default{"DIE_ON_FAILURE"} = 1;
43$default{"SSH_EXEC"} = "ssh \$SSH_USER\@\$MACHINE \$SSH_COMMAND";
44$default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE";
45$default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot";
46$default{"STOP_AFTER_SUCCESS"} = 10;
47$default{"STOP_AFTER_FAILURE"} = 60;
48$default{"LOCALVERSION"} = "-test";
49
50my $ktest_config;
51my $version;
52my $machine;
53my $ssh_user;
54my $tmpdir;
55my $builddir;
56my $outputdir;
57my $output_config;
58my $test_type;
59my $build_type;
60my $build_options;
61my $reboot_type;
62my $reboot_script;
63my $power_cycle;
64my $reboot;
65my $reboot_on_error;
66my $poweroff_on_error;
67my $die_on_failure;
68my $powercycle_after_reboot;
69my $poweroff_after_halt;
70my $ssh_exec;
71my $scp_to_target;
72my $power_off;
73my $grub_menu;
74my $grub_number;
75my $target;
76my $make;
77my $post_install;
78my $noclean;
79my $minconfig;
80my $addconfig;
81my $in_bisect = 0;
82my $bisect_bad = "";
83my $reverse_bisect;
84my $in_patchcheck = 0;
85my $run_test;
86my $redirect;
87my $buildlog;
88my $dmesg;
89my $monitor_fp;
90my $monitor_pid;
91my $monitor_cnt = 0;
92my $sleep_time;
93my $bisect_sleep_time;
94my $store_failures;
95my $timeout;
96my $booted_timeout;
97my $console;
98my $success_line;
99my $stop_after_success;
100my $stop_after_failure;
101my $build_target;
102my $target_image;
103my $localversion;
104my $iteration = 0;
105my $successes = 0;
106
107my %entered_configs;
108my %config_help;
109
110$config_help{"MACHINE"} = << "EOF"
111 The machine hostname that you will test.
112EOF
113 ;
114$config_help{"SSH_USER"} = << "EOF"
115 The box is expected to have ssh on normal bootup, provide the user
116 (most likely root, since you need privileged operations)
117EOF
118 ;
119$config_help{"BUILD_DIR"} = << "EOF"
120 The directory that contains the Linux source code (full path).
121EOF
122 ;
123$config_help{"OUTPUT_DIR"} = << "EOF"
124 The directory that the objects will be built (full path).
125 (can not be same as BUILD_DIR)
126EOF
127 ;
128$config_help{"BUILD_TARGET"} = << "EOF"
129 The location of the compiled file to copy to the target.
130 (relative to OUTPUT_DIR)
131EOF
132 ;
133$config_help{"TARGET_IMAGE"} = << "EOF"
134 The place to put your image on the test machine.
135EOF
136 ;
137$config_help{"POWER_CYCLE"} = << "EOF"
138 A script or command to reboot the box.
139
140 Here is a digital loggers power switch example
141 POWER_CYCLE = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin\@power/outlet?5=CCL'
142
143 Here is an example to reboot a virtual box on the current host
144 with the name "Guest".
145 POWER_CYCLE = virsh destroy Guest; sleep 5; virsh start Guest
146EOF
147 ;
148$config_help{"CONSOLE"} = << "EOF"
149 The script or command that reads the console
150
151 If you use ttywatch server, something like the following would work.
152CONSOLE = nc -d localhost 3001
153
154 For a virtual machine with guest name "Guest".
155CONSOLE = virsh console Guest
156EOF
157 ;
158$config_help{"LOCALVERSION"} = << "EOF"
159 Required version ending to differentiate the test
160 from other linux builds on the system.
161EOF
162 ;
163$config_help{"REBOOT_TYPE"} = << "EOF"
164 Way to reboot the box to the test kernel.
165 Only valid options so far are "grub" and "script".
166
167 If you specify grub, it will assume grub version 1
168 and will search in /boot/grub/menu.lst for the title \$GRUB_MENU
169 and select that target to reboot to the kernel. If this is not
170 your setup, then specify "script" and have a command or script
171 specified in REBOOT_SCRIPT to boot to the target.
172
173 The entry in /boot/grub/menu.lst must be entered in manually.
174 The test will not modify that file.
175EOF
176 ;
177$config_help{"GRUB_MENU"} = << "EOF"
178 The grub title name for the test kernel to boot
179 (Only mandatory if REBOOT_TYPE = grub)
180
181 Note, ktest.pl will not update the grub menu.lst, you need to
182 manually add an option for the test. ktest.pl will search
183 the grub menu.lst for this option to find what kernel to
184 reboot into.
185
186 For example, if in the /boot/grub/menu.lst the test kernel title has:
187 title Test Kernel
188 kernel vmlinuz-test
189 GRUB_MENU = Test Kernel
190EOF
191 ;
192$config_help{"REBOOT_SCRIPT"} = << "EOF"
193 A script to reboot the target into the test kernel
194 (Only mandatory if REBOOT_TYPE = script)
195EOF
196 ;
197
198
199sub get_ktest_config {
200 my ($config) = @_;
201
202 return if (defined($opt{$config}));
203
204 if (defined($config_help{$config})) {
205 print "\n";
206 print $config_help{$config};
207 }
208
209 for (;;) {
210 print "$config = ";
211 if (defined($default{$config})) {
212 print "\[$default{$config}\] ";
213 }
214 $entered_configs{$config} = <STDIN>;
215 $entered_configs{$config} =~ s/^\s*(.*\S)\s*$/$1/;
216 if ($entered_configs{$config} =~ /^\s*$/) {
217 if ($default{$config}) {
218 $entered_configs{$config} = $default{$config};
219 } else {
220 print "Your answer can not be blank\n";
221 next;
222 }
223 }
224 last;
225 }
226}
227
228sub get_ktest_configs {
229 get_ktest_config("MACHINE");
230 get_ktest_config("SSH_USER");
231 get_ktest_config("BUILD_DIR");
232 get_ktest_config("OUTPUT_DIR");
233 get_ktest_config("BUILD_TARGET");
234 get_ktest_config("TARGET_IMAGE");
235 get_ktest_config("POWER_CYCLE");
236 get_ktest_config("CONSOLE");
237 get_ktest_config("LOCALVERSION");
238
239 my $rtype = $opt{"REBOOT_TYPE"};
240
241 if (!defined($rtype)) {
242 if (!defined($opt{"GRUB_MENU"})) {
243 get_ktest_config("REBOOT_TYPE");
244 $rtype = $entered_configs{"REBOOT_TYPE"};
245 } else {
246 $rtype = "grub";
247 }
248 }
249
250 if ($rtype eq "grub") {
251 get_ktest_config("GRUB_MENU");
252 } else {
253 get_ktest_config("REBOOT_SCRIPT");
254 }
255}
256
257sub set_value {
258 my ($lvalue, $rvalue) = @_;
259
260 if (defined($opt{$lvalue})) {
261 die "Error: Option $lvalue defined more than once!\n";
262 }
263 if ($rvalue =~ /^\s*$/) {
264 delete $opt{$lvalue};
265 } else {
266 $opt{$lvalue} = $rvalue;
267 }
268}
269
270sub read_config {
271 my ($config) = @_;
272
273 open(IN, $config) || die "can't read file $config";
274
275 my $name = $config;
276 $name =~ s,.*/(.*),$1,;
277
278 my $test_num = 0;
279 my $default = 1;
280 my $repeat = 1;
281 my $num_tests_set = 0;
282 my $skip = 0;
283 my $rest;
284
285 while (<IN>) {
286
287 # ignore blank lines and comments
288 next if (/^\s*$/ || /\s*\#/);
289
290 if (/^\s*TEST_START(.*)/) {
291
292 $rest = $1;
293
294 if ($num_tests_set) {
295 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
296 }
297
298 my $old_test_num = $test_num;
299 my $old_repeat = $repeat;
300
301 $test_num += $repeat;
302 $default = 0;
303 $repeat = 1;
304
305 if ($rest =~ /\s+SKIP(.*)/) {
306 $rest = $1;
307 $skip = 1;
308 } else {
309 $skip = 0;
310 }
311
312 if ($rest =~ /\s+ITERATE\s+(\d+)(.*)$/) {
313 $repeat = $1;
314 $rest = $2;
315 $repeat_tests{"$test_num"} = $repeat;
316 }
317
318 if ($rest =~ /\s+SKIP(.*)/) {
319 $rest = $1;
320 $skip = 1;
321 }
322
323 if ($rest !~ /^\s*$/) {
324 die "$name: $.: Gargbage found after TEST_START\n$_";
325 }
326
327 if ($skip) {
328 $test_num = $old_test_num;
329 $repeat = $old_repeat;
330 }
331
332 } elsif (/^\s*DEFAULTS(.*)$/) {
333 $default = 1;
334
335 $rest = $1;
336
337 if ($rest =~ /\s+SKIP(.*)/) {
338 $rest = $1;
339 $skip = 1;
340 } else {
341 $skip = 0;
342 }
343
344 if ($rest !~ /^\s*$/) {
345 die "$name: $.: Gargbage found after DEFAULTS\n$_";
346 }
347
348 } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) {
349
350 next if ($skip);
351
352 my $lvalue = $1;
353 my $rvalue = $2;
354
355 if (!$default &&
356 ($lvalue eq "NUM_TESTS" ||
357 $lvalue eq "LOG_FILE" ||
358 $lvalue eq "CLEAR_LOG")) {
359 die "$name: $.: $lvalue must be set in DEFAULTS section\n";
360 }
361
362 if ($lvalue eq "NUM_TESTS") {
363 if ($test_num) {
364 die "$name: $.: Can not specify both NUM_TESTS and TEST_START\n";
365 }
366 if (!$default) {
367 die "$name: $.: NUM_TESTS must be set in default section\n";
368 }
369 $num_tests_set = 1;
370 }
371
372 if ($default || $lvalue =~ /\[\d+\]$/) {
373 set_value($lvalue, $rvalue);
374 } else {
375 my $val = "$lvalue\[$test_num\]";
376 set_value($val, $rvalue);
377
378 if ($repeat > 1) {
379 $repeats{$val} = $repeat;
380 }
381 }
382 } else {
383 die "$name: $.: Garbage found in config\n$_";
384 }
385 }
386
387 close(IN);
388
389 if ($test_num) {
390 $test_num += $repeat - 1;
391 $opt{"NUM_TESTS"} = $test_num;
392 }
393
394 # make sure we have all mandatory configs
395 get_ktest_configs;
396
397 # set any defaults
398
399 foreach my $default (keys %default) {
400 if (!defined($opt{$default})) {
401 $opt{$default} = $default{$default};
402 }
403 }
404}
405
406sub _logit {
407 if (defined($opt{"LOG_FILE"})) {
408 open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}";
409 print OUT @_;
410 close(OUT);
411 }
412}
413
414sub logit {
415 if (defined($opt{"LOG_FILE"})) {
416 _logit @_;
417 } else {
418 print @_;
419 }
420}
421
422sub doprint {
423 print @_;
424 _logit @_;
425}
426
427sub run_command;
428
429sub reboot {
430 # try to reboot normally
431 if (run_command $reboot) {
432 if (defined($powercycle_after_reboot)) {
433 sleep $powercycle_after_reboot;
434 run_command "$power_cycle";
435 }
436 } else {
437 # nope? power cycle it.
438 run_command "$power_cycle";
439 }
440}
441
442sub do_not_reboot {
443 my $i = $iteration;
444
445 return $test_type eq "build" ||
446 ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") ||
447 ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build");
448}
449
450sub dodie {
451 doprint "CRITICAL FAILURE... ", @_, "\n";
452
453 my $i = $iteration;
454
455 if ($reboot_on_error && !do_not_reboot) {
456
457 doprint "REBOOTING\n";
458 reboot;
459
460 } elsif ($poweroff_on_error && defined($power_off)) {
461 doprint "POWERING OFF\n";
462 `$power_off`;
463 }
464
465 die @_, "\n";
466}
467
468sub open_console {
469 my ($fp) = @_;
470
471 my $flags;
472
473 my $pid = open($fp, "$console|") or
474 dodie "Can't open console $console";
475
476 $flags = fcntl($fp, F_GETFL, 0) or
477 dodie "Can't get flags for the socket: $!";
478 $flags = fcntl($fp, F_SETFL, $flags | O_NONBLOCK) or
479 dodie "Can't set flags for the socket: $!";
480
481 return $pid;
482}
483
484sub close_console {
485 my ($fp, $pid) = @_;
486
487 doprint "kill child process $pid\n";
488 kill 2, $pid;
489
490 print "closing!\n";
491 close($fp);
492}
493
494sub start_monitor {
495 if ($monitor_cnt++) {
496 return;
497 }
498 $monitor_fp = \*MONFD;
499 $monitor_pid = open_console $monitor_fp;
500
501 return;
502
503 open(MONFD, "Stop perl from warning about single use of MONFD");
504}
505
506sub end_monitor {
507 if (--$monitor_cnt) {
508 return;
509 }
510 close_console($monitor_fp, $monitor_pid);
511}
512
513sub wait_for_monitor {
514 my ($time) = @_;
515 my $line;
516
517 doprint "** Wait for monitor to settle down **\n";
518
519 # read the monitor and wait for the system to calm down
520 do {
521 $line = wait_for_input($monitor_fp, $time);
522 print "$line" if (defined($line));
523 } while (defined($line));
524 print "** Monitor flushed **\n";
525}
526
527sub fail {
528
529 if ($die_on_failure) {
530 dodie @_;
531 }
532
533 doprint "FAILED\n";
534
535 my $i = $iteration;
536
537 # no need to reboot for just building.
538 if (!do_not_reboot) {
539 doprint "REBOOTING\n";
540 reboot;
541 start_monitor;
542 wait_for_monitor $sleep_time;
543 end_monitor;
544 }
545
546 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
547 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
548 doprint "KTEST RESULT: TEST $i Failed: ", @_, "\n";
549 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
550 doprint "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
551
552 return 1 if (!defined($store_failures));
553
554 my @t = localtime;
555 my $date = sprintf "%04d%02d%02d%02d%02d%02d",
556 1900+$t[5],$t[4],$t[3],$t[2],$t[1],$t[0];
557
558 my $type = $build_type;
559 if ($type =~ /useconfig/) {
560 $type = "useconfig";
561 }
562
563 my $dir = "$machine-$test_type-$type-fail-$date";
564 my $faildir = "$store_failures/$dir";
565
566 if (!-d $faildir) {
567 mkpath($faildir) or
568 die "can't create $faildir";
569 }
570 if (-f "$output_config") {
571 cp "$output_config", "$faildir/config" or
572 die "failed to copy .config";
573 }
574 if (-f $buildlog) {
575 cp $buildlog, "$faildir/buildlog" or
576 die "failed to move $buildlog";
577 }
578 if (-f $dmesg) {
579 cp $dmesg, "$faildir/dmesg" or
580 die "failed to move $dmesg";
581 }
582
583 doprint "*** Saved info to $faildir ***\n";
584
585 return 1;
586}
587
588sub run_command {
589 my ($command) = @_;
590 my $dolog = 0;
591 my $dord = 0;
592 my $pid;
593
594 $command =~ s/\$SSH_USER/$ssh_user/g;
595 $command =~ s/\$MACHINE/$machine/g;
596
597 doprint("$command ... ");
598
599 $pid = open(CMD, "$command 2>&1 |") or
600 (fail "unable to exec $command" and return 0);
601
602 if (defined($opt{"LOG_FILE"})) {
603 open(LOG, ">>$opt{LOG_FILE}") or
604 dodie "failed to write to log";
605 $dolog = 1;
606 }
607
608 if (defined($redirect)) {
609 open (RD, ">$redirect") or
610 dodie "failed to write to redirect $redirect";
611 $dord = 1;
612 }
613
614 while (<CMD>) {
615 print LOG if ($dolog);
616 print RD if ($dord);
617 }
618
619 waitpid($pid, 0);
620 my $failed = $?;
621
622 close(CMD);
623 close(LOG) if ($dolog);
624 close(RD) if ($dord);
625
626 if ($failed) {
627 doprint "FAILED!\n";
628 } else {
629 doprint "SUCCESS\n";
630 }
631
632 return !$failed;
633}
634
635sub run_ssh {
636 my ($cmd) = @_;
637 my $cp_exec = $ssh_exec;
638
639 $cp_exec =~ s/\$SSH_COMMAND/$cmd/g;
640 return run_command "$cp_exec";
641}
642
643sub run_scp {
644 my ($src, $dst) = @_;
645 my $cp_scp = $scp_to_target;
646
647 $cp_scp =~ s/\$SRC_FILE/$src/g;
648 $cp_scp =~ s/\$DST_FILE/$dst/g;
649
650 return run_command "$cp_scp";
651}
652
653sub get_grub_index {
654
655 if ($reboot_type ne "grub") {
656 return;
657 }
658 return if (defined($grub_number));
659
660 doprint "Find grub menu ... ";
661 $grub_number = -1;
662
663 my $ssh_grub = $ssh_exec;
664 $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g;
665
666 open(IN, "$ssh_grub |")
667 or die "unable to get menu.lst";
668
669 while (<IN>) {
670 if (/^\s*title\s+$grub_menu\s*$/) {
671 $grub_number++;
672 last;
673 } elsif (/^\s*title\s/) {
674 $grub_number++;
675 }
676 }
677 close(IN);
678
679 die "Could not find '$grub_menu' in /boot/grub/menu on $machine"
680 if ($grub_number < 0);
681 doprint "$grub_number\n";
682}
683
684sub wait_for_input
685{
686 my ($fp, $time) = @_;
687 my $rin;
688 my $ready;
689 my $line;
690 my $ch;
691
692 if (!defined($time)) {
693 $time = $timeout;
694 }
695
696 $rin = '';
697 vec($rin, fileno($fp), 1) = 1;
698 $ready = select($rin, undef, undef, $time);
699
700 $line = "";
701
702 # try to read one char at a time
703 while (sysread $fp, $ch, 1) {
704 $line .= $ch;
705 last if ($ch eq "\n");
706 }
707
708 if (!length($line)) {
709 return undef;
710 }
711
712 return $line;
713}
714
715sub reboot_to {
716 if ($reboot_type eq "grub") {
717 run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
718 return;
719 }
720
721 run_command "$reboot_script";
722}
723
724sub get_sha1 {
725 my ($commit) = @_;
726
727 doprint "git rev-list --max-count=1 $commit ... ";
728 my $sha1 = `git rev-list --max-count=1 $commit`;
729 my $ret = $?;
730
731 logit $sha1;
732
733 if ($ret) {
734 doprint "FAILED\n";
735 dodie "Failed to get git $commit";
736 }
737
738 print "SUCCESS\n";
739
740 chomp $sha1;
741
742 return $sha1;
743}
744
745sub monitor {
746 my $booted = 0;
747 my $bug = 0;
748 my $skip_call_trace = 0;
749 my $loops;
750
751 wait_for_monitor 5;
752
753 my $line;
754 my $full_line = "";
755
756 open(DMESG, "> $dmesg") or
757 die "unable to write to $dmesg";
758
759 reboot_to;
760
761 my $success_start;
762 my $failure_start;
763
764 for (;;) {
765
766 if ($booted) {
767 $line = wait_for_input($monitor_fp, $booted_timeout);
768 } else {
769 $line = wait_for_input($monitor_fp);
770 }
771
772 last if (!defined($line));
773
774 doprint $line;
775 print DMESG $line;
776
777 # we are not guaranteed to get a full line
778 $full_line .= $line;
779
780 if ($full_line =~ /$success_line/) {
781 $booted = 1;
782 $success_start = time;
783 }
784
785 if ($booted && defined($stop_after_success) &&
786 $stop_after_success >= 0) {
787 my $now = time;
788 if ($now - $success_start >= $stop_after_success) {
789 doprint "Test forced to stop after $stop_after_success seconds after success\n";
790 last;
791 }
792 }
793
794 if ($full_line =~ /\[ backtrace testing \]/) {
795 $skip_call_trace = 1;
796 }
797
798 if ($full_line =~ /call trace:/i) {
799 if (!$skip_call_trace) {
800 $bug = 1;
801 $failure_start = time;
802 }
803 }
804
805 if ($bug && defined($stop_after_failure) &&
806 $stop_after_failure >= 0) {
807 my $now = time;
808 if ($now - $failure_start >= $stop_after_failure) {
809 doprint "Test forced to stop after $stop_after_failure seconds after failure\n";
810 last;
811 }
812 }
813
814 if ($full_line =~ /\[ end of backtrace testing \]/) {
815 $skip_call_trace = 0;
816 }
817
818 if ($full_line =~ /Kernel panic -/) {
819 $bug = 1;
820 }
821
822 if ($line =~ /\n/) {
823 $full_line = "";
824 }
825 }
826
827 close(DMESG);
828
829 if ($bug) {
830 return 0 if ($in_bisect);
831 fail "failed - got a bug report" and return 0;
832 }
833
834 if (!$booted) {
835 return 0 if ($in_bisect);
836 fail "failed - never got a boot prompt." and return 0;
837 }
838
839 return 1;
840}
841
842sub install {
843
844 run_scp "$outputdir/$build_target", "$target_image" or
845 dodie "failed to copy image";
846
847 my $install_mods = 0;
848
849 # should we process modules?
850 $install_mods = 0;
851 open(IN, "$output_config") or dodie("Can't read config file");
852 while (<IN>) {
853 if (/CONFIG_MODULES(=y)?/) {
854 $install_mods = 1 if (defined($1));
855 last;
856 }
857 }
858 close(IN);
859
860 if (!$install_mods) {
861 doprint "No modules needed\n";
862 return;
863 }
864
865 run_command "$make INSTALL_MOD_PATH=$tmpdir modules_install" or
866 dodie "Failed to install modules";
867
868 my $modlib = "/lib/modules/$version";
869 my $modtar = "ktest-mods.tar.bz2";
870
871 run_ssh "rm -rf $modlib" or
872 dodie "failed to remove old mods: $modlib";
873
874 # would be nice if scp -r did not follow symbolic links
875 run_command "cd $tmpdir && tar -cjf $modtar lib/modules/$version" or
876 dodie "making tarball";
877
878 run_scp "$tmpdir/$modtar", "/tmp" or
879 dodie "failed to copy modules";
880
881 unlink "$tmpdir/$modtar";
882
883 run_ssh "'(cd / && tar xf /tmp/$modtar)'" or
884 dodie "failed to tar modules";
885
886 run_ssh "rm -f /tmp/$modtar";
887
888 return if (!defined($post_install));
889
890 my $cp_post_install = $post_install;
891 $cp_post_install = s/\$KERNEL_VERSION/$version/g;
892 run_command "$cp_post_install" or
893 dodie "Failed to run post install";
894}
895
896sub check_buildlog {
897 my ($patch) = @_;
898
899 my @files = `git show $patch | diffstat -l`;
900
901 open(IN, "git show $patch |") or
902 dodie "failed to show $patch";
903 while (<IN>) {
904 if (m,^--- a/(.*),) {
905 chomp $1;
906 $files[$#files] = $1;
907 }
908 }
909 close(IN);
910
911 open(IN, $buildlog) or dodie "Can't open $buildlog";
912 while (<IN>) {
913 if (/^\s*(.*?):.*(warning|error)/) {
914 my $err = $1;
915 foreach my $file (@files) {
916 my $fullpath = "$builddir/$file";
917 if ($file eq $err || $fullpath eq $err) {
918 fail "$file built with warnings" and return 0;
919 }
920 }
921 }
922 }
923 close(IN);
924
925 return 1;
926}
927
928sub build {
929 my ($type) = @_;
930 my $defconfig = "";
931
932 unlink $buildlog;
933
934 if ($type =~ /^useconfig:(.*)/) {
935 run_command "cp $1 $output_config" or
936 dodie "could not copy $1 to .config";
937
938 $type = "oldconfig";
939 }
940
941 # old config can ask questions
942 if ($type eq "oldconfig") {
943 $type = "oldnoconfig";
944
945 # allow for empty configs
946 run_command "touch $output_config";
947
948 run_command "mv $output_config $outputdir/config_temp" or
949 dodie "moving .config";
950
951 if (!$noclean && !run_command "$make mrproper") {
952 dodie "make mrproper";
953 }
954
955 run_command "mv $outputdir/config_temp $output_config" or
956 dodie "moving config_temp";
957
958 } elsif (!$noclean) {
959 unlink "$output_config";
960 run_command "$make mrproper" or
961 dodie "make mrproper";
962 }
963
964 # add something to distinguish this build
965 open(OUT, "> $outputdir/localversion") or dodie("Can't make localversion file");
966 print OUT "$localversion\n";
967 close(OUT);
968
969 if (defined($minconfig)) {
970 $defconfig = "KCONFIG_ALLCONFIG=$minconfig";
971 }
972
973 run_command "$defconfig $make $type" or
974 dodie "failed make config";
975
976 $redirect = "$buildlog";
977 if (!run_command "$make $build_options") {
978 undef $redirect;
979 # bisect may need this to pass
980 return 0 if ($in_bisect);
981 fail "failed build" and return 0;
982 }
983 undef $redirect;
984
985 return 1;
986}
987
988sub halt {
989 if (!run_ssh "halt" or defined($power_off)) {
990 if (defined($poweroff_after_halt)) {
991 sleep $poweroff_after_halt;
992 run_command "$power_off";
993 }
994 } else {
995 # nope? the zap it!
996 run_command "$power_off";
997 }
998}
999
1000sub success {
1001 my ($i) = @_;
1002
1003 $successes++;
1004
1005 doprint "\n\n*******************************************\n";
1006 doprint "*******************************************\n";
1007 doprint "KTEST RESULT: TEST $i SUCCESS!!!! **\n";
1008 doprint "*******************************************\n";
1009 doprint "*******************************************\n";
1010
1011 if ($i != $opt{"NUM_TESTS"} && !do_not_reboot) {
1012 doprint "Reboot and wait $sleep_time seconds\n";
1013 reboot;
1014 start_monitor;
1015 wait_for_monitor $sleep_time;
1016 end_monitor;
1017 }
1018}
1019
1020sub get_version {
1021 # get the release name
1022 doprint "$make kernelrelease ... ";
1023 $version = `$make kernelrelease | tail -1`;
1024 chomp($version);
1025 doprint "$version\n";
1026}
1027
1028sub child_run_test {
1029 my $failed = 0;
1030
1031 # child should have no power
1032 $reboot_on_error = 0;
1033 $poweroff_on_error = 0;
1034 $die_on_failure = 1;
1035
1036 run_command $run_test or $failed = 1;
1037 exit $failed;
1038}
1039
1040my $child_done;
1041
1042sub child_finished {
1043 $child_done = 1;
1044}
1045
1046sub do_run_test {
1047 my $child_pid;
1048 my $child_exit;
1049 my $line;
1050 my $full_line;
1051 my $bug = 0;
1052
1053 wait_for_monitor 1;
1054
1055 doprint "run test $run_test\n";
1056
1057 $child_done = 0;
1058
1059 $SIG{CHLD} = qw(child_finished);
1060
1061 $child_pid = fork;
1062
1063 child_run_test if (!$child_pid);
1064
1065 $full_line = "";
1066
1067 do {
1068 $line = wait_for_input($monitor_fp, 1);
1069 if (defined($line)) {
1070
1071 # we are not guaranteed to get a full line
1072 $full_line .= $line;
1073
1074 if ($full_line =~ /call trace:/i) {
1075 $bug = 1;
1076 }
1077
1078 if ($full_line =~ /Kernel panic -/) {
1079 $bug = 1;
1080 }
1081
1082 if ($line =~ /\n/) {
1083 $full_line = "";
1084 }
1085 }
1086 } while (!$child_done && !$bug);
1087
1088 if ($bug) {
1089 doprint "Detected kernel crash!\n";
1090 # kill the child with extreme prejudice
1091 kill 9, $child_pid;
1092 }
1093
1094 waitpid $child_pid, 0;
1095 $child_exit = $?;
1096
1097 if ($bug || $child_exit) {
1098 return 0 if $in_bisect;
1099 fail "test failed" and return 0;
1100 }
1101 return 1;
1102}
1103
1104sub run_git_bisect {
1105 my ($command) = @_;
1106
1107 doprint "$command ... ";
1108
1109 my $output = `$command 2>&1`;
1110 my $ret = $?;
1111
1112 logit $output;
1113
1114 if ($ret) {
1115 doprint "FAILED\n";
1116 dodie "Failed to git bisect";
1117 }
1118
1119 doprint "SUCCESS\n";
1120 if ($output =~ m/^(Bisecting: .*\(roughly \d+ steps?\))\s+\[([[:xdigit:]]+)\]/) {
1121 doprint "$1 [$2]\n";
1122 } elsif ($output =~ m/^([[:xdigit:]]+) is the first bad commit/) {
1123 $bisect_bad = $1;
1124 doprint "Found bad commit... $1\n";
1125 return 0;
1126 } else {
1127 # we already logged it, just print it now.
1128 print $output;
1129 }
1130
1131 return 1;
1132}
1133
1134# returns 1 on success, 0 on failure
1135sub run_bisect_test {
1136 my ($type, $buildtype) = @_;
1137
1138 my $failed = 0;
1139 my $result;
1140 my $output;
1141 my $ret;
1142
1143 $in_bisect = 1;
1144
1145 build $buildtype or $failed = 1;
1146
1147 if ($type ne "build") {
1148 dodie "Failed on build" if $failed;
1149
1150 # Now boot the box
1151 get_grub_index;
1152 get_version;
1153 install;
1154
1155 start_monitor;
1156 monitor or $failed = 1;
1157
1158 if ($type ne "boot") {
1159 dodie "Failed on boot" if $failed;
1160
1161 do_run_test or $failed = 1;
1162 }
1163 end_monitor;
1164 }
1165
1166 if ($failed) {
1167 $result = 0;
1168
1169 # reboot the box to a good kernel
1170 if ($type ne "build") {
1171 doprint "Reboot and sleep $bisect_sleep_time seconds\n";
1172 reboot;
1173 start_monitor;
1174 wait_for_monitor $bisect_sleep_time;
1175 end_monitor;
1176 }
1177 } else {
1178 $result = 1;
1179 }
1180 $in_bisect = 0;
1181
1182 return $result;
1183}
1184
1185sub run_bisect {
1186 my ($type) = @_;
1187 my $buildtype = "oldconfig";
1188
1189 # We should have a minconfig to use?
1190 if (defined($minconfig)) {
1191 $buildtype = "useconfig:$minconfig";
1192 }
1193
1194 my $ret = run_bisect_test $type, $buildtype;
1195
1196
1197 # Are we looking for where it worked, not failed?
1198 if ($reverse_bisect) {
1199 $ret = !$ret;
1200 }
1201
1202 if ($ret) {
1203 return "good";
1204 } else {
1205 return "bad";
1206 }
1207}
1208
1209sub bisect {
1210 my ($i) = @_;
1211
1212 my $result;
1213
1214 die "BISECT_GOOD[$i] not defined\n" if (!defined($opt{"BISECT_GOOD[$i]"}));
1215 die "BISECT_BAD[$i] not defined\n" if (!defined($opt{"BISECT_BAD[$i]"}));
1216 die "BISECT_TYPE[$i] not defined\n" if (!defined($opt{"BISECT_TYPE[$i]"}));
1217
1218 my $good = $opt{"BISECT_GOOD[$i]"};
1219 my $bad = $opt{"BISECT_BAD[$i]"};
1220 my $type = $opt{"BISECT_TYPE[$i]"};
1221 my $start = $opt{"BISECT_START[$i]"};
1222 my $replay = $opt{"BISECT_REPLAY[$i]"};
1223
1224 # convert to true sha1's
1225 $good = get_sha1($good);
1226 $bad = get_sha1($bad);
1227
1228 if (defined($opt{"BISECT_REVERSE[$i]"}) &&
1229 $opt{"BISECT_REVERSE[$i]"} == 1) {
1230 doprint "Performing a reverse bisect (bad is good, good is bad!)\n";
1231 $reverse_bisect = 1;
1232 } else {
1233 $reverse_bisect = 0;
1234 }
1235
1236 # Can't have a test without having a test to run
1237 if ($type eq "test" && !defined($run_test)) {
1238 $type = "boot";
1239 }
1240
1241 my $check = $opt{"BISECT_CHECK[$i]"};
1242 if (defined($check) && $check ne "0") {
1243
1244 # get current HEAD
1245 my $head = get_sha1("HEAD");
1246
1247 if ($check ne "good") {
1248 doprint "TESTING BISECT BAD [$bad]\n";
1249 run_command "git checkout $bad" or
1250 die "Failed to checkout $bad";
1251
1252 $result = run_bisect $type;
1253
1254 if ($result ne "bad") {
1255 fail "Tested BISECT_BAD [$bad] and it succeeded" and return 0;
1256 }
1257 }
1258
1259 if ($check ne "bad") {
1260 doprint "TESTING BISECT GOOD [$good]\n";
1261 run_command "git checkout $good" or
1262 die "Failed to checkout $good";
1263
1264 $result = run_bisect $type;
1265
1266 if ($result ne "good") {
1267 fail "Tested BISECT_GOOD [$good] and it failed" and return 0;
1268 }
1269 }
1270
1271 # checkout where we started
1272 run_command "git checkout $head" or
1273 die "Failed to checkout $head";
1274 }
1275
1276 run_command "git bisect start" or
1277 dodie "could not start bisect";
1278
1279 run_command "git bisect good $good" or
1280 dodie "could not set bisect good to $good";
1281
1282 run_git_bisect "git bisect bad $bad" or
1283 dodie "could not set bisect bad to $bad";
1284
1285 if (defined($replay)) {
1286 run_command "git bisect replay $replay" or
1287 dodie "failed to run replay";
1288 }
1289
1290 if (defined($start)) {
1291 run_command "git checkout $start" or
1292 dodie "failed to checkout $start";
1293 }
1294
1295 my $test;
1296 do {
1297 $result = run_bisect $type;
1298 $test = run_git_bisect "git bisect $result";
1299 } while ($test);
1300
1301 run_command "git bisect log" or
1302 dodie "could not capture git bisect log";
1303
1304 run_command "git bisect reset" or
1305 dodie "could not reset git bisect";
1306
1307 doprint "Bad commit was [$bisect_bad]\n";
1308
1309 success $i;
1310}
1311
1312my %config_ignore;
1313my %config_set;
1314
1315my %config_list;
1316my %null_config;
1317
1318my %dependency;
1319
1320sub process_config_ignore {
1321 my ($config) = @_;
1322
1323 open (IN, $config)
1324 or dodie "Failed to read $config";
1325
1326 while (<IN>) {
1327 if (/^(.*?(CONFIG\S*)(=.*| is not set))/) {
1328 $config_ignore{$2} = $1;
1329 }
1330 }
1331
1332 close(IN);
1333}
1334
1335sub read_current_config {
1336 my ($config_ref) = @_;
1337
1338 %{$config_ref} = ();
1339 undef %{$config_ref};
1340
1341 my @key = keys %{$config_ref};
1342 if ($#key >= 0) {
1343 print "did not delete!\n";
1344 exit;
1345 }
1346 open (IN, "$output_config");
1347
1348 while (<IN>) {
1349 if (/^(CONFIG\S+)=(.*)/) {
1350 ${$config_ref}{$1} = $2;
1351 }
1352 }
1353 close(IN);
1354}
1355
1356sub get_dependencies {
1357 my ($config) = @_;
1358
1359 my $arr = $dependency{$config};
1360 if (!defined($arr)) {
1361 return ();
1362 }
1363
1364 my @deps = @{$arr};
1365
1366 foreach my $dep (@{$arr}) {
1367 print "ADD DEP $dep\n";
1368 @deps = (@deps, get_dependencies $dep);
1369 }
1370
1371 return @deps;
1372}
1373
1374sub create_config {
1375 my @configs = @_;
1376
1377 open(OUT, ">$output_config") or dodie "Can not write to $output_config";
1378
1379 foreach my $config (@configs) {
1380 print OUT "$config_set{$config}\n";
1381 my @deps = get_dependencies $config;
1382 foreach my $dep (@deps) {
1383 print OUT "$config_set{$dep}\n";
1384 }
1385 }
1386
1387 foreach my $config (keys %config_ignore) {
1388 print OUT "$config_ignore{$config}\n";
1389 }
1390 close(OUT);
1391
1392# exit;
1393 run_command "$make oldnoconfig" or
1394 dodie "failed make config oldconfig";
1395
1396}
1397
1398sub compare_configs {
1399 my (%a, %b) = @_;
1400
1401 foreach my $item (keys %a) {
1402 if (!defined($b{$item})) {
1403 print "diff $item\n";
1404 return 1;
1405 }
1406 delete $b{$item};
1407 }
1408
1409 my @keys = keys %b;
1410 if ($#keys) {
1411 print "diff2 $keys[0]\n";
1412 }
1413 return -1 if ($#keys >= 0);
1414
1415 return 0;
1416}
1417
1418sub run_config_bisect_test {
1419 my ($type) = @_;
1420
1421 return run_bisect_test $type, "oldconfig";
1422}
1423
1424sub process_passed {
1425 my (%configs) = @_;
1426
1427 doprint "These configs had no failure: (Enabling them for further compiles)\n";
1428 # Passed! All these configs are part of a good compile.
1429 # Add them to the min options.
1430 foreach my $config (keys %configs) {
1431 if (defined($config_list{$config})) {
1432 doprint " removing $config\n";
1433 $config_ignore{$config} = $config_list{$config};
1434 delete $config_list{$config};
1435 }
1436 }
1437 doprint "config copied to $outputdir/config_good\n";
1438 run_command "cp -f $output_config $outputdir/config_good";
1439}
1440
1441sub process_failed {
1442 my ($config) = @_;
1443
1444 doprint "\n\n***************************************\n";
1445 doprint "Found bad config: $config\n";
1446 doprint "***************************************\n\n";
1447}
1448
1449sub run_config_bisect {
1450
1451 my @start_list = keys %config_list;
1452
1453 if ($#start_list < 0) {
1454 doprint "No more configs to test!!!\n";
1455 return -1;
1456 }
1457
1458 doprint "***** RUN TEST ***\n";
1459 my $type = $opt{"CONFIG_BISECT_TYPE[$iteration]"};
1460 my $ret;
1461 my %current_config;
1462
1463 my $count = $#start_list + 1;
1464 doprint " $count configs to test\n";
1465
1466 my $half = int($#start_list / 2);
1467
1468 do {
1469 my @tophalf = @start_list[0 .. $half];
1470
1471 create_config @tophalf;
1472 read_current_config \%current_config;
1473
1474 $count = $#tophalf + 1;
1475 doprint "Testing $count configs\n";
1476 my $found = 0;
1477 # make sure we test something
1478 foreach my $config (@tophalf) {
1479 if (defined($current_config{$config})) {
1480 logit " $config\n";
1481 $found = 1;
1482 }
1483 }
1484 if (!$found) {
1485 # try the other half
1486 doprint "Top half produced no set configs, trying bottom half\n";
1487 @tophalf = @start_list[$half .. $#start_list];
1488 create_config @tophalf;
1489 read_current_config \%current_config;
1490 foreach my $config (@tophalf) {
1491 if (defined($current_config{$config})) {
1492 logit " $config\n";
1493 $found = 1;
1494 }
1495 }
1496 if (!$found) {
1497 doprint "Failed: Can't make new config with current configs\n";
1498 foreach my $config (@start_list) {
1499 doprint " CONFIG: $config\n";
1500 }
1501 return -1;
1502 }
1503 $count = $#tophalf + 1;
1504 doprint "Testing $count configs\n";
1505 }
1506
1507 $ret = run_config_bisect_test $type;
1508
1509 if ($ret) {
1510 process_passed %current_config;
1511 return 0;
1512 }
1513
1514 doprint "This config had a failure.\n";
1515 doprint "Removing these configs that were not set in this config:\n";
1516 doprint "config copied to $outputdir/config_bad\n";
1517 run_command "cp -f $output_config $outputdir/config_bad";
1518
1519 # A config exists in this group that was bad.
1520 foreach my $config (keys %config_list) {
1521 if (!defined($current_config{$config})) {
1522 doprint " removing $config\n";
1523 delete $config_list{$config};
1524 }
1525 }
1526
1527 @start_list = @tophalf;
1528
1529 if ($#start_list == 0) {
1530 process_failed $start_list[0];
1531 return 1;
1532 }
1533
1534 # remove half the configs we are looking at and see if
1535 # they are good.
1536 $half = int($#start_list / 2);
1537 } while ($half > 0);
1538
1539 # we found a single config, try it again
1540 my @tophalf = @start_list[0 .. 0];
1541
1542 $ret = run_config_bisect_test $type;
1543 if ($ret) {
1544 process_passed %current_config;
1545 return 0;
1546 }
1547
1548 process_failed $start_list[0];
1549 return 1;
1550}
1551
1552sub config_bisect {
1553 my ($i) = @_;
1554
1555 my $start_config = $opt{"CONFIG_BISECT[$i]"};
1556
1557 my $tmpconfig = "$tmpdir/use_config";
1558
1559 # Make the file with the bad config and the min config
1560 if (defined($minconfig)) {
1561 # read the min config for things to ignore
1562 run_command "cp $minconfig $tmpconfig" or
1563 dodie "failed to copy $minconfig to $tmpconfig";
1564 } else {
1565 unlink $tmpconfig;
1566 }
1567
1568 # Add other configs
1569 if (defined($addconfig)) {
1570 run_command "cat $addconfig >> $tmpconfig" or
1571 dodie "failed to append $addconfig";
1572 }
1573
1574 my $defconfig = "";
1575 if (-f $tmpconfig) {
1576 $defconfig = "KCONFIG_ALLCONFIG=$tmpconfig";
1577 process_config_ignore $tmpconfig;
1578 }
1579
1580 # now process the start config
1581 run_command "cp $start_config $output_config" or
1582 dodie "failed to copy $start_config to $output_config";
1583
1584 # read directly what we want to check
1585 my %config_check;
1586 open (IN, $output_config)
1587 or dodie "faied to open $output_config";
1588
1589 while (<IN>) {
1590 if (/^((CONFIG\S*)=.*)/) {
1591 $config_check{$2} = $1;
1592 }
1593 }
1594 close(IN);
1595
1596 # Now run oldconfig with the minconfig (and addconfigs)
1597 run_command "$defconfig $make oldnoconfig" or
1598 dodie "failed make config oldconfig";
1599
1600 # check to see what we lost (or gained)
1601 open (IN, $output_config)
1602 or dodie "Failed to read $start_config";
1603
1604 my %removed_configs;
1605 my %added_configs;
1606
1607 while (<IN>) {
1608 if (/^((CONFIG\S*)=.*)/) {
1609 # save off all options
1610 $config_set{$2} = $1;
1611 if (defined($config_check{$2})) {
1612 if (defined($config_ignore{$2})) {
1613 $removed_configs{$2} = $1;
1614 } else {
1615 $config_list{$2} = $1;
1616 }
1617 } elsif (!defined($config_ignore{$2})) {
1618 $added_configs{$2} = $1;
1619 $config_list{$2} = $1;
1620 }
1621 }
1622 }
1623 close(IN);
1624
1625 my @confs = keys %removed_configs;
1626 if ($#confs >= 0) {
1627 doprint "Configs overridden by default configs and removed from check:\n";
1628 foreach my $config (@confs) {
1629 doprint " $config\n";
1630 }
1631 }
1632 @confs = keys %added_configs;
1633 if ($#confs >= 0) {
1634 doprint "Configs appearing in make oldconfig and added:\n";
1635 foreach my $config (@confs) {
1636 doprint " $config\n";
1637 }
1638 }
1639
1640 my %config_test;
1641 my $once = 0;
1642
1643 # Sometimes kconfig does weird things. We must make sure
1644 # that the config we autocreate has everything we need
1645 # to test, otherwise we may miss testing configs, or
1646 # may not be able to create a new config.
1647 # Here we create a config with everything set.
1648 create_config (keys %config_list);
1649 read_current_config \%config_test;
1650 foreach my $config (keys %config_list) {
1651 if (!defined($config_test{$config})) {
1652 if (!$once) {
1653 $once = 1;
1654 doprint "Configs not produced by kconfig (will not be checked):\n";
1655 }
1656 doprint " $config\n";
1657 delete $config_list{$config};
1658 }
1659 }
1660 my $ret;
1661 do {
1662 $ret = run_config_bisect;
1663 } while (!$ret);
1664
1665 return $ret if ($ret < 0);
1666
1667 success $i;
1668}
1669
1670sub patchcheck {
1671 my ($i) = @_;
1672
1673 die "PATCHCHECK_START[$i] not defined\n"
1674 if (!defined($opt{"PATCHCHECK_START[$i]"}));
1675 die "PATCHCHECK_TYPE[$i] not defined\n"
1676 if (!defined($opt{"PATCHCHECK_TYPE[$i]"}));
1677
1678 my $start = $opt{"PATCHCHECK_START[$i]"};
1679
1680 my $end = "HEAD";
1681 if (defined($opt{"PATCHCHECK_END[$i]"})) {
1682 $end = $opt{"PATCHCHECK_END[$i]"};
1683 }
1684
1685 # Get the true sha1's since we can use things like HEAD~3
1686 $start = get_sha1($start);
1687 $end = get_sha1($end);
1688
1689 my $type = $opt{"PATCHCHECK_TYPE[$i]"};
1690
1691 # Can't have a test without having a test to run
1692 if ($type eq "test" && !defined($run_test)) {
1693 $type = "boot";
1694 }
1695
1696 open (IN, "git log --pretty=oneline $end|") or
1697 dodie "could not get git list";
1698
1699 my @list;
1700
1701 while (<IN>) {
1702 chomp;
1703 $list[$#list+1] = $_;
1704 last if (/^$start/);
1705 }
1706 close(IN);
1707
1708 if ($list[$#list] !~ /^$start/) {
1709 fail "SHA1 $start not found";
1710 }
1711
1712 # go backwards in the list
1713 @list = reverse @list;
1714
1715 my $save_clean = $noclean;
1716
1717 $in_patchcheck = 1;
1718 foreach my $item (@list) {
1719 my $sha1 = $item;
1720 $sha1 =~ s/^([[:xdigit:]]+).*/$1/;
1721
1722 doprint "\nProcessing commit $item\n\n";
1723
1724 run_command "git checkout $sha1" or
1725 die "Failed to checkout $sha1";
1726
1727 # only clean on the first and last patch
1728 if ($item eq $list[0] ||
1729 $item eq $list[$#list]) {
1730 $noclean = $save_clean;
1731 } else {
1732 $noclean = 1;
1733 }
1734
1735 if (defined($minconfig)) {
1736 build "useconfig:$minconfig" or return 0;
1737 } else {
1738 # ?? no config to use?
1739 build "oldconfig" or return 0;
1740 }
1741
1742 check_buildlog $sha1 or return 0;
1743
1744 next if ($type eq "build");
1745
1746 get_grub_index;
1747 get_version;
1748 install;
1749
1750 my $failed = 0;
1751
1752 start_monitor;
1753 monitor or $failed = 1;
1754
1755 if (!$failed && $type ne "boot"){
1756 do_run_test or $failed = 1;
1757 }
1758 end_monitor;
1759 return 0 if ($failed);
1760
1761 }
1762 $in_patchcheck = 0;
1763 success $i;
1764
1765 return 1;
1766}
1767
1768$#ARGV < 1 or die "ktest.pl version: $VERSION\n usage: ktest.pl config-file\n";
1769
1770if ($#ARGV == 0) {
1771 $ktest_config = $ARGV[0];
1772 if (! -f $ktest_config) {
1773 print "$ktest_config does not exist.\n";
1774 my $ans;
1775 for (;;) {
1776 print "Create it? [Y/n] ";
1777 $ans = <STDIN>;
1778 chomp $ans;
1779 if ($ans =~ /^\s*$/) {
1780 $ans = "y";
1781 }
1782 last if ($ans =~ /^y$/i || $ans =~ /^n$/i);
1783 print "Please answer either 'y' or 'n'.\n";
1784 }
1785 if ($ans !~ /^y$/i) {
1786 exit 0;
1787 }
1788 }
1789} else {
1790 $ktest_config = "ktest.conf";
1791}
1792
1793if (! -f $ktest_config) {
1794 open(OUT, ">$ktest_config") or die "Can not create $ktest_config";
1795 print OUT << "EOF"
1796# Generated by ktest.pl
1797#
1798# Define each test with TEST_START
1799# The config options below it will override the defaults
1800TEST_START
1801
1802DEFAULTS
1803EOF
1804;
1805 close(OUT);
1806}
1807read_config $ktest_config;
1808
1809# Append any configs entered in manually to the config file.
1810my @new_configs = keys %entered_configs;
1811if ($#new_configs >= 0) {
1812 print "\nAppending entered in configs to $ktest_config\n";
1813 open(OUT, ">>$ktest_config") or die "Can not append to $ktest_config";
1814 foreach my $config (@new_configs) {
1815 print OUT "$config = $entered_configs{$config}\n";
1816 $opt{$config} = $entered_configs{$config};
1817 }
1818}
1819
1820if ($opt{"CLEAR_LOG"} && defined($opt{"LOG_FILE"})) {
1821 unlink $opt{"LOG_FILE"};
1822}
1823
1824doprint "\n\nSTARTING AUTOMATED TESTS\n\n";
1825
1826for (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) {
1827
1828 if (!$i) {
1829 doprint "DEFAULT OPTIONS:\n";
1830 } else {
1831 doprint "\nTEST $i OPTIONS";
1832 if (defined($repeat_tests{$i})) {
1833 $repeat = $repeat_tests{$i};
1834 doprint " ITERATE $repeat";
1835 }
1836 doprint "\n";
1837 }
1838
1839 foreach my $option (sort keys %opt) {
1840
1841 if ($option =~ /\[(\d+)\]$/) {
1842 next if ($i != $1);
1843 } else {
1844 next if ($i);
1845 }
1846
1847 doprint "$option = $opt{$option}\n";
1848 }
1849}
1850
1851sub set_test_option {
1852 my ($name, $i) = @_;
1853
1854 my $option = "$name\[$i\]";
1855
1856 if (defined($opt{$option})) {
1857 return $opt{$option};
1858 }
1859
1860 foreach my $test (keys %repeat_tests) {
1861 if ($i >= $test &&
1862 $i < $test + $repeat_tests{$test}) {
1863 $option = "$name\[$test\]";
1864 if (defined($opt{$option})) {
1865 return $opt{$option};
1866 }
1867 }
1868 }
1869
1870 if (defined($opt{$name})) {
1871 return $opt{$name};
1872 }
1873
1874 return undef;
1875}
1876
1877# First we need to do is the builds
1878for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
1879
1880 $iteration = $i;
1881
1882 my $makecmd = set_test_option("MAKE_CMD", $i);
1883
1884 $machine = set_test_option("MACHINE", $i);
1885 $ssh_user = set_test_option("SSH_USER", $i);
1886 $tmpdir = set_test_option("TMP_DIR", $i);
1887 $outputdir = set_test_option("OUTPUT_DIR", $i);
1888 $builddir = set_test_option("BUILD_DIR", $i);
1889 $test_type = set_test_option("TEST_TYPE", $i);
1890 $build_type = set_test_option("BUILD_TYPE", $i);
1891 $build_options = set_test_option("BUILD_OPTIONS", $i);
1892 $power_cycle = set_test_option("POWER_CYCLE", $i);
1893 $reboot = set_test_option("REBOOT", $i);
1894 $noclean = set_test_option("BUILD_NOCLEAN", $i);
1895 $minconfig = set_test_option("MIN_CONFIG", $i);
1896 $run_test = set_test_option("TEST", $i);
1897 $addconfig = set_test_option("ADD_CONFIG", $i);
1898 $reboot_type = set_test_option("REBOOT_TYPE", $i);
1899 $grub_menu = set_test_option("GRUB_MENU", $i);
1900 $post_install = set_test_option("POST_INSTALL", $i);
1901 $reboot_script = set_test_option("REBOOT_SCRIPT", $i);
1902 $reboot_on_error = set_test_option("REBOOT_ON_ERROR", $i);
1903 $poweroff_on_error = set_test_option("POWEROFF_ON_ERROR", $i);
1904 $die_on_failure = set_test_option("DIE_ON_FAILURE", $i);
1905 $power_off = set_test_option("POWER_OFF", $i);
1906 $powercycle_after_reboot = set_test_option("POWERCYCLE_AFTER_REBOOT", $i);
1907 $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i);
1908 $sleep_time = set_test_option("SLEEP_TIME", $i);
1909 $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i);
1910 $store_failures = set_test_option("STORE_FAILURES", $i);
1911 $timeout = set_test_option("TIMEOUT", $i);
1912 $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i);
1913 $console = set_test_option("CONSOLE", $i);
1914 $success_line = set_test_option("SUCCESS_LINE", $i);
1915 $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i);
1916 $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i);
1917 $build_target = set_test_option("BUILD_TARGET", $i);
1918 $ssh_exec = set_test_option("SSH_EXEC", $i);
1919 $scp_to_target = set_test_option("SCP_TO_TARGET", $i);
1920 $target_image = set_test_option("TARGET_IMAGE", $i);
1921 $localversion = set_test_option("LOCALVERSION", $i);
1922
1923 chdir $builddir || die "can't change directory to $builddir";
1924
1925 if (!-d $tmpdir) {
1926 mkpath($tmpdir) or
1927 die "can't create $tmpdir";
1928 }
1929
1930 $ENV{"SSH_USER"} = $ssh_user;
1931 $ENV{"MACHINE"} = $machine;
1932
1933 $target = "$ssh_user\@$machine";
1934
1935 $buildlog = "$tmpdir/buildlog-$machine";
1936 $dmesg = "$tmpdir/dmesg-$machine";
1937 $make = "$makecmd O=$outputdir";
1938 $output_config = "$outputdir/.config";
1939
1940 if ($reboot_type eq "grub") {
1941 dodie "GRUB_MENU not defined" if (!defined($grub_menu));
1942 } elsif (!defined($reboot_script)) {
1943 dodie "REBOOT_SCRIPT not defined"
1944 }
1945
1946 my $run_type = $build_type;
1947 if ($test_type eq "patchcheck") {
1948 $run_type = $opt{"PATCHCHECK_TYPE[$i]"};
1949 } elsif ($test_type eq "bisect") {
1950 $run_type = $opt{"BISECT_TYPE[$i]"};
1951 } elsif ($test_type eq "config_bisect") {
1952 $run_type = $opt{"CONFIG_BISECT_TYPE[$i]"};
1953 }
1954
1955 # mistake in config file?
1956 if (!defined($run_type)) {
1957 $run_type = "ERROR";
1958 }
1959
1960 doprint "\n\n";
1961 doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type\n\n";
1962
1963 unlink $dmesg;
1964 unlink $buildlog;
1965
1966 if (!defined($minconfig)) {
1967 $minconfig = $addconfig;
1968
1969 } elsif (defined($addconfig)) {
1970 run_command "cat $addconfig $minconfig > $tmpdir/add_config" or
1971 dodie "Failed to create temp config";
1972 $minconfig = "$tmpdir/add_config";
1973 }
1974
1975 my $checkout = $opt{"CHECKOUT[$i]"};
1976 if (defined($checkout)) {
1977 run_command "git checkout $checkout" or
1978 die "failed to checkout $checkout";
1979 }
1980
1981 if ($test_type eq "bisect") {
1982 bisect $i;
1983 next;
1984 } elsif ($test_type eq "config_bisect") {
1985 config_bisect $i;
1986 next;
1987 } elsif ($test_type eq "patchcheck") {
1988 patchcheck $i;
1989 next;
1990 }
1991
1992 if ($build_type ne "nobuild") {
1993 build $build_type or next;
1994 }
1995
1996 if ($test_type ne "build") {
1997 get_grub_index;
1998 get_version;
1999 install;
2000
2001 my $failed = 0;
2002 start_monitor;
2003 monitor or $failed = 1;;
2004
2005 if (!$failed && $test_type ne "boot" && defined($run_test)) {
2006 do_run_test or $failed = 1;
2007 }
2008 end_monitor;
2009 next if ($failed);
2010 }
2011
2012 success $i;
2013}
2014
2015if ($opt{"POWEROFF_ON_SUCCESS"}) {
2016 halt;
2017} elsif ($opt{"REBOOT_ON_SUCCESS"} && !do_not_reboot) {
2018 reboot;
2019}
2020
2021doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n";
2022
2023exit 0;
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
new file mode 100644
index 000000000000..3408c594b2de
--- /dev/null
+++ b/tools/testing/ktest/sample.conf
@@ -0,0 +1,622 @@
1#
2# Config file for ktest.pl
3#
4# Note, all paths must be absolute
5#
6
7# Options set in the beginning of the file are considered to be
8# default options. These options can be overriden by test specific
9# options, with the following exceptions:
10#
11# LOG_FILE
12# CLEAR_LOG
13# POWEROFF_ON_SUCCESS
14# REBOOT_ON_SUCCESS
15#
16# Test specific options are set after the label:
17#
18# TEST_START
19#
20# The options after a TEST_START label are specific to that test.
21# Each TEST_START label will set up a new test. If you want to
22# perform a test more than once, you can add the ITERATE label
23# to it followed by the number of times you want that test
24# to iterate. If the ITERATE is left off, the test will only
25# be performed once.
26#
27# TEST_START ITERATE 10
28#
29# You can skip a test by adding SKIP (before or after the ITERATE
30# and number)
31#
32# TEST_START SKIP
33#
34# TEST_START SKIP ITERATE 10
35#
36# TEST_START ITERATE 10 SKIP
37#
38# The SKIP label causes the options and the test itself to be ignored.
39# This is useful to set up several different tests in one config file, and
40# only enabling the ones you want to use for a current test run.
41#
42# You can add default options anywhere in the file as well
43# with the DEFAULTS tag. This allows you to have default options
44# after the test options to keep the test options at the top
45# of the file. You can even place the DEFAULTS tag between
46# test cases (but not in the middle of a single test case)
47#
48# TEST_START
49# MIN_CONFIG = /home/test/config-test1
50#
51# DEFAULTS
52# MIN_CONFIG = /home/test/config-default
53#
54# TEST_START ITERATE 10
55#
56# The above will run the first test with MIN_CONFIG set to
57# /home/test/config-test-1. Then 10 tests will be executed
58# with MIN_CONFIG with /home/test/config-default.
59#
60# You can also disable defaults with the SKIP option
61#
62# DEFAULTS SKIP
63# MIN_CONFIG = /home/test/config-use-sometimes
64#
65# DEFAULTS
66# MIN_CONFIG = /home/test/config-most-times
67#
68# The above will ignore the first MIN_CONFIG. If you want to
69# use the first MIN_CONFIG, remove the SKIP from the first
70# DEFAULTS tag and add it to the second. Be careful, options
71# may only be declared once per test or default. If you have
72# the same option name under the same test or as default
73# ktest will fail to execute, and no tests will run.
74#
75
76
77#### Mandatory Default Options ####
78
79# These options must be in the default section, although most
80# may be overridden by test options.
81
82# The machine hostname that you will test
83#MACHINE = target
84
85# The box is expected to have ssh on normal bootup, provide the user
86# (most likely root, since you need privileged operations)
87#SSH_USER = root
88
89# The directory that contains the Linux source code
90#BUILD_DIR = /home/test/linux.git
91
92# The directory that the objects will be built
93# (can not be same as BUILD_DIR)
94#OUTPUT_DIR = /home/test/build/target
95
96# The location of the compiled file to copy to the target
97# (relative to OUTPUT_DIR)
98#BUILD_TARGET = arch/x86/boot/bzImage
99
100# The place to put your image on the test machine
101#TARGET_IMAGE = /boot/vmlinuz-test
102
103# A script or command to reboot the box
104#
105# Here is a digital loggers power switch example
106#POWER_CYCLE = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin@power/outlet?5=CCL'
107#
108# Here is an example to reboot a virtual box on the current host
109# with the name "Guest".
110#POWER_CYCLE = virsh destroy Guest; sleep 5; virsh start Guest
111
112# The script or command that reads the console
113#
114# If you use ttywatch server, something like the following would work.
115#CONSOLE = nc -d localhost 3001
116#
117# For a virtual machine with guest name "Guest".
118#CONSOLE = virsh console Guest
119
120# Required version ending to differentiate the test
121# from other linux builds on the system.
122#LOCALVERSION = -test
123
124# The grub title name for the test kernel to boot
125# (Only mandatory if REBOOT_TYPE = grub)
126#
127# Note, ktest.pl will not update the grub menu.lst, you need to
128# manually add an option for the test. ktest.pl will search
129# the grub menu.lst for this option to find what kernel to
130# reboot into.
131#
132# For example, if in the /boot/grub/menu.lst the test kernel title has:
133# title Test Kernel
134# kernel vmlinuz-test
135#GRUB_MENU = Test Kernel
136
137# A script to reboot the target into the test kernel
138# (Only mandatory if REBOOT_TYPE = script)
139#REBOOT_SCRIPT =
140
141#### Optional Config Options (all have defaults) ####
142
143# Start a test setup. If you leave this off, all options
144# will be default and the test will run once.
145# This is a label and not really an option (it takes no value).
146# You can append ITERATE and a number after it to iterate the
147# test a number of times, or SKIP to ignore this test.
148#
149#TEST_START
150#TEST_START ITERATE 5
151#TEST_START SKIP
152
153# Have the following options as default again. Used after tests
154# have already been defined by TEST_START. Optionally, you can
155# just define all default options before the first TEST_START
156# and you do not need this option.
157#
158# This is a label and not really an option (it takes no value).
159# You can append SKIP to this label and the options within this
160# section will be ignored.
161#
162# DEFAULTS
163# DEFAULTS SKIP
164
165# The default test type (default test)
166# The test types may be:
167# build - only build the kernel, do nothing else
168# boot - build and boot the kernel
169# test - build, boot and if TEST is set, run the test script
170# (If TEST is not set, it defaults back to boot)
171# bisect - Perform a bisect on the kernel (see BISECT_TYPE below)
172# patchcheck - Do a test on a series of commits in git (see PATCHCHECK below)
173#TEST_TYPE = test
174
175# Test to run if there is a successful boot and TEST_TYPE is test.
176# Must exit with 0 on success and non zero on error
177# default (undefined)
178#TEST = ssh user@machine /root/run_test
179
180# The build type is any make config type or special command
181# (default randconfig)
182# nobuild - skip the clean and build step
183# useconfig:/path/to/config - use the given config and run
184# oldconfig on it.
185# This option is ignored if TEST_TYPE is patchcheck or bisect
186#BUILD_TYPE = randconfig
187
188# The make command (default make)
189# If you are building a 32bit x86 on a 64 bit host
190#MAKE_CMD = CC=i386-gcc AS=i386-as make ARCH=i386
191
192# Any build options for the make of the kernel (not for other makes, like configs)
193# (default "")
194#BUILD_OPTIONS = -j20
195
196# If you need an initrd, you can add a script or code here to install
197# it. The environment variable KERNEL_VERSION will be set to the
198# kernel version that is used. Remember to add the initrd line
199# to your grub menu.lst file.
200#
201# Here's a couple of examples to use:
202#POST_INSTALL = ssh user@target /sbin/mkinitrd --allow-missing -f /boot/initramfs-test.img $KERNEL_VERSION
203#
204# or on some systems:
205#POST_INSTALL = ssh user@target /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
206
207# Way to reboot the box to the test kernel.
208# Only valid options so far are "grub" and "script"
209# (default grub)
210# If you specify grub, it will assume grub version 1
211# and will search in /boot/grub/menu.lst for the title $GRUB_MENU
212# and select that target to reboot to the kernel. If this is not
213# your setup, then specify "script" and have a command or script
214# specified in REBOOT_SCRIPT to boot to the target.
215#
216# The entry in /boot/grub/menu.lst must be entered in manually.
217# The test will not modify that file.
218#REBOOT_TYPE = grub
219
220# The min config that is needed to build for the machine
221# A nice way to create this is with the following:
222#
223# $ ssh target
224# $ lsmod > mymods
225# $ scp mymods host:/tmp
226# $ exit
227# $ cd linux.git
228# $ rm .config
229# $ make LSMOD=mymods localyesconfig
230# $ grep '^CONFIG' .config > /home/test/config-min
231#
232# If you want even less configs:
233#
234# log in directly to target (do not ssh)
235#
236# $ su
237# # lsmod | cut -d' ' -f1 | xargs rmmod
238#
239# repeat the above several times
240#
241# # lsmod > mymods
242# # reboot
243#
244# May need to reboot to get your network back to copy the mymods
245# to the host, and then remove the previous .config and run the
246# localyesconfig again. The CONFIG_MIN generated like this will
247# not guarantee network activity to the box so the TEST_TYPE of
248# test may fail.
249#
250# You might also want to set:
251# CONFIG_CMDLINE="<your options here>"
252# randconfig may set the above and override your real command
253# line options.
254# (default undefined)
255#MIN_CONFIG = /home/test/config-min
256
257# Sometimes there's options that just break the boot and
258# you do not care about. Here are a few:
259# # CONFIG_STAGING is not set
260# Staging drivers are horrible, and can break the build.
261# # CONFIG_SCSI_DEBUG is not set
262# SCSI_DEBUG may change your root partition
263# # CONFIG_KGDB_SERIAL_CONSOLE is not set
264# KGDB may cause oops waiting for a connection that's not there.
265# This option points to the file containing config options that will be prepended
266# to the MIN_CONFIG (or be the MIN_CONFIG if it is not set)
267#
268# Note, config options in MIN_CONFIG will override these options.
269#
270# (default undefined)
271#ADD_CONFIG = /home/test/config-broken
272
273# The location on the host where to write temp files
274# (default /tmp/ktest)
275#TMP_DIR = /tmp/ktest
276
277# Optional log file to write the status (recommended)
278# Note, this is a DEFAULT section only option.
279# (default undefined)
280#LOG_FILE = /home/test/logfiles/target.log
281
282# Remove old logfile if it exists before starting all tests.
283# Note, this is a DEFAULT section only option.
284# (default 0)
285#CLEAR_LOG = 0
286
287# Line to define a successful boot up in console output.
288# This is what the line contains, not the entire line. If you need
289# the entire line to match, then use regural expression syntax like:
290# (do not add any quotes around it)
291#
292# SUCCESS_LINE = ^MyBox Login:$
293#
294# (default "login:")
295#SUCCESS_LINE = login:
296
297# In case the console constantly fills the screen, having
298# a specified time to stop the test after success is recommended.
299# (in seconds)
300# (default 10)
301#STOP_AFTER_SUCCESS = 10
302
303# In case the console constantly fills the screen, having
304# a specified time to stop the test after failure is recommended.
305# (in seconds)
306# (default 60)
307#STOP_AFTER_FAILURE = 60
308
309# Stop testing if a build fails. If set, the script will end if
310# a failure is detected, otherwise it will save off the .config,
311# dmesg and bootlog in a directory called
312# MACHINE-TEST_TYPE_BUILD_TYPE-fail-yyyymmddhhmmss
313# if the STORE_FAILURES directory is set.
314# (default 1)
315# Note, even if this is set to zero, there are some errors that still
316# stop the tests.
317#DIE_ON_FAILURE = 1
318
319# Directory to store failure directories on failure. If this is not
320# set, DIE_ON_FAILURE=0 will not save off the .config, dmesg and
321# bootlog. This option is ignored if DIE_ON_FAILURE is not set.
322# (default undefined)
323#STORE_FAILURES = /home/test/failures
324
325# Build without doing a make mrproper, or removing .config
326# (default 0)
327#BUILD_NOCLEAN = 0
328
329# As the test reads the console, after it hits the SUCCESS_LINE
330# the time it waits for the monitor to settle down between reads
331# can usually be lowered.
332# (in seconds) (default 1)
333#BOOTED_TIMEOUT = 1
334
335# The timeout in seconds when we consider the box hung after
336# the console stop producing output. Be sure to leave enough
337# time here to get pass a reboot. Some machines may not produce
338# any console output for a long time during a reboot. You do
339# not want the test to fail just because the system was in
340# the process of rebooting to the test kernel.
341# (default 120)
342#TIMEOUT = 120
343
344# In between tests, a reboot of the box may occur, and this
345# is the time to wait for the console after it stops producing
346# output. Some machines may not produce a large lag on reboot
347# so this should accommodate it.
348# The difference between this and TIMEOUT, is that TIMEOUT happens
349# when rebooting to the test kernel. This sleep time happens
350# after a test has completed and we are about to start running
351# another test. If a reboot to the reliable kernel happens,
352# we wait SLEEP_TIME for the console to stop producing output
353# before starting the next test.
354# (default 60)
355#SLEEP_TIME = 60
356
357# The time in between bisects to sleep (in seconds)
358# (default 60)
359#BISECT_SLEEP_TIME = 60
360
361# Reboot the target box on error (default 0)
362#REBOOT_ON_ERROR = 0
363
364# Power off the target on error (ignored if REBOOT_ON_ERROR is set)
365# Note, this is a DEFAULT section only option.
366# (default 0)
367#POWEROFF_ON_ERROR = 0
368
369# Power off the target after all tests have completed successfully
370# Note, this is a DEFAULT section only option.
371# (default 0)
372#POWEROFF_ON_SUCCESS = 0
373
374# Reboot the target after all test completed successfully (default 1)
375# (ignored if POWEROFF_ON_SUCCESS is set)
376#REBOOT_ON_SUCCESS = 1
377
378# In case there are isses with rebooting, you can specify this
379# to always powercycle after this amount of time after calling
380# reboot.
381# Note, POWERCYCLE_AFTER_REBOOT = 0 does NOT disable it. It just
382# makes it powercycle immediately after rebooting. Do not define
383# it if you do not want it.
384# (default undefined)
385#POWERCYCLE_AFTER_REBOOT = 5
386
387# In case there's isses with halting, you can specify this
388# to always poweroff after this amount of time after calling
389# halt.
390# Note, POWEROFF_AFTER_HALT = 0 does NOT disable it. It just
391# makes it poweroff immediately after halting. Do not define
392# it if you do not want it.
393# (default undefined)
394#POWEROFF_AFTER_HALT = 20
395
396# A script or command to power off the box (default undefined)
397# Needed for POWEROFF_ON_ERROR and SUCCESS
398#
399# Example for digital loggers power switch:
400#POWER_OFF = wget --no-proxy -O /dev/null -q --auth-no-challenge 'http://admin:admin@power/outlet?5=OFF'
401#
402# Example for a virtual guest call "Guest".
403#POWER_OFF = virsh destroy Guest
404
405# The way to execute a command on the target
406# (default ssh $SSH_USER@$MACHINE $SSH_COMMAND";)
407# The variables SSH_USER, MACHINE and SSH_COMMAND are defined
408#SSH_EXEC = ssh $SSH_USER@$MACHINE $SSH_COMMAND";
409
410# The way to copy a file to the target
411# (default scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE)
412# The variables SSH_USER, MACHINE, SRC_FILE and DST_FILE are defined.
413#SCP_TO_TARGET = scp $SRC_FILE $SSH_USER@$MACHINE:$DST_FILE
414
415# The nice way to reboot the target
416# (default ssh $SSH_USER@$MACHINE reboot)
417# The variables SSH_USER and MACHINE are defined.
418#REBOOT = ssh $SSH_USER@$MACHINE reboot
419
420#### Per test run options ####
421# The following options are only allowed in TEST_START sections.
422# They are ignored in the DEFAULTS sections.
423#
424# All of these are optional and undefined by default, although
425# some of these options are required for TEST_TYPE of patchcheck
426# and bisect.
427#
428#
429# CHECKOUT = branch
430#
431# If the BUILD_DIR is a git repository, then you can set this option
432# to checkout the given branch before running the TEST. If you
433# specify this for the first run, that branch will be used for
434# all preceding tests until a new CHECKOUT is set.
435#
436#
437#
438# For TEST_TYPE = patchcheck
439#
440# This expects the BUILD_DIR to be a git repository, and
441# will checkout the PATCHCHECK_START commit.
442#
443# The option BUILD_TYPE will be ignored.
444#
445# The MIN_CONFIG will be used for all builds of the patchcheck. The build type
446# used for patchcheck is oldconfig.
447#
448# PATCHCHECK_START is required and is the first patch to
449# test (the SHA1 of the commit). You may also specify anything
450# that git checkout allows (branch name, tage, HEAD~3).
451#
452# PATCHCHECK_END is the last patch to check (default HEAD)
453#
454# PATCHCHECK_TYPE is required and is the type of test to run:
455# build, boot, test.
456#
457# Note, the build test will look for warnings, if a warning occurred
458# in a file that a commit touches, the build will fail.
459#
460# If BUILD_NOCLEAN is set, then make mrproper will not be run on
461# any of the builds, just like all other TEST_TYPE tests. But
462# what makes patchcheck different from the other tests, is if
463# BUILD_NOCLEAN is not set, only the first and last patch run
464# make mrproper. This helps speed up the test.
465#
466# Example:
467# TEST_START
468# TEST_TYPE = patchcheck
469# CHECKOUT = mybranch
470# PATCHCHECK_TYPE = boot
471# PATCHCHECK_START = 747e94ae3d1b4c9bf5380e569f614eb9040b79e7
472# PATCHCHECK_END = HEAD~2
473#
474#
475#
476# For TEST_TYPE = bisect
477#
478# You can specify a git bisect if the BUILD_DIR is a git repository.
479# The MIN_CONFIG will be used for all builds of the bisect. The build type
480# used for bisecting is oldconfig.
481#
482# The option BUILD_TYPE will be ignored.
483#
484# BISECT_TYPE is the type of test to perform:
485# build - bad fails to build
486# boot - bad builds but fails to boot
487# test - bad boots but fails a test
488#
489# BISECT_GOOD is the commit (SHA1) to label as good (accepts all git good commit types)
490# BISECT_BAD is the commit to label as bad (accepts all git bad commit types)
491#
492# The above three options are required for a bisect operation.
493#
494# BISECT_REPLAY = /path/to/replay/file (optional, default undefined)
495#
496# If an operation failed in the bisect that was not expected to
497# fail. Then the test ends. The state of the BUILD_DIR will be
498# left off at where the failure occurred. You can examine the
499# reason for the failure, and perhaps even find a git commit
500# that would work to continue with. You can run:
501#
502# git bisect log > /path/to/replay/file
503#
504# The adding:
505#
506# BISECT_REPLAY= /path/to/replay/file
507#
508# And running the test again. The test will perform the initial
509# git bisect start, git bisect good, and git bisect bad, and
510# then it will run git bisect replay on this file, before
511# continuing with the bisect.
512#
513# BISECT_START = commit (optional, default undefined)
514#
515# As with BISECT_REPLAY, if the test failed on a commit that
516# just happen to have a bad commit in the middle of the bisect,
517# and you need to skip it. If BISECT_START is defined, it
518# will checkout that commit after doing the initial git bisect start,
519# git bisect good, git bisect bad, and running the git bisect replay
520# if the BISECT_REPLAY is set.
521#
522# BISECT_REVERSE = 1 (optional, default 0)
523#
524# In those strange instances where it was broken forever
525# and you are trying to find where it started to work!
526# Set BISECT_GOOD to the commit that was last known to fail
527# Set BISECT_BAD to the commit that is known to start working.
528# With BISECT_REVERSE = 1, The test will consider failures as
529# good, and success as bad.
530#
531# BISECT_CHECK = 1 (optional, default 0)
532#
533# Just to be sure the good is good and bad is bad, setting
534# BISECT_CHECK to 1 will start the bisect by first checking
535# out BISECT_BAD and makes sure it fails, then it will check
536# out BISECT_GOOD and makes sure it succeeds before starting
537# the bisect (it works for BISECT_REVERSE too).
538#
539# You can limit the test to just check BISECT_GOOD or
540# BISECT_BAD with BISECT_CHECK = good or
541# BISECT_CHECK = bad, respectively.
542#
543# Example:
544# TEST_START
545# TEST_TYPE = bisect
546# BISECT_GOOD = v2.6.36
547# BISECT_BAD = b5153163ed580e00c67bdfecb02b2e3843817b3e
548# BISECT_TYPE = build
549# MIN_CONFIG = /home/test/config-bisect
550#
551#
552#
553# For TEST_TYPE = config_bisect
554#
555# In those cases that you have two different configs. One of them
556# work, the other does not, and you do not know what config causes
557# the problem.
558# The TEST_TYPE config_bisect will bisect the bad config looking for
559# what config causes the failure.
560#
561# The way it works is this:
562#
563# First it finds a config to work with. Since a different version, or
564# MIN_CONFIG may cause different dependecies, it must run through this
565# preparation.
566#
567# Overwrites any config set in the bad config with a config set in
568# either the MIN_CONFIG or ADD_CONFIG. Thus, make sure these configs
569# are minimal and do not disable configs you want to test:
570# (ie. # CONFIG_FOO is not set).
571#
572# An oldconfig is run on the bad config and any new config that
573# appears will be added to the configs to test.
574#
575# Finally, it generates a config with the above result and runs it
576# again through make oldconfig to produce a config that should be
577# satisfied by kconfig.
578#
579# Then it starts the bisect.
580#
581# The configs to test are cut in half. If all the configs in this
582# half depend on a config in the other half, then the other half
583# is tested instead. If no configs are enabled by either half, then
584# this means a circular dependency exists and the test fails.
585#
586# A config is created with the test half, and the bisect test is run.
587#
588# If the bisect succeeds, then all configs in the generated config
589# are removed from the configs to test and added to the configs that
590# will be enabled for all builds (they will be enabled, but not be part
591# of the configs to examine).
592#
593# If the bisect fails, then all test configs that were not enabled by
594# the config file are removed from the test. These configs will not
595# be enabled in future tests. Since current config failed, we consider
596# this to be a subset of the config that we started with.
597#
598# When we are down to one config, it is considered the bad config.
599#
600# Note, the config chosen may not be the true bad config. Due to
601# dependencies and selections of the kbuild system, mulitple
602# configs may be needed to cause a failure. If you disable the
603# config that was found and restart the test, if the test fails
604# again, it is recommended to rerun the config_bisect with a new
605# bad config without the found config enabled.
606#
607# The option BUILD_TYPE will be ignored.
608#
609# CONFIG_BISECT_TYPE is the type of test to perform:
610# build - bad fails to build
611# boot - bad builds but fails to boot
612# test - bad boots but fails a test
613#
614# CONFIG_BISECT is the config that failed to boot
615#
616# Example:
617# TEST_START
618# TEST_TYPE = config_bisect
619# CONFIG_BISECT_TYPE = build
620# CONFIG_BISECT = /home/test/¢onfig-bad
621# MIN_CONFIG = /home/test/config-min
622#
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
new file mode 100644
index 000000000000..bbe2e3a2ea62
--- /dev/null
+++ b/tools/usb/ffs-test.c
@@ -0,0 +1,554 @@
1/*
2 * ffs-test.c.c -- user mode filesystem api for usb composite function
3 *
4 * Copyright (C) 2010 Samsung Electronics
5 * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22/* $(CROSS_COMPILE)cc -Wall -Wextra -g -o ffs-test ffs-test.c -lpthread */
23
24
25#define _BSD_SOURCE /* for endian.h */
26
27#include <endian.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <pthread.h>
31#include <stdarg.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/ioctl.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38#include <unistd.h>
39
40#include <linux/usb/functionfs.h>
41
42
43/******************** Little Endian Handling ********************************/
44
45#define cpu_to_le16(x) htole16(x)
46#define cpu_to_le32(x) htole32(x)
47#define le32_to_cpu(x) le32toh(x)
48#define le16_to_cpu(x) le16toh(x)
49
50static inline __u16 get_unaligned_le16(const void *_ptr)
51{
52 const __u8 *ptr = _ptr;
53 return ptr[0] | (ptr[1] << 8);
54}
55
56static inline __u32 get_unaligned_le32(const void *_ptr)
57{
58 const __u8 *ptr = _ptr;
59 return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
60}
61
62static inline void put_unaligned_le16(__u16 val, void *_ptr)
63{
64 __u8 *ptr = _ptr;
65 *ptr++ = val;
66 *ptr++ = val >> 8;
67}
68
69static inline void put_unaligned_le32(__u32 val, void *_ptr)
70{
71 __u8 *ptr = _ptr;
72 *ptr++ = val;
73 *ptr++ = val >> 8;
74 *ptr++ = val >> 16;
75 *ptr++ = val >> 24;
76}
77
78
79/******************** Messages and Errors ***********************************/
80
81static const char argv0[] = "ffs-test";
82
83static unsigned verbosity = 7;
84
85static void _msg(unsigned level, const char *fmt, ...)
86{
87 if (level < 2)
88 level = 2;
89 else if (level > 7)
90 level = 7;
91
92 if (level <= verbosity) {
93 static const char levels[8][6] = {
94 [2] = "crit:",
95 [3] = "err: ",
96 [4] = "warn:",
97 [5] = "note:",
98 [6] = "info:",
99 [7] = "dbg: "
100 };
101
102 int _errno = errno;
103 va_list ap;
104
105 fprintf(stderr, "%s: %s ", argv0, levels[level]);
106 va_start(ap, fmt);
107 vfprintf(stderr, fmt, ap);
108 va_end(ap);
109
110 if (fmt[strlen(fmt) - 1] != '\n') {
111 char buffer[128];
112 strerror_r(_errno, buffer, sizeof buffer);
113 fprintf(stderr, ": (-%d) %s\n", _errno, buffer);
114 }
115
116 fflush(stderr);
117 }
118}
119
120#define die(...) (_msg(2, __VA_ARGS__), exit(1))
121#define err(...) _msg(3, __VA_ARGS__)
122#define warn(...) _msg(4, __VA_ARGS__)
123#define note(...) _msg(5, __VA_ARGS__)
124#define info(...) _msg(6, __VA_ARGS__)
125#define debug(...) _msg(7, __VA_ARGS__)
126
127#define die_on(cond, ...) do { \
128 if (cond) \
129 die(__VA_ARGS__); \
130 } while (0)
131
132
133/******************** Descriptors and Strings *******************************/
134
135static const struct {
136 struct usb_functionfs_descs_head header;
137 struct {
138 struct usb_interface_descriptor intf;
139 struct usb_endpoint_descriptor_no_audio sink;
140 struct usb_endpoint_descriptor_no_audio source;
141 } __attribute__((packed)) fs_descs, hs_descs;
142} __attribute__((packed)) descriptors = {
143 .header = {
144 .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC),
145 .length = cpu_to_le32(sizeof descriptors),
146 .fs_count = 3,
147 .hs_count = 3,
148 },
149 .fs_descs = {
150 .intf = {
151 .bLength = sizeof descriptors.fs_descs.intf,
152 .bDescriptorType = USB_DT_INTERFACE,
153 .bNumEndpoints = 2,
154 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
155 .iInterface = 1,
156 },
157 .sink = {
158 .bLength = sizeof descriptors.fs_descs.sink,
159 .bDescriptorType = USB_DT_ENDPOINT,
160 .bEndpointAddress = 1 | USB_DIR_IN,
161 .bmAttributes = USB_ENDPOINT_XFER_BULK,
162 /* .wMaxPacketSize = autoconfiguration (kernel) */
163 },
164 .source = {
165 .bLength = sizeof descriptors.fs_descs.source,
166 .bDescriptorType = USB_DT_ENDPOINT,
167 .bEndpointAddress = 2 | USB_DIR_OUT,
168 .bmAttributes = USB_ENDPOINT_XFER_BULK,
169 /* .wMaxPacketSize = autoconfiguration (kernel) */
170 },
171 },
172 .hs_descs = {
173 .intf = {
174 .bLength = sizeof descriptors.fs_descs.intf,
175 .bDescriptorType = USB_DT_INTERFACE,
176 .bNumEndpoints = 2,
177 .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
178 .iInterface = 1,
179 },
180 .sink = {
181 .bLength = sizeof descriptors.hs_descs.sink,
182 .bDescriptorType = USB_DT_ENDPOINT,
183 .bEndpointAddress = 1 | USB_DIR_IN,
184 .bmAttributes = USB_ENDPOINT_XFER_BULK,
185 .wMaxPacketSize = cpu_to_le16(512),
186 },
187 .source = {
188 .bLength = sizeof descriptors.hs_descs.source,
189 .bDescriptorType = USB_DT_ENDPOINT,
190 .bEndpointAddress = 2 | USB_DIR_OUT,
191 .bmAttributes = USB_ENDPOINT_XFER_BULK,
192 .wMaxPacketSize = cpu_to_le16(512),
193 .bInterval = 1, /* NAK every 1 uframe */
194 },
195 },
196};
197
198
199#define STR_INTERFACE_ "Source/Sink"
200
201static const struct {
202 struct usb_functionfs_strings_head header;
203 struct {
204 __le16 code;
205 const char str1[sizeof STR_INTERFACE_];
206 } __attribute__((packed)) lang0;
207} __attribute__((packed)) strings = {
208 .header = {
209 .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
210 .length = cpu_to_le32(sizeof strings),
211 .str_count = cpu_to_le32(1),
212 .lang_count = cpu_to_le32(1),
213 },
214 .lang0 = {
215 cpu_to_le16(0x0409), /* en-us */
216 STR_INTERFACE_,
217 },
218};
219
220#define STR_INTERFACE strings.lang0.str1
221
222
223/******************** Files and Threads Handling ****************************/
224
225struct thread;
226
227static ssize_t read_wrap(struct thread *t, void *buf, size_t nbytes);
228static ssize_t write_wrap(struct thread *t, const void *buf, size_t nbytes);
229static ssize_t ep0_consume(struct thread *t, const void *buf, size_t nbytes);
230static ssize_t fill_in_buf(struct thread *t, void *buf, size_t nbytes);
231static ssize_t empty_out_buf(struct thread *t, const void *buf, size_t nbytes);
232
233
234static struct thread {
235 const char *const filename;
236 size_t buf_size;
237
238 ssize_t (*in)(struct thread *, void *, size_t);
239 const char *const in_name;
240
241 ssize_t (*out)(struct thread *, const void *, size_t);
242 const char *const out_name;
243
244 int fd;
245 pthread_t id;
246 void *buf;
247 ssize_t status;
248} threads[] = {
249 {
250 "ep0", 4 * sizeof(struct usb_functionfs_event),
251 read_wrap, NULL,
252 ep0_consume, "<consume>",
253 0, 0, NULL, 0
254 },
255 {
256 "ep1", 8 * 1024,
257 fill_in_buf, "<in>",
258 write_wrap, NULL,
259 0, 0, NULL, 0
260 },
261 {
262 "ep2", 8 * 1024,
263 read_wrap, NULL,
264 empty_out_buf, "<out>",
265 0, 0, NULL, 0
266 },
267};
268
269
270static void init_thread(struct thread *t)
271{
272 t->buf = malloc(t->buf_size);
273 die_on(!t->buf, "malloc");
274
275 t->fd = open(t->filename, O_RDWR);
276 die_on(t->fd < 0, "%s", t->filename);
277}
278
279static void cleanup_thread(void *arg)
280{
281 struct thread *t = arg;
282 int ret, fd;
283
284 fd = t->fd;
285 if (t->fd < 0)
286 return;
287 t->fd = -1;
288
289 /* test the FIFO ioctls (non-ep0 code paths) */
290 if (t != threads) {
291 ret = ioctl(fd, FUNCTIONFS_FIFO_STATUS);
292 if (ret < 0) {
293 /* ENODEV reported after disconnect */
294 if (errno != ENODEV)
295 err("%s: get fifo status", t->filename);
296 } else if (ret) {
297 warn("%s: unclaimed = %d\n", t->filename, ret);
298 if (ioctl(fd, FUNCTIONFS_FIFO_FLUSH) < 0)
299 err("%s: fifo flush", t->filename);
300 }
301 }
302
303 if (close(fd) < 0)
304 err("%s: close", t->filename);
305
306 free(t->buf);
307 t->buf = NULL;
308}
309
310static void *start_thread_helper(void *arg)
311{
312 const char *name, *op, *in_name, *out_name;
313 struct thread *t = arg;
314 ssize_t ret;
315
316 info("%s: starts\n", t->filename);
317 in_name = t->in_name ? t->in_name : t->filename;
318 out_name = t->out_name ? t->out_name : t->filename;
319
320 pthread_cleanup_push(cleanup_thread, arg);
321
322 for (;;) {
323 pthread_testcancel();
324
325 ret = t->in(t, t->buf, t->buf_size);
326 if (ret > 0) {
327 ret = t->out(t, t->buf, t->buf_size);
328 name = out_name;
329 op = "write";
330 } else {
331 name = in_name;
332 op = "read";
333 }
334
335 if (ret > 0) {
336 /* nop */
337 } else if (!ret) {
338 debug("%s: %s: EOF", name, op);
339 break;
340 } else if (errno == EINTR || errno == EAGAIN) {
341 debug("%s: %s", name, op);
342 } else {
343 warn("%s: %s", name, op);
344 break;
345 }
346 }
347
348 pthread_cleanup_pop(1);
349
350 t->status = ret;
351 info("%s: ends\n", t->filename);
352 return NULL;
353}
354
355static void start_thread(struct thread *t)
356{
357 debug("%s: starting\n", t->filename);
358
359 die_on(pthread_create(&t->id, NULL, start_thread_helper, t) < 0,
360 "pthread_create(%s)", t->filename);
361}
362
363static void join_thread(struct thread *t)
364{
365 int ret = pthread_join(t->id, NULL);
366
367 if (ret < 0)
368 err("%s: joining thread", t->filename);
369 else
370 debug("%s: joined\n", t->filename);
371}
372
373
374static ssize_t read_wrap(struct thread *t, void *buf, size_t nbytes)
375{
376 return read(t->fd, buf, nbytes);
377}
378
379static ssize_t write_wrap(struct thread *t, const void *buf, size_t nbytes)
380{
381 return write(t->fd, buf, nbytes);
382}
383
384
385/******************** Empty/Fill buffer routines ****************************/
386
387/* 0 -- stream of zeros, 1 -- i % 63, 2 -- pipe */
388enum pattern { PAT_ZERO, PAT_SEQ, PAT_PIPE };
389static enum pattern pattern;
390
391static ssize_t
392fill_in_buf(struct thread *ignore, void *buf, size_t nbytes)
393{
394 size_t i;
395 __u8 *p;
396
397 (void)ignore;
398
399 switch (pattern) {
400 case PAT_ZERO:
401 memset(buf, 0, nbytes);
402 break;
403
404 case PAT_SEQ:
405 for (p = buf, i = 0; i < nbytes; ++i, ++p)
406 *p = i % 63;
407 break;
408
409 case PAT_PIPE:
410 return fread(buf, 1, nbytes, stdin);
411 }
412
413 return nbytes;
414}
415
416static ssize_t
417empty_out_buf(struct thread *ignore, const void *buf, size_t nbytes)
418{
419 const __u8 *p;
420 __u8 expected;
421 ssize_t ret;
422 size_t len;
423
424 (void)ignore;
425
426 switch (pattern) {
427 case PAT_ZERO:
428 expected = 0;
429 for (p = buf, len = 0; len < nbytes; ++p, ++len)
430 if (*p)
431 goto invalid;
432 break;
433
434 case PAT_SEQ:
435 for (p = buf, len = 0; len < nbytes; ++p, ++len)
436 if (*p != len % 63) {
437 expected = len % 63;
438 goto invalid;
439 }
440 break;
441
442 case PAT_PIPE:
443 ret = fwrite(buf, nbytes, 1, stdout);
444 if (ret > 0)
445 fflush(stdout);
446 break;
447
448invalid:
449 err("bad OUT byte %zd, expected %02x got %02x\n",
450 len, expected, *p);
451 for (p = buf, len = 0; len < nbytes; ++p, ++len) {
452 if (0 == (len % 32))
453 fprintf(stderr, "%4d:", len);
454 fprintf(stderr, " %02x", *p);
455 if (31 == (len % 32))
456 fprintf(stderr, "\n");
457 }
458 fflush(stderr);
459 errno = EILSEQ;
460 return -1;
461 }
462
463 return len;
464}
465
466
467/******************** Endpoints routines ************************************/
468
469static void handle_setup(const struct usb_ctrlrequest *setup)
470{
471 printf("bRequestType = %d\n", setup->bRequestType);
472 printf("bRequest = %d\n", setup->bRequest);
473 printf("wValue = %d\n", le16_to_cpu(setup->wValue));
474 printf("wIndex = %d\n", le16_to_cpu(setup->wIndex));
475 printf("wLength = %d\n", le16_to_cpu(setup->wLength));
476}
477
478static ssize_t
479ep0_consume(struct thread *ignore, const void *buf, size_t nbytes)
480{
481 static const char *const names[] = {
482 [FUNCTIONFS_BIND] = "BIND",
483 [FUNCTIONFS_UNBIND] = "UNBIND",
484 [FUNCTIONFS_ENABLE] = "ENABLE",
485 [FUNCTIONFS_DISABLE] = "DISABLE",
486 [FUNCTIONFS_SETUP] = "SETUP",
487 [FUNCTIONFS_SUSPEND] = "SUSPEND",
488 [FUNCTIONFS_RESUME] = "RESUME",
489 };
490
491 const struct usb_functionfs_event *event = buf;
492 size_t n;
493
494 (void)ignore;
495
496 for (n = nbytes / sizeof *event; n; --n, ++event)
497 switch (event->type) {
498 case FUNCTIONFS_BIND:
499 case FUNCTIONFS_UNBIND:
500 case FUNCTIONFS_ENABLE:
501 case FUNCTIONFS_DISABLE:
502 case FUNCTIONFS_SETUP:
503 case FUNCTIONFS_SUSPEND:
504 case FUNCTIONFS_RESUME:
505 printf("Event %s\n", names[event->type]);
506 if (event->type == FUNCTIONFS_SETUP)
507 handle_setup(&event->u.setup);
508 break;
509
510 default:
511 printf("Event %03u (unknown)\n", event->type);
512 }
513
514 return nbytes;
515}
516
517static void ep0_init(struct thread *t)
518{
519 ssize_t ret;
520
521 info("%s: writing descriptors\n", t->filename);
522 ret = write(t->fd, &descriptors, sizeof descriptors);
523 die_on(ret < 0, "%s: write: descriptors", t->filename);
524
525 info("%s: writing strings\n", t->filename);
526 ret = write(t->fd, &strings, sizeof strings);
527 die_on(ret < 0, "%s: write: strings", t->filename);
528}
529
530
531/******************** Main **************************************************/
532
533int main(void)
534{
535 unsigned i;
536
537 /* XXX TODO: Argument parsing missing */
538
539 init_thread(threads);
540 ep0_init(threads);
541
542 for (i = 1; i < sizeof threads / sizeof *threads; ++i)
543 init_thread(threads + i);
544
545 for (i = 1; i < sizeof threads / sizeof *threads; ++i)
546 start_thread(threads + i);
547
548 start_thread_helper(threads);
549
550 for (i = 1; i < sizeof threads / sizeof *threads; ++i)
551 join_thread(threads + i);
552
553 return 0;
554}
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
new file mode 100644
index 000000000000..f08e89463842
--- /dev/null
+++ b/tools/usb/testusb.c
@@ -0,0 +1,547 @@
1/* $(CROSS_COMPILE)cc -Wall -Wextra -g -lpthread -o testusb testusb.c */
2
3/*
4 * Copyright (c) 2002 by David Brownell
5 * Copyright (c) 2010 by Samsung Electronics
6 * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23/*
24 * This program issues ioctls to perform the tests implemented by the
25 * kernel driver. It can generate a variety of transfer patterns; you
26 * should make sure to test both regular streaming and mixes of
27 * transfer sizes (including short transfers).
28 *
29 * For more information on how this can be used and on USB testing
30 * refer to <URL:http://www.linux-usb.org/usbtest/>.
31 */
32
33#include <stdio.h>
34#include <string.h>
35#include <ftw.h>
36#include <stdlib.h>
37#include <pthread.h>
38#include <unistd.h>
39#include <errno.h>
40#include <limits.h>
41
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <fcntl.h>
45
46#include <sys/ioctl.h>
47#include <linux/usbdevice_fs.h>
48
49/*-------------------------------------------------------------------------*/
50
51#define TEST_CASES 30
52
53// FIXME make these public somewhere; usbdevfs.h?
54
55struct usbtest_param {
56 // inputs
57 unsigned test_num; /* 0..(TEST_CASES-1) */
58 unsigned iterations;
59 unsigned length;
60 unsigned vary;
61 unsigned sglen;
62
63 // outputs
64 struct timeval duration;
65};
66#define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param)
67
68/*-------------------------------------------------------------------------*/
69
70/* #include <linux/usb_ch9.h> */
71
72#define USB_DT_DEVICE 0x01
73#define USB_DT_INTERFACE 0x04
74
75#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
76#define USB_CLASS_VENDOR_SPEC 0xff
77
78
79struct usb_device_descriptor {
80 __u8 bLength;
81 __u8 bDescriptorType;
82 __u16 bcdUSB;
83 __u8 bDeviceClass;
84 __u8 bDeviceSubClass;
85 __u8 bDeviceProtocol;
86 __u8 bMaxPacketSize0;
87 __u16 idVendor;
88 __u16 idProduct;
89 __u16 bcdDevice;
90 __u8 iManufacturer;
91 __u8 iProduct;
92 __u8 iSerialNumber;
93 __u8 bNumConfigurations;
94} __attribute__ ((packed));
95
96struct usb_interface_descriptor {
97 __u8 bLength;
98 __u8 bDescriptorType;
99
100 __u8 bInterfaceNumber;
101 __u8 bAlternateSetting;
102 __u8 bNumEndpoints;
103 __u8 bInterfaceClass;
104 __u8 bInterfaceSubClass;
105 __u8 bInterfaceProtocol;
106 __u8 iInterface;
107} __attribute__ ((packed));
108
109enum usb_device_speed {
110 USB_SPEED_UNKNOWN = 0, /* enumerating */
111 USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
112 USB_SPEED_HIGH /* usb 2.0 */
113};
114
115/*-------------------------------------------------------------------------*/
116
117static char *speed (enum usb_device_speed s)
118{
119 switch (s) {
120 case USB_SPEED_UNKNOWN: return "unknown";
121 case USB_SPEED_LOW: return "low";
122 case USB_SPEED_FULL: return "full";
123 case USB_SPEED_HIGH: return "high";
124 default: return "??";
125 }
126}
127
128struct testdev {
129 struct testdev *next;
130 char *name;
131 pthread_t thread;
132 enum usb_device_speed speed;
133 unsigned ifnum : 8;
134 unsigned forever : 1;
135 int test;
136
137 struct usbtest_param param;
138};
139static struct testdev *testdevs;
140
141static int testdev_ffs_ifnum(FILE *fd)
142{
143 union {
144 char buf[255];
145 struct usb_interface_descriptor intf;
146 } u;
147
148 for (;;) {
149 if (fread(u.buf, 1, 1, fd) != 1)
150 return -1;
151 if (fread(u.buf + 1, (unsigned char)u.buf[0] - 1, 1, fd) != 1)
152 return -1;
153
154 if (u.intf.bLength == sizeof u.intf
155 && u.intf.bDescriptorType == USB_DT_INTERFACE
156 && u.intf.bNumEndpoints == 2
157 && u.intf.bInterfaceClass == USB_CLASS_VENDOR_SPEC
158 && u.intf.bInterfaceSubClass == 0
159 && u.intf.bInterfaceProtocol == 0)
160 return (unsigned char)u.intf.bInterfaceNumber;
161 }
162}
163
164static int testdev_ifnum(FILE *fd)
165{
166 struct usb_device_descriptor dev;
167
168 if (fread(&dev, sizeof dev, 1, fd) != 1)
169 return -1;
170
171 if (dev.bLength != sizeof dev || dev.bDescriptorType != USB_DT_DEVICE)
172 return -1;
173
174 /* FX2 with (tweaked) bulksrc firmware */
175 if (dev.idVendor == 0x0547 && dev.idProduct == 0x1002)
176 return 0;
177
178 /*----------------------------------------------------*/
179
180 /* devices that start up using the EZ-USB default device and
181 * which we can use after loading simple firmware. hotplug
182 * can fxload it, and then run this test driver.
183 *
184 * we return false positives in two cases:
185 * - the device has a "real" driver (maybe usb-serial) that
186 * renumerates. the device should vanish quickly.
187 * - the device doesn't have the test firmware installed.
188 */
189
190 /* generic EZ-USB FX controller */
191 if (dev.idVendor == 0x0547 && dev.idProduct == 0x2235)
192 return 0;
193
194 /* generic EZ-USB FX2 controller */
195 if (dev.idVendor == 0x04b4 && dev.idProduct == 0x8613)
196 return 0;
197
198 /* CY3671 development board with EZ-USB FX */
199 if (dev.idVendor == 0x0547 && dev.idProduct == 0x0080)
200 return 0;
201
202 /* Keyspan 19Qi uses an21xx (original EZ-USB) */
203 if (dev.idVendor == 0x06cd && dev.idProduct == 0x010b)
204 return 0;
205
206 /*----------------------------------------------------*/
207
208 /* "gadget zero", Linux-USB test software */
209 if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a0)
210 return 0;
211
212 /* user mode subset of that */
213 if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a4)
214 return testdev_ffs_ifnum(fd);
215 /* return 0; */
216
217 /* iso version of usermode code */
218 if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4a3)
219 return 0;
220
221 /* some GPL'd test firmware uses these IDs */
222
223 if (dev.idVendor == 0xfff0 && dev.idProduct == 0xfff0)
224 return 0;
225
226 /*----------------------------------------------------*/
227
228 /* iBOT2 high speed webcam */
229 if (dev.idVendor == 0x0b62 && dev.idProduct == 0x0059)
230 return 0;
231
232 /*----------------------------------------------------*/
233
234 /* the FunctionFS gadget can have the source/sink interface
235 * anywhere. We look for an interface descriptor that match
236 * what we expect. We ignore configuratiens thou. */
237
238 if (dev.idVendor == 0x0525 && dev.idProduct == 0xa4ac
239 && (dev.bDeviceClass == USB_CLASS_PER_INTERFACE
240 || dev.bDeviceClass == USB_CLASS_VENDOR_SPEC))
241 return testdev_ffs_ifnum(fd);
242
243 return -1;
244}
245
246static int find_testdev(const char *name, const struct stat *sb, int flag)
247{
248 FILE *fd;
249 int ifnum;
250 struct testdev *entry;
251
252 (void)sb; /* unused */
253
254 if (flag != FTW_F)
255 return 0;
256 /* ignore /proc/bus/usb/{devices,drivers} */
257 if (strrchr(name, '/')[1] == 'd')
258 return 0;
259
260 fd = fopen(name, "rb");
261 if (!fd) {
262 perror(name);
263 return 0;
264 }
265
266 ifnum = testdev_ifnum(fd);
267 fclose(fd);
268 if (ifnum < 0)
269 return 0;
270
271 entry = calloc(1, sizeof *entry);
272 if (!entry)
273 goto nomem;
274
275 entry->name = strdup(name);
276 if (!entry->name) {
277 free(entry);
278nomem:
279 perror("malloc");
280 return 0;
281 }
282
283 entry->ifnum = ifnum;
284
285 /* FIXME ask usbfs what speed; update USBDEVFS_CONNECTINFO so
286 * it tells about high speed etc */
287
288 fprintf(stderr, "%s speed\t%s\t%u\n",
289 speed(entry->speed), entry->name, entry->ifnum);
290
291 entry->next = testdevs;
292 testdevs = entry;
293 return 0;
294}
295
296static int
297usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
298{
299 struct usbdevfs_ioctl wrapper;
300
301 wrapper.ifno = ifno;
302 wrapper.ioctl_code = request;
303 wrapper.data = param;
304
305 return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
306}
307
308static void *handle_testdev (void *arg)
309{
310 struct testdev *dev = arg;
311 int fd, i;
312 int status;
313
314 if ((fd = open (dev->name, O_RDWR)) < 0) {
315 perror ("can't open dev file r/w");
316 return 0;
317 }
318
319restart:
320 for (i = 0; i < TEST_CASES; i++) {
321 if (dev->test != -1 && dev->test != i)
322 continue;
323 dev->param.test_num = i;
324
325 status = usbdev_ioctl (fd, dev->ifnum,
326 USBTEST_REQUEST, &dev->param);
327 if (status < 0 && errno == EOPNOTSUPP)
328 continue;
329
330 /* FIXME need a "syslog it" option for background testing */
331
332 /* NOTE: each thread emits complete lines; no fragments! */
333 if (status < 0) {
334 char buf [80];
335 int err = errno;
336
337 if (strerror_r (errno, buf, sizeof buf)) {
338 snprintf (buf, sizeof buf, "error %d", err);
339 errno = err;
340 }
341 printf ("%s test %d --> %d (%s)\n",
342 dev->name, i, errno, buf);
343 } else
344 printf ("%s test %d, %4d.%.06d secs\n", dev->name, i,
345 (int) dev->param.duration.tv_sec,
346 (int) dev->param.duration.tv_usec);
347
348 fflush (stdout);
349 }
350 if (dev->forever)
351 goto restart;
352
353 close (fd);
354 return arg;
355}
356
357static const char *usbfs_dir_find(void)
358{
359 static char usbfs_path_0[] = "/dev/usb/devices";
360 static char usbfs_path_1[] = "/proc/bus/usb/devices";
361
362 static char *const usbfs_paths[] = {
363 usbfs_path_0, usbfs_path_1
364 };
365
366 static char *const *
367 end = usbfs_paths + sizeof usbfs_paths / sizeof *usbfs_paths;
368
369 char *const *it = usbfs_paths;
370 do {
371 int fd = open(*it, O_RDONLY);
372 close(fd);
373 if (fd >= 0) {
374 strrchr(*it, '/')[0] = '\0';
375 return *it;
376 }
377 } while (++it != end);
378
379 return NULL;
380}
381
382static int parse_num(unsigned *num, const char *str)
383{
384 unsigned long val;
385 char *end;
386
387 errno = 0;
388 val = strtoul(str, &end, 0);
389 if (errno || *end || val > UINT_MAX)
390 return -1;
391 *num = val;
392 return 0;
393}
394
395int main (int argc, char **argv)
396{
397
398 int c;
399 struct testdev *entry;
400 char *device;
401 const char *usbfs_dir = NULL;
402 int all = 0, forever = 0, not = 0;
403 int test = -1 /* all */;
404 struct usbtest_param param;
405
406 /* pick defaults that works with all speeds, without short packets.
407 *
408 * Best per-frame data rates:
409 * high speed, bulk 512 * 13 * 8 = 53248
410 * interrupt 1024 * 3 * 8 = 24576
411 * full speed, bulk/intr 64 * 19 = 1216
412 * interrupt 64 * 1 = 64
413 * low speed, interrupt 8 * 1 = 8
414 */
415 param.iterations = 1000;
416 param.length = 512;
417 param.vary = 512;
418 param.sglen = 32;
419
420 /* for easy use when hotplugging */
421 device = getenv ("DEVICE");
422
423 while ((c = getopt (argc, argv, "D:aA:c:g:hns:t:v:")) != EOF)
424 switch (c) {
425 case 'D': /* device, if only one */
426 device = optarg;
427 continue;
428 case 'A': /* use all devices with specified usbfs dir */
429 usbfs_dir = optarg;
430 /* FALL THROUGH */
431 case 'a': /* use all devices */
432 device = NULL;
433 all = 1;
434 continue;
435 case 'c': /* count iterations */
436 if (parse_num(&param.iterations, optarg))
437 goto usage;
438 continue;
439 case 'g': /* scatter/gather entries */
440 if (parse_num(&param.sglen, optarg))
441 goto usage;
442 continue;
443 case 'l': /* loop forever */
444 forever = 1;
445 continue;
446 case 'n': /* no test running! */
447 not = 1;
448 continue;
449 case 's': /* size of packet */
450 if (parse_num(&param.length, optarg))
451 goto usage;
452 continue;
453 case 't': /* run just one test */
454 test = atoi (optarg);
455 if (test < 0)
456 goto usage;
457 continue;
458 case 'v': /* vary packet size by ... */
459 if (parse_num(&param.vary, optarg))
460 goto usage;
461 continue;
462 case '?':
463 case 'h':
464 default:
465usage:
466 fprintf (stderr, "usage: %s [-n] [-D dev | -a | -A usbfs-dir]\n"
467 "\t[-c iterations] [-t testnum]\n"
468 "\t[-s packetsize] [-g sglen] [-v vary]\n",
469 argv [0]);
470 return 1;
471 }
472 if (optind != argc)
473 goto usage;
474 if (!all && !device) {
475 fprintf (stderr, "must specify '-a' or '-D dev', "
476 "or DEVICE=/proc/bus/usb/BBB/DDD in env\n");
477 goto usage;
478 }
479
480 /* Find usbfs mount point */
481 if (!usbfs_dir) {
482 usbfs_dir = usbfs_dir_find();
483 if (!usbfs_dir) {
484 fputs ("usbfs files are missing\n", stderr);
485 return -1;
486 }
487 }
488
489 /* collect and list the test devices */
490 if (ftw (usbfs_dir, find_testdev, 3) != 0) {
491 fputs ("ftw failed; is usbfs missing?\n", stderr);
492 return -1;
493 }
494
495 /* quit, run single test, or create test threads */
496 if (!testdevs && !device) {
497 fputs ("no test devices recognized\n", stderr);
498 return -1;
499 }
500 if (not)
501 return 0;
502 if (testdevs && testdevs->next == 0 && !device)
503 device = testdevs->name;
504 for (entry = testdevs; entry; entry = entry->next) {
505 int status;
506
507 entry->param = param;
508 entry->forever = forever;
509 entry->test = test;
510
511 if (device) {
512 if (strcmp (entry->name, device))
513 continue;
514 return handle_testdev (entry) != entry;
515 }
516 status = pthread_create (&entry->thread, 0, handle_testdev, entry);
517 if (status) {
518 perror ("pthread_create");
519 continue;
520 }
521 }
522 if (device) {
523 struct testdev dev;
524
525 /* kernel can recognize test devices we don't */
526 fprintf (stderr, "%s: %s may see only control tests\n",
527 argv [0], device);
528
529 memset (&dev, 0, sizeof dev);
530 dev.name = device;
531 dev.param = param;
532 dev.forever = forever;
533 dev.test = test;
534 return handle_testdev (&dev) != &dev;
535 }
536
537 /* wait for tests to complete */
538 for (entry = testdevs; entry; entry = entry->next) {
539 void *retval;
540
541 if (pthread_join (entry->thread, &retval))
542 perror ("pthread_join");
543 /* testing errors discarded! */
544 }
545
546 return 0;
547}
diff --git a/tools/virtio/Makefile b/tools/virtio/Makefile
new file mode 100644
index 000000000000..d1d442ed106a
--- /dev/null
+++ b/tools/virtio/Makefile
@@ -0,0 +1,12 @@
1all: test mod
2test: virtio_test
3virtio_test: virtio_ring.o virtio_test.o
4CFLAGS += -g -O2 -Wall -I. -I ../../usr/include/ -Wno-pointer-sign -fno-strict-overflow -MMD
5vpath %.c ../../drivers/virtio
6mod:
7 ${MAKE} -C `pwd`/../.. M=`pwd`/vhost_test
8.PHONY: all test mod clean
9clean:
10 ${RM} *.o vhost_test/*.o vhost_test/.*.cmd \
11 vhost_test/Module.symvers vhost_test/modules.order *.d
12-include *.d
diff --git a/tools/virtio/linux/device.h b/tools/virtio/linux/device.h
new file mode 100644
index 000000000000..4ad7e1df0db5
--- /dev/null
+++ b/tools/virtio/linux/device.h
@@ -0,0 +1,2 @@
1#ifndef LINUX_DEVICE_H
2#endif
diff --git a/tools/virtio/linux/slab.h b/tools/virtio/linux/slab.h
new file mode 100644
index 000000000000..81baeac8ae40
--- /dev/null
+++ b/tools/virtio/linux/slab.h
@@ -0,0 +1,2 @@
1#ifndef LINUX_SLAB_H
2#endif
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
new file mode 100644
index 000000000000..669bcdd45805
--- /dev/null
+++ b/tools/virtio/linux/virtio.h
@@ -0,0 +1,223 @@
1#ifndef LINUX_VIRTIO_H
2#define LINUX_VIRTIO_H
3
4#include <stdbool.h>
5#include <stdlib.h>
6#include <stddef.h>
7#include <stdio.h>
8#include <string.h>
9#include <assert.h>
10
11#include <linux/types.h>
12#include <errno.h>
13
14typedef unsigned long long dma_addr_t;
15
16struct scatterlist {
17 unsigned long page_link;
18 unsigned int offset;
19 unsigned int length;
20 dma_addr_t dma_address;
21};
22
23struct page {
24 unsigned long long dummy;
25};
26
27#define BUG_ON(__BUG_ON_cond) assert(!(__BUG_ON_cond))
28
29/* Physical == Virtual */
30#define virt_to_phys(p) ((unsigned long)p)
31#define phys_to_virt(a) ((void *)(unsigned long)(a))
32/* Page address: Virtual / 4K */
33#define virt_to_page(p) ((struct page*)((virt_to_phys(p) / 4096) * \
34 sizeof(struct page)))
35#define offset_in_page(p) (((unsigned long)p) % 4096)
36#define sg_phys(sg) ((sg->page_link & ~0x3) / sizeof(struct page) * 4096 + \
37 sg->offset)
38static inline void sg_mark_end(struct scatterlist *sg)
39{
40 /*
41 * Set termination bit, clear potential chain bit
42 */
43 sg->page_link |= 0x02;
44 sg->page_link &= ~0x01;
45}
46static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
47{
48 memset(sgl, 0, sizeof(*sgl) * nents);
49 sg_mark_end(&sgl[nents - 1]);
50}
51static inline void sg_assign_page(struct scatterlist *sg, struct page *page)
52{
53 unsigned long page_link = sg->page_link & 0x3;
54
55 /*
56 * In order for the low bit stealing approach to work, pages
57 * must be aligned at a 32-bit boundary as a minimum.
58 */
59 BUG_ON((unsigned long) page & 0x03);
60 sg->page_link = page_link | (unsigned long) page;
61}
62
63static inline void sg_set_page(struct scatterlist *sg, struct page *page,
64 unsigned int len, unsigned int offset)
65{
66 sg_assign_page(sg, page);
67 sg->offset = offset;
68 sg->length = len;
69}
70
71static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
72 unsigned int buflen)
73{
74 sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf));
75}
76
77static inline void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
78{
79 sg_init_table(sg, 1);
80 sg_set_buf(sg, buf, buflen);
81}
82
83typedef __u16 u16;
84
85typedef enum {
86 GFP_KERNEL,
87 GFP_ATOMIC,
88} gfp_t;
89typedef enum {
90 IRQ_NONE,
91 IRQ_HANDLED
92} irqreturn_t;
93
94static inline void *kmalloc(size_t s, gfp_t gfp)
95{
96 return malloc(s);
97}
98
99static inline void kfree(void *p)
100{
101 free(p);
102}
103
104#define container_of(ptr, type, member) ({ \
105 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
106 (type *)( (char *)__mptr - offsetof(type,member) );})
107
108#define uninitialized_var(x) x = x
109
110# ifndef likely
111# define likely(x) (__builtin_expect(!!(x), 1))
112# endif
113# ifndef unlikely
114# define unlikely(x) (__builtin_expect(!!(x), 0))
115# endif
116
117#define pr_err(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
118#ifdef DEBUG
119#define pr_debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
120#else
121#define pr_debug(format, ...) do {} while (0)
122#endif
123#define dev_err(dev, format, ...) fprintf (stderr, format, ## __VA_ARGS__)
124#define dev_warn(dev, format, ...) fprintf (stderr, format, ## __VA_ARGS__)
125
126/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
127#define list_add_tail(a, b) do {} while (0)
128#define list_del(a) do {} while (0)
129
130#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
131#define BITS_PER_BYTE 8
132#define BITS_PER_LONG (sizeof(long) * BITS_PER_BYTE)
133#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
134/* TODO: Not atomic as it should be:
135 * we don't use this for anything important. */
136static inline void clear_bit(int nr, volatile unsigned long *addr)
137{
138 unsigned long mask = BIT_MASK(nr);
139 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
140
141 *p &= ~mask;
142}
143
144static inline int test_bit(int nr, const volatile unsigned long *addr)
145{
146 return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
147}
148
149/* The only feature we care to support */
150#define virtio_has_feature(dev, feature) \
151 test_bit((feature), (dev)->features)
152/* end of stubs */
153
154struct virtio_device {
155 void *dev;
156 unsigned long features[1];
157};
158
159struct virtqueue {
160 /* TODO: commented as list macros are empty stubs for now.
161 * Broken but enough for virtio_ring.c
162 * struct list_head list; */
163 void (*callback)(struct virtqueue *vq);
164 const char *name;
165 struct virtio_device *vdev;
166 void *priv;
167};
168
169#define EXPORT_SYMBOL_GPL(__EXPORT_SYMBOL_GPL_name) \
170 void __EXPORT_SYMBOL_GPL##__EXPORT_SYMBOL_GPL_name() { \
171}
172#define MODULE_LICENSE(__MODULE_LICENSE_value) \
173 const char *__MODULE_LICENSE_name = __MODULE_LICENSE_value
174
175#define CONFIG_SMP
176
177#if defined(__i386__) || defined(__x86_64__)
178#define barrier() asm volatile("" ::: "memory")
179#define mb() __sync_synchronize()
180
181#define smp_mb() mb()
182# define smp_rmb() barrier()
183# define smp_wmb() barrier()
184#else
185#error Please fill in barrier macros
186#endif
187
188/* Interfaces exported by virtio_ring. */
189int virtqueue_add_buf_gfp(struct virtqueue *vq,
190 struct scatterlist sg[],
191 unsigned int out_num,
192 unsigned int in_num,
193 void *data,
194 gfp_t gfp);
195
196static inline int virtqueue_add_buf(struct virtqueue *vq,
197 struct scatterlist sg[],
198 unsigned int out_num,
199 unsigned int in_num,
200 void *data)
201{
202 return virtqueue_add_buf_gfp(vq, sg, out_num, in_num, data, GFP_ATOMIC);
203}
204
205void virtqueue_kick(struct virtqueue *vq);
206
207void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
208
209void virtqueue_disable_cb(struct virtqueue *vq);
210
211bool virtqueue_enable_cb(struct virtqueue *vq);
212
213void *virtqueue_detach_unused_buf(struct virtqueue *vq);
214struct virtqueue *vring_new_virtqueue(unsigned int num,
215 unsigned int vring_align,
216 struct virtio_device *vdev,
217 void *pages,
218 void (*notify)(struct virtqueue *vq),
219 void (*callback)(struct virtqueue *vq),
220 const char *name);
221void vring_del_virtqueue(struct virtqueue *vq);
222
223#endif
diff --git a/tools/virtio/vhost_test/Makefile b/tools/virtio/vhost_test/Makefile
new file mode 100644
index 000000000000..a1d35b81b314
--- /dev/null
+++ b/tools/virtio/vhost_test/Makefile
@@ -0,0 +1,2 @@
1obj-m += vhost_test.o
2EXTRA_CFLAGS += -Idrivers/vhost
diff --git a/tools/virtio/vhost_test/vhost_test.c b/tools/virtio/vhost_test/vhost_test.c
new file mode 100644
index 000000000000..18735189e62b
--- /dev/null
+++ b/tools/virtio/vhost_test/vhost_test.c
@@ -0,0 +1 @@
#include "test.c"
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
new file mode 100644
index 000000000000..df0c6d2c3860
--- /dev/null
+++ b/tools/virtio/virtio_test.c
@@ -0,0 +1,248 @@
1#define _GNU_SOURCE
2#include <getopt.h>
3#include <string.h>
4#include <poll.h>
5#include <sys/eventfd.h>
6#include <stdlib.h>
7#include <assert.h>
8#include <unistd.h>
9#include <sys/ioctl.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <fcntl.h>
13#include <linux/vhost.h>
14#include <linux/virtio.h>
15#include <linux/virtio_ring.h>
16#include "../../drivers/vhost/test.h"
17
18struct vq_info {
19 int kick;
20 int call;
21 int num;
22 int idx;
23 void *ring;
24 /* copy used for control */
25 struct vring vring;
26 struct virtqueue *vq;
27};
28
29struct vdev_info {
30 struct virtio_device vdev;
31 int control;
32 struct pollfd fds[1];
33 struct vq_info vqs[1];
34 int nvqs;
35 void *buf;
36 size_t buf_size;
37 struct vhost_memory *mem;
38};
39
40void vq_notify(struct virtqueue *vq)
41{
42 struct vq_info *info = vq->priv;
43 unsigned long long v = 1;
44 int r;
45 r = write(info->kick, &v, sizeof v);
46 assert(r == sizeof v);
47}
48
49void vq_callback(struct virtqueue *vq)
50{
51}
52
53
54void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info)
55{
56 struct vhost_vring_state state = { .index = info->idx };
57 struct vhost_vring_file file = { .index = info->idx };
58 unsigned long long features = dev->vdev.features[0];
59 struct vhost_vring_addr addr = {
60 .index = info->idx,
61 .desc_user_addr = (uint64_t)(unsigned long)info->vring.desc,
62 .avail_user_addr = (uint64_t)(unsigned long)info->vring.avail,
63 .used_user_addr = (uint64_t)(unsigned long)info->vring.used,
64 };
65 int r;
66 r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
67 assert(r >= 0);
68 state.num = info->vring.num;
69 r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
70 assert(r >= 0);
71 state.num = 0;
72 r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
73 assert(r >= 0);
74 r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
75 assert(r >= 0);
76 file.fd = info->kick;
77 r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
78 assert(r >= 0);
79 file.fd = info->call;
80 r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
81 assert(r >= 0);
82}
83
84static void vq_info_add(struct vdev_info *dev, int num)
85{
86 struct vq_info *info = &dev->vqs[dev->nvqs];
87 int r;
88 info->idx = dev->nvqs;
89 info->kick = eventfd(0, EFD_NONBLOCK);
90 info->call = eventfd(0, EFD_NONBLOCK);
91 r = posix_memalign(&info->ring, 4096, vring_size(num, 4096));
92 assert(r >= 0);
93 memset(info->ring, 0, vring_size(num, 4096));
94 vring_init(&info->vring, num, info->ring, 4096);
95 info->vq = vring_new_virtqueue(info->vring.num, 4096, &dev->vdev, info->ring,
96 vq_notify, vq_callback, "test");
97 assert(info->vq);
98 info->vq->priv = info;
99 vhost_vq_setup(dev, info);
100 dev->fds[info->idx].fd = info->call;
101 dev->fds[info->idx].events = POLLIN;
102 dev->nvqs++;
103}
104
105static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
106{
107 int r;
108 memset(dev, 0, sizeof *dev);
109 dev->vdev.features[0] = features;
110 dev->vdev.features[1] = features >> 32;
111 dev->buf_size = 1024;
112 dev->buf = malloc(dev->buf_size);
113 assert(dev->buf);
114 dev->control = open("/dev/vhost-test", O_RDWR);
115 assert(dev->control >= 0);
116 r = ioctl(dev->control, VHOST_SET_OWNER, NULL);
117 assert(r >= 0);
118 dev->mem = malloc(offsetof(struct vhost_memory, regions) +
119 sizeof dev->mem->regions[0]);
120 assert(dev->mem);
121 memset(dev->mem, 0, offsetof(struct vhost_memory, regions) +
122 sizeof dev->mem->regions[0]);
123 dev->mem->nregions = 1;
124 dev->mem->regions[0].guest_phys_addr = (long)dev->buf;
125 dev->mem->regions[0].userspace_addr = (long)dev->buf;
126 dev->mem->regions[0].memory_size = dev->buf_size;
127 r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
128 assert(r >= 0);
129}
130
131/* TODO: this is pretty bad: we get a cache line bounce
132 * for the wait queue on poll and another one on read,
133 * plus the read which is there just to clear the
134 * current state. */
135static void wait_for_interrupt(struct vdev_info *dev)
136{
137 int i;
138 unsigned long long val;
139 poll(dev->fds, dev->nvqs, -1);
140 for (i = 0; i < dev->nvqs; ++i)
141 if (dev->fds[i].revents & POLLIN) {
142 read(dev->fds[i].fd, &val, sizeof val);
143 }
144}
145
146static void run_test(struct vdev_info *dev, struct vq_info *vq, int bufs)
147{
148 struct scatterlist sl;
149 long started = 0, completed = 0;
150 long completed_before;
151 int r, test = 1;
152 unsigned len;
153 long long spurious = 0;
154 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
155 assert(r >= 0);
156 for (;;) {
157 virtqueue_disable_cb(vq->vq);
158 completed_before = completed;
159 do {
160 if (started < bufs) {
161 sg_init_one(&sl, dev->buf, dev->buf_size);
162 r = virtqueue_add_buf(vq->vq, &sl, 1, 0,
163 dev->buf + started);
164 if (likely(r >= 0)) {
165 ++started;
166 virtqueue_kick(vq->vq);
167 }
168 } else
169 r = -1;
170
171 /* Flush out completed bufs if any */
172 if (virtqueue_get_buf(vq->vq, &len)) {
173 ++completed;
174 r = 0;
175 }
176
177 } while (r >= 0);
178 if (completed == completed_before)
179 ++spurious;
180 assert(completed <= bufs);
181 assert(started <= bufs);
182 if (completed == bufs)
183 break;
184 if (virtqueue_enable_cb(vq->vq)) {
185 wait_for_interrupt(dev);
186 }
187 }
188 test = 0;
189 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
190 assert(r >= 0);
191 fprintf(stderr, "spurious wakeus: 0x%llx\n", spurious);
192}
193
194const char optstring[] = "h";
195const struct option longopts[] = {
196 {
197 .name = "help",
198 .val = 'h',
199 },
200 {
201 .name = "indirect",
202 .val = 'I',
203 },
204 {
205 .name = "no-indirect",
206 .val = 'i',
207 },
208 {
209 }
210};
211
212static void help()
213{
214 fprintf(stderr, "Usage: virtio_test [--help] [--no-indirect]\n");
215}
216
217int main(int argc, char **argv)
218{
219 struct vdev_info dev;
220 unsigned long long features = 1ULL << VIRTIO_RING_F_INDIRECT_DESC;
221 int o;
222
223 for (;;) {
224 o = getopt_long(argc, argv, optstring, longopts, NULL);
225 switch (o) {
226 case -1:
227 goto done;
228 case '?':
229 help();
230 exit(2);
231 case 'h':
232 help();
233 goto done;
234 case 'i':
235 features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
236 break;
237 default:
238 assert(0);
239 break;
240 }
241 }
242
243done:
244 vdev_info_init(&dev, features);
245 vq_info_add(&dev, 256);
246 run_test(&dev, &dev.vqs[0], 0x100000);
247 return 0;
248}