aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMichal Marek <mmarek@suse.cz>2010-10-27 18:15:57 -0400
committerMichal Marek <mmarek@suse.cz>2010-10-27 18:15:57 -0400
commitb74b953b998bcc2db91b694446f3a2619ec32de6 (patch)
tree6ce24caabd730f6ae9287ed0676ec32e6ff31e9d /tools
parentabb438526201c6a79949ad45375c051b6681c253 (diff)
parentf6f94e2ab1b33f0082ac22d71f66385a60d8157f (diff)
Merge commit 'v2.6.36' into kbuild/misc
Update to be able to fix a recent change to scripts/basic/docproc.c (commit eda603f).
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.txt2
-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-diff.txt2
-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.txt68
-rw-r--r--tools/perf/Documentation/perf-list.txt33
-rw-r--r--tools/perf/Documentation/perf-lock.txt29
-rw-r--r--tools/perf/Documentation/perf-probe.txt99
-rw-r--r--tools/perf/Documentation/perf-record.txt21
-rw-r--r--tools/perf/Documentation/perf-sched.txt4
-rw-r--r--tools/perf/Documentation/perf-stat.txt14
-rw-r--r--tools/perf/Documentation/perf-test.txt22
-rw-r--r--tools/perf/Documentation/perf-top.txt10
-rw-r--r--tools/perf/Documentation/perf-trace-perl.txt8
-rw-r--r--tools/perf/Documentation/perf-trace-python.txt623
-rw-r--r--tools/perf/Documentation/perf-trace.txt17
-rw-r--r--tools/perf/Documentation/perf.txt2
-rw-r--r--tools/perf/MANIFEST12
-rw-r--r--tools/perf/Makefile537
-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/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.c3
-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.c352
-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.c37
-rw-r--r--tools/perf/builtin-diff.c130
-rw-r--r--tools/perf/builtin-help.c13
-rw-r--r--tools/perf/builtin-inject.c228
-rw-r--r--tools/perf/builtin-kmem.c64
-rw-r--r--tools/perf/builtin-kvm.c144
-rw-r--r--tools/perf/builtin-lock.c1005
-rw-r--r--tools/perf/builtin-probe.c280
-rw-r--r--tools/perf/builtin-record.c662
-rw-r--r--tools/perf/builtin-report.c356
-rw-r--r--tools/perf/builtin-sched.c66
-rw-r--r--tools/perf/builtin-stat.c283
-rw-r--r--tools/perf/builtin-test.c281
-rw-r--r--tools/perf/builtin-timechart.c151
-rw-r--r--tools/perf/builtin-top.c451
-rw-r--r--tools/perf/builtin-trace.c166
-rw-r--r--tools/perf/builtin.h5
-rw-r--r--tools/perf/command-list.txt6
-rw-r--r--tools/perf/design.txt8
-rw-r--r--tools/perf/feature-tests.mak119
-rw-r--r--tools/perf/perf-archive.sh46
-rw-r--r--tools/perf/perf.c58
-rw-r--r--tools/perf/perf.h25
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.c5
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/Context.xs3
-rw-r--r--tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm8
-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-report8
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-record2
-rw-r--r--tools/perf/scripts/perl/bin/rw-by-pid-report2
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-record2
-rw-r--r--tools/perf/scripts/perl/bin/rwtop-report23
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-record2
-rw-r--r--tools/perf/scripts/perl/bin/wakeup-latency-report2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-record2
-rw-r--r--tools/perf/scripts/perl/bin/workqueue-stats-report2
-rw-r--r--tools/perf/scripts/perl/failed-syscalls.pl42
-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.pl12
-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.py28
-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/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.py68
-rw-r--r--tools/perf/scripts/python/sched-migration.py461
-rw-r--r--tools/perf/scripts/python/sctop.py78
-rw-r--r--tools/perf/scripts/python/syscall-counts-by-pid.py64
-rw-r--r--tools/perf/scripts/python/syscall-counts.py58
-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.c77
-rw-r--r--tools/perf/util/build-id.h10
-rw-r--r--tools/perf/util/cache.h68
-rw-r--r--tools/perf/util/callchain.c131
-rw-r--r--tools/perf/util/callchain.h15
-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.c114
-rw-r--r--tools/perf/util/cpumap.h7
-rw-r--r--tools/perf/util/data_map.c252
-rw-r--r--tools/perf/util/debug.c19
-rw-r--r--tools/perf/util/debug.h29
-rw-r--r--tools/perf/util/debugfs.c17
-rw-r--r--tools/perf/util/debugfs.h2
-rw-r--r--tools/perf/util/event.c554
-rw-r--r--tools/perf/util/event.h136
-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.c752
-rw-r--r--tools/perf/util/header.h46
-rw-r--r--tools/perf/util/help.c30
-rw-r--r--tools/perf/util/hist.c752
-rw-r--r--tools/perf/util/hist.h141
-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/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.h20
-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/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.h227
-rw-r--r--tools/perf/util/parse-events.c101
-rw-r--r--tools/perf/util/parse-events.h1
-rw-r--r--tools/perf/util/parse-options.c55
-rw-r--r--tools/perf/util/parse-options.h29
-rw-r--r--tools/perf/util/path.c204
-rw-r--r--tools/perf/util/probe-event.c1670
-rw-r--r--tools/perf/util/probe-event.h123
-rw-r--r--tools/perf/util/probe-finder.c1777
-rw-r--r--tools/perf/util/probe-finder.h81
-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)118
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c594
-rw-r--r--tools/perf/util/session.c833
-rw-r--r--tools/perf/util/session.h130
-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.c141
-rw-r--r--tools/perf/util/string.h17
-rw-r--r--tools/perf/util/symbol.c1358
-rw-r--r--tools/perf/util/symbol.h124
-rw-r--r--tools/perf/util/thread.c235
-rw-r--r--tools/perf/util/thread.h53
-rw-r--r--tools/perf/util/trace-event-info.c99
-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.h25
-rw-r--r--tools/perf/util/ui/browser.c329
-rw-r--r--tools/perf/util/ui/browser.h46
-rw-r--r--tools/perf/util/ui/browsers/annotate.c241
-rw-r--r--tools/perf/util/ui/browsers/hists.c948
-rw-r--r--tools/perf/util/ui/browsers/map.c161
-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.c114
-rw-r--r--tools/perf/util/ui/util.h10
-rw-r--r--tools/perf/util/util.c116
-rw-r--r--tools/perf/util/util.h193
-rw-r--r--tools/perf/util/values.c1
-rw-r--r--tools/perf/util/wrapper.c110
-rw-r--r--tools/usb/ffs-test.c554
-rw-r--r--tools/usb/testusb.c547
207 files changed, 21700 insertions, 6396 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..5164a655c39f 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----
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-diff.txt b/tools/perf/Documentation/perf-diff.txt
index 8974e208cba6..20d97d84ea1c 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----
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..d004e19fe6d6
--- /dev/null
+++ b/tools/perf/Documentation/perf-kvm.txt
@@ -0,0 +1,68 @@
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 couinter 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--host=::
44 Collect host side performance profile.
45--guest=::
46 Collect guest side performance profile.
47--guestmount=<path>::
48 Guest os root file system mount directory. Users mounts guest os
49 root directories under <path> by a specific filesystem access method,
50 typically, sshfs. For example, start 2 guest os. The one's pid is 8888
51 and the other's is 9999.
52 #mkdir ~/guestmount; cd ~/guestmount
53 #sshfs -o allow_other,direct_io -p 5551 localhost:/ 8888/
54 #sshfs -o allow_other,direct_io -p 5552 localhost:/ 9999/
55 #perf kvm --host --guest --guestmount=~/guestmount top
56--guestkallsyms=<path>::
57 Guest os /proc/kallsyms file copy. 'perf' kvm' reads it to get guest
58 kernel symbols. Users copy it out from guest os.
59--guestmodules=<path>::
60 Guest os /proc/modules file copy. 'perf' kvm' reads it to get guest
61 kernel module information. Users copy it out from guest os.
62--guestvmlinux=<path>::
63 Guest os kernel vmlinux.
64
65SEE ALSO
66--------
67linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1],
68linkperf: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..43e3dd284b90 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -15,6 +15,35 @@ 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
18RAW HARDWARE EVENT DESCRIPTOR
19-----------------------------
20Even when an event is not available in a symbolic form within perf right now,
21it can be encoded in a per processor specific way.
22
23For instance For x86 CPUs NNN represents the raw register encoding with the
24layout of IA32_PERFEVTSELx MSRs (see [Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide] Figure 30-1 Layout
25of IA32_PERFEVTSELx MSRs) or AMD's PerfEvtSeln (see [AMD64 Architecture Programmer’s Manual Volume 2: System Programming], Page 344,
26Figure 13-7 Performance Event-Select Register (PerfEvtSeln)).
27
28Example:
29
30If the Intel docs for a QM720 Core i7 describe an event as:
31
32 Event Umask Event Mask
33 Num. Value Mnemonic Description Comment
34
35 A8H 01H LSD.UOPS Counts the number of micro-ops Use cmask=1 and
36 delivered by loop stream detector invert to count
37 cycles
38
39raw encoding of 0x1A8 can be used:
40
41 perf stat -e r1a8 -a sleep 1
42 perf record -e r1a8 ...
43
44You should refer to the processor specific documentation for getting these
45details. Some of them are referenced in the SEE ALSO section below.
46
18OPTIONS 47OPTIONS
19------- 48-------
20None 49None
@@ -22,4 +51,6 @@ None
22SEE ALSO 51SEE ALSO
23-------- 52--------
24linkperf:perf-stat[1], linkperf:perf-top[1], 53linkperf:perf-stat[1], linkperf:perf-top[1],
25linkperf:perf-record[1] 54linkperf:perf-record[1],
55http://www.intel.com/Assets/PDF/manual/253669.pdf[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide],
56http://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..b317102138c8
--- /dev/null
+++ b/tools/perf/Documentation/perf-lock.txt
@@ -0,0 +1,29 @@
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
27SEE ALSO
28--------
29linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 250e391b4bc8..27d52dae5a43 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -15,6 +15,8 @@ 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' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
18 20
19DESCRIPTION 21DESCRIPTION
20----------- 22-----------
@@ -29,6 +31,10 @@ OPTIONS
29--vmlinux=PATH:: 31--vmlinux=PATH::
30 Specify vmlinux path which has debuginfo (Dwarf binary). 32 Specify vmlinux path which has debuginfo (Dwarf binary).
31 33
34-s::
35--source=PATH::
36 Specify path to kernel source.
37
32-v:: 38-v::
33--verbose:: 39--verbose::
34 Be more verbose (show parsed arguments, etc). 40 Be more verbose (show parsed arguments, etc).
@@ -39,22 +45,105 @@ OPTIONS
39 45
40-d:: 46-d::
41--del=:: 47--del=::
42 Delete a probe event. 48 Delete probe events. This accepts glob wildcards('*', '?') and character
49 classes(e.g. [a-z], [!A-Z]).
43 50
44-l:: 51-l::
45--list:: 52--list::
46 List up current probe events. 53 List up current probe events.
47 54
55-L::
56--line=::
57 Show source code lines which can be probed. This needs an argument
58 which specifies a range of the source code. (see LINE SYNTAX for detail)
59
60-f::
61--force::
62 Forcibly add events with existing name.
63
64-n::
65--dry-run::
66 Dry run. With this option, --add and --del doesn't execute actual
67 adding and removal operations.
68
69--max-probes::
70 Set the maximum number of probe points for an event. Default is 128.
71
48PROBE SYNTAX 72PROBE SYNTAX
49------------ 73------------
50Probe points are defined by following syntax. 74Probe points are defined by following syntax.
51 75
52 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 76 1) Define event based on function name
77 [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
78
79 2) Define event based on source file with line number
80 [EVENT=]SRC:ALN [ARG ...]
81
82 3) Define event based on source file with lazy pattern
83 [EVENT=]SRC;PTN [ARG ...]
84
53 85
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'. 86'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. 87'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. 88It 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). 89'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT).
90
91PROBE ARGUMENT
92--------------
93Each probe argument follows below syntax.
94
95 [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
96
97'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'.)
98'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.
99
100LINE SYNTAX
101-----------
102Line range is descripted by following syntax.
103
104 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]"
105
106FUNC specifies the function name of showing lines. 'RLN' is the start line
107number from function entry line, and 'RLN2' is the end line number. As same as
108probe syntax, 'SRC' means the source file path, 'ALN' is start line number,
109and 'ALN2' is end line number in the file. It is also possible to specify how
110many lines to show by using 'NUM'.
111So, "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.
112
113LAZY MATCHING
114-------------
115 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]).
116
117e.g.
118 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on.
119
120This 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.)
121
122
123EXAMPLES
124--------
125Display which lines in schedule() can be probed:
126
127 ./perf probe --line schedule
128
129Add a probe on schedule() function 12th line with recording cpu local variable:
130
131 ./perf probe schedule:12 cpu
132 or
133 ./perf probe --add='schedule:12 cpu'
134
135 this will add one or more probes which has the name start with "schedule".
136
137 Add probes on lines in schedule() function which calls update_rq_clock().
138
139 ./perf probe 'schedule;update_rq_clock*'
140 or
141 ./perf probe --add='schedule;update_rq_clock*'
142
143Delete all probes on schedule().
144
145 ./perf probe --del='schedule*'
146
58 147
59SEE ALSO 148SEE ALSO
60-------- 149--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index fc46c0b40f6e..3ee27dccfde9 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -58,7 +58,7 @@ OPTIONS
58 58
59-f:: 59-f::
60--force:: 60--force::
61 Overwrite existing data file. 61 Overwrite existing data file. (deprecated)
62 62
63-c:: 63-c::
64--count=:: 64--count=::
@@ -69,8 +69,8 @@ OPTIONS
69 Output file name. 69 Output file name.
70 70
71-i:: 71-i::
72--inherit:: 72--no-inherit::
73 Child tasks inherit counters. 73 Child tasks do not inherit counters.
74-F:: 74-F::
75--freq=:: 75--freq=::
76 Profile at this frequency. 76 Profile at this frequency.
@@ -101,7 +101,20 @@ OPTIONS
101 101
102-R:: 102-R::
103--raw-samples:: 103--raw-samples::
104Collect raw sample records from all opened counters (typically for tracepoint counters). 104Collect raw sample records from all opened counters (default for tracepoint counters).
105
106-C::
107--cpu::
108Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a
109comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
110In per-thread mode with inheritance mode on (default), samples are captured only when
111the thread executes on the designated CPUs. Default is to monitor all CPUs.
112
113-N::
114--no-buildid-cache::
115Do not update the builid cache. This saves some overhead in situations
116where the information in the perf.data file (which includes buildids)
117is sufficient.
105 118
106SEE ALSO 119SEE ALSO
107-------- 120--------
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
index 1ce79198997b..8417644a6166 100644
--- a/tools/perf/Documentation/perf-sched.txt
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -12,7 +12,7 @@ SYNOPSIS
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15There's four variants of perf sched: 15There are four 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,7 +27,7 @@ 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
33OPTIONS 33OPTIONS
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 484080dd5b6f..4b3a2d46b437 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -31,8 +31,8 @@ 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 pid
@@ -43,6 +43,16 @@ OPTIONS
43-c:: 43-c::
44 scale counter values 44 scale counter values
45 45
46-B::
47 print large numbers with thousands' separators according to locale
48
49-C::
50--cpu=::
51Count only on the list of cpus provided. Multiple CPUs can be provided as a
52comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
53In per-thread mode, this option is ignored. The -a option is still necessary
54to activate system-wide monitoring. Default is to count on all CPUs.
55
46EXAMPLES 56EXAMPLES
47-------- 57--------
48 58
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
new file mode 100644
index 000000000000..1c4b5f5b7f71
--- /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 thru 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-top.txt b/tools/perf/Documentation/perf-top.txt
index 4a7d558dc309..1f9687663f2a 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -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-sperated 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>::
@@ -74,7 +76,7 @@ OPTIONS
74 76
75-s <symbol>:: 77-s <symbol>::
76--sym-annotate=<symbol>:: 78--sym-annotate=<symbol>::
77 Annotate this symbol. Requires -k option. 79 Annotate this symbol.
78 80
79-v:: 81-v::
80--verbose:: 82--verbose::
diff --git a/tools/perf/Documentation/perf-trace-perl.txt b/tools/perf/Documentation/perf-trace-perl.txt
index c5f55f439091..ee6525ee6d69 100644
--- a/tools/perf/Documentation/perf-trace-perl.txt
+++ b/tools/perf/Documentation/perf-trace-perl.txt
@@ -8,7 +8,7 @@ perf-trace-perl - Process trace data with a Perl script
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf trace' [-s [lang]:script[.ext] ] 11'perf trace' [-s [Perl]:script[.pl] ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -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):
diff --git a/tools/perf/Documentation/perf-trace-python.txt b/tools/perf/Documentation/perf-trace-python.txt
new file mode 100644
index 000000000000..693be804dd3d
--- /dev/null
+++ b/tools/perf/Documentation/perf-trace-python.txt
@@ -0,0 +1,623 @@
1perf-trace-python(1)
2====================
3
4NAME
5----
6perf-trace-python - Process trace data with a Python script
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' [-s [Python]:script[.py] ]
12
13DESCRIPTION
14-----------
15
16This perf trace option is used to process perf trace 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 trace 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 trace
33scripts via 'perf trace -l'. As such, this script also shows how to
34integrate your script into the list of general-purpose 'perf trace'
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 trace' 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 trace -g python
114generated Python script: perf-trace.py
115
116The output file created also in the current directory is named
117perf-trace.py. Here's the file in its entirety:
118
119# perf trace event handlers, generated by perf trace -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-trace-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-Trace-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 trace 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-trace.py syscall-counts.py
193# perf trace -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-Trace-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-Trace-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 trace -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 trace -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 trace -l' command e.g.:
335
336----
337root@tropicana:~# perf trace -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 trace -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 trace -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-trace.py
394drwxr-xr-x 3 trz trz 4096 2010-01-26 22:49 Perf-Trace-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 trace -l'
400should show a new entry for your script:
401
402----
403root@tropicana:~# perf trace -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 trace record':
413
414 # perf trace record syscall-counts
415
416and display the output using 'perf trace report':
417
418 # perf trace 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 trace -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-trace.py script, while not interesting for its results,
434attempts to exercise all of the main scripting features.
435
436EVENT HANDLERS
437--------------
438
439When perf trace 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 trace 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-Trace-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 trace 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 trace Python modules. To use the functions and
569variables from the given module, add the corresponding 'from XXXX
570import' line to your perf trace 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 trace:
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-trace[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 60e5900da483..122ec9dc4853 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -1,5 +1,5 @@
1perf-trace(1) 1perf-trace(1)
2============== 2=============
3 3
4NAME 4NAME
5---- 5----
@@ -19,6 +19,11 @@ There are several variants of perf trace:
19 'perf trace' to see a detailed trace of the workload that was 19 'perf trace' to see a detailed trace of the workload that was
20 recorded. 20 recorded.
21 21
22 You can also run a set of pre-canned scripts that aggregate and
23 summarize the raw trace data in various ways (the list of scripts is
24 available via 'perf trace -l'). The following variants allow you to
25 record and run those scripts:
26
22 'perf trace record <script>' to record the events required for 'perf 27 'perf trace record <script>' to record the events required for 'perf
23 trace report'. <script> is the name displayed in the output of 28 trace report'. <script> is the name displayed in the output of
24 'perf trace --list' i.e. the actual script name minus any language 29 'perf trace --list' i.e. the actual script name minus any language
@@ -31,6 +36,9 @@ There are several variants of perf trace:
31 record <script>' is used and should be present for this command to 36 record <script>' is used and should be present for this command to
32 succeed. 37 succeed.
33 38
39 See the 'SEE ALSO' section for links to language-specific
40 information on how to write and run your own trace scripts.
41
34OPTIONS 42OPTIONS
35------- 43-------
36-D:: 44-D::
@@ -45,9 +53,11 @@ OPTIONS
45--list=:: 53--list=::
46 Display a list of available trace scripts. 54 Display a list of available trace scripts.
47 55
48-s:: 56-s ['lang']::
49--script=:: 57--script=::
50 Process trace data with the given script ([lang]:script[.ext]). 58 Process trace data with the given script ([lang]:script[.ext]).
59 If the string 'lang' is specified in place of a script name, a
60 list of supported languages will be displayed instead.
51 61
52-g:: 62-g::
53--gen-script=:: 63--gen-script=::
@@ -56,4 +66,5 @@ OPTIONS
56 66
57SEE ALSO 67SEE ALSO
58-------- 68--------
59linkperf:perf-record[1], linkperf:perf-trace-perl[1] 69linkperf:perf-record[1], linkperf:perf-trace-perl[1],
70linkperf:perf-trace-python[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..8c7fc0c8f0b8
--- /dev/null
+++ b/tools/perf/MANIFEST
@@ -0,0 +1,12 @@
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
10include/linux/poison.h
11include/linux/magic.h
12include/linux/hw_breakpoint.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 2e7fa3a06806..1950e19af1cf 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,20 @@ 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 ARCH := x86
189endif
190
165# CFLAGS and LDFLAGS are for the users to override from the command line. 191# CFLAGS and LDFLAGS are for the users to override from the command line.
166 192
167# 193#
@@ -200,7 +226,7 @@ endif
200 226
201CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 227CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
202EXTLIBS = -lpthread -lrt -lelf -lm 228EXTLIBS = -lpthread -lrt -lelf -lm
203ALL_CFLAGS = $(CFLAGS) 229ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
204ALL_LDFLAGS = $(LDFLAGS) 230ALL_LDFLAGS = $(LDFLAGS)
205STRIP ?= strip 231STRIP ?= strip
206 232
@@ -216,7 +242,10 @@ STRIP ?= strip
216# runtime figures out where they are based on the path to the executable. 242# runtime figures out where they are based on the path to the executable.
217# This can help installing the suite in a relocatable way. 243# This can help installing the suite in a relocatable way.
218 244
245# Make the path relative to DESTDIR, not to prefix
246ifndef DESTDIR
219prefix = $(HOME) 247prefix = $(HOME)
248endif
220bindir_relative = bin 249bindir_relative = bin
221bindir = $(prefix)/$(bindir_relative) 250bindir = $(prefix)/$(bindir_relative)
222mandir = share/man 251mandir = share/man
@@ -233,13 +262,13 @@ sysconfdir = $(prefix)/etc
233ETC_PERFCONFIG = etc/perfconfig 262ETC_PERFCONFIG = etc/perfconfig
234endif 263endif
235lib = lib 264lib = lib
236# DESTDIR=
237 265
238export prefix bindir sharedir sysconfdir 266export prefix bindir sharedir sysconfdir
239 267
240CC = $(CROSS_COMPILE)gcc 268CC = $(CROSS_COMPILE)gcc
241AR = $(CROSS_COMPILE)ar 269AR = $(CROSS_COMPILE)ar
242RM = rm -f 270RM = rm -f
271MKDIR = mkdir
243TAR = tar 272TAR = tar
244FIND = find 273FIND = find
245INSTALL = install 274INSTALL = install
@@ -256,14 +285,10 @@ else
256 QUIET_STDERR = ">/dev/null 2>&1" 285 QUIET_STDERR = ">/dev/null 2>&1"
257endif 286endif
258 287
259BITBUCKET = "/dev/null" 288-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 289
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) 290ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y)
266 CFLAGS := $(CFLAGS) -fstack-protector-all 291 CFLAGS := $(CFLAGS) -fstack-protector-all
267endif 292endif
268 293
269 294
@@ -272,7 +297,7 @@ endif
272# Those must not be GNU-specific; they are shared with perl/ which may 297# 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 298# be built by a different compiler. (Note that this is an artifact now
274# but it still might be nice to keep that distinction.) 299# but it still might be nice to keep that distinction.)
275BASIC_CFLAGS = -Iutil/include 300BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include
276BASIC_LDFLAGS = 301BASIC_LDFLAGS =
277 302
278# Guard against environment variables 303# Guard against environment variables
@@ -286,11 +311,7 @@ SCRIPT_PERL =
286SCRIPT_SH = 311SCRIPT_SH =
287TEST_PROGRAMS = 312TEST_PROGRAMS =
288 313
289# 314SCRIPT_SH += perf-archive.sh
290# No scripts right now:
291#
292
293# SCRIPT_SH += perf-am.sh
294 315
295# 316#
296# No Perl scripts right now: 317# No Perl scripts right now:
@@ -310,20 +331,17 @@ PROGRAMS += $(EXTRA_PROGRAMS)
310# 331#
311# Single 'perf' binary right now: 332# Single 'perf' binary right now:
312# 333#
313PROGRAMS += perf 334PROGRAMS += $(OUTPUT)perf
314 335
315# List built-in command $C whose implementation cmd_$C() is not in 336# 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. 337# builtin-$C.o but is linked in as part of some other command.
317# 338#
318# None right now:
319#
320# BUILT_INS += perf-init $X
321 339
322# what 'all' will build and 'install' will install, in perfexecdir 340# what 'all' will build and 'install' will install, in perfexecdir
323ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) 341ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
324 342
325# what 'all' will build but not install in perfexecdir 343# what 'all' will build but not install in perfexecdir
326OTHER_PROGRAMS = perf$X 344OTHER_PROGRAMS = $(OUTPUT)perf$X
327 345
328# Set paths to tools early so that they can be used for version tests. 346# Set paths to tools early so that they can be used for version tests.
329ifndef SHELL_PATH 347ifndef SHELL_PATH
@@ -335,11 +353,12 @@ endif
335 353
336export PERL_PATH 354export PERL_PATH
337 355
338LIB_FILE=libperf.a 356LIB_FILE=$(OUTPUT)libperf.a
339 357
340LIB_H += ../../include/linux/perf_event.h 358LIB_H += ../../include/linux/perf_event.h
341LIB_H += ../../include/linux/rbtree.h 359LIB_H += ../../include/linux/rbtree.h
342LIB_H += ../../include/linux/list.h 360LIB_H += ../../include/linux/list.h
361LIB_H += ../../include/linux/hash.h
343LIB_H += ../../include/linux/stringify.h 362LIB_H += ../../include/linux/stringify.h
344LIB_H += util/include/linux/bitmap.h 363LIB_H += util/include/linux/bitmap.h
345LIB_H += util/include/linux/bitops.h 364LIB_H += util/include/linux/bitops.h
@@ -354,21 +373,24 @@ LIB_H += util/include/linux/rbtree.h
354LIB_H += util/include/linux/string.h 373LIB_H += util/include/linux/string.h
355LIB_H += util/include/linux/types.h 374LIB_H += util/include/linux/types.h
356LIB_H += util/include/asm/asm-offsets.h 375LIB_H += util/include/asm/asm-offsets.h
357LIB_H += util/include/asm/bitops.h
358LIB_H += util/include/asm/bug.h 376LIB_H += util/include/asm/bug.h
359LIB_H += util/include/asm/byteorder.h 377LIB_H += util/include/asm/byteorder.h
378LIB_H += util/include/asm/hweight.h
360LIB_H += util/include/asm/swab.h 379LIB_H += util/include/asm/swab.h
361LIB_H += util/include/asm/system.h 380LIB_H += util/include/asm/system.h
362LIB_H += util/include/asm/uaccess.h 381LIB_H += util/include/asm/uaccess.h
382LIB_H += util/include/dwarf-regs.h
363LIB_H += perf.h 383LIB_H += perf.h
364LIB_H += util/cache.h 384LIB_H += util/cache.h
365LIB_H += util/callchain.h 385LIB_H += util/callchain.h
386LIB_H += util/build-id.h
366LIB_H += util/debug.h 387LIB_H += util/debug.h
367LIB_H += util/debugfs.h 388LIB_H += util/debugfs.h
368LIB_H += util/event.h 389LIB_H += util/event.h
369LIB_H += util/exec_cmd.h 390LIB_H += util/exec_cmd.h
370LIB_H += util/types.h 391LIB_H += util/types.h
371LIB_H += util/levenshtein.h 392LIB_H += util/levenshtein.h
393LIB_H += util/map.h
372LIB_H += util/parse-options.h 394LIB_H += util/parse-options.h
373LIB_H += util/parse-events.h 395LIB_H += util/parse-events.h
374LIB_H += util/quote.h 396LIB_H += util/quote.h
@@ -377,7 +399,6 @@ LIB_H += util/header.h
377LIB_H += util/help.h 399LIB_H += util/help.h
378LIB_H += util/session.h 400LIB_H += util/session.h
379LIB_H += util/strbuf.h 401LIB_H += util/strbuf.h
380LIB_H += util/string.h
381LIB_H += util/strlist.h 402LIB_H += util/strlist.h
382LIB_H += util/svghelper.h 403LIB_H += util/svghelper.h
383LIB_H += util/run-command.h 404LIB_H += util/run-command.h
@@ -389,77 +410,85 @@ LIB_H += util/sort.h
389LIB_H += util/hist.h 410LIB_H += util/hist.h
390LIB_H += util/thread.h 411LIB_H += util/thread.h
391LIB_H += util/trace-event.h 412LIB_H += util/trace-event.h
392LIB_H += util/trace-event-perl.h
393LIB_H += util/probe-finder.h 413LIB_H += util/probe-finder.h
394LIB_H += util/probe-event.h 414LIB_H += util/probe-event.h
395 415LIB_H += util/pstack.h
396LIB_OBJS += util/abspath.o 416LIB_H += util/cpumap.h
397LIB_OBJS += util/alias.o 417
398LIB_OBJS += util/config.o 418LIB_OBJS += $(OUTPUT)util/abspath.o
399LIB_OBJS += util/ctype.o 419LIB_OBJS += $(OUTPUT)util/alias.o
400LIB_OBJS += util/debugfs.o 420LIB_OBJS += $(OUTPUT)util/build-id.o
401LIB_OBJS += util/environment.o 421LIB_OBJS += $(OUTPUT)util/config.o
402LIB_OBJS += util/event.o 422LIB_OBJS += $(OUTPUT)util/ctype.o
403LIB_OBJS += util/exec_cmd.o 423LIB_OBJS += $(OUTPUT)util/debugfs.o
404LIB_OBJS += util/help.o 424LIB_OBJS += $(OUTPUT)util/environment.o
405LIB_OBJS += util/levenshtein.o 425LIB_OBJS += $(OUTPUT)util/event.o
406LIB_OBJS += util/parse-options.o 426LIB_OBJS += $(OUTPUT)util/exec_cmd.o
407LIB_OBJS += util/parse-events.o 427LIB_OBJS += $(OUTPUT)util/help.o
408LIB_OBJS += util/path.o 428LIB_OBJS += $(OUTPUT)util/levenshtein.o
409LIB_OBJS += util/rbtree.o 429LIB_OBJS += $(OUTPUT)util/parse-options.o
410LIB_OBJS += util/bitmap.o 430LIB_OBJS += $(OUTPUT)util/parse-events.o
411LIB_OBJS += util/hweight.o 431LIB_OBJS += $(OUTPUT)util/path.o
412LIB_OBJS += util/find_next_bit.o 432LIB_OBJS += $(OUTPUT)util/rbtree.o
413LIB_OBJS += util/run-command.o 433LIB_OBJS += $(OUTPUT)util/bitmap.o
414LIB_OBJS += util/quote.o 434LIB_OBJS += $(OUTPUT)util/hweight.o
415LIB_OBJS += util/strbuf.o 435LIB_OBJS += $(OUTPUT)util/run-command.o
416LIB_OBJS += util/string.o 436LIB_OBJS += $(OUTPUT)util/quote.o
417LIB_OBJS += util/strlist.o 437LIB_OBJS += $(OUTPUT)util/strbuf.o
418LIB_OBJS += util/usage.o 438LIB_OBJS += $(OUTPUT)util/string.o
419LIB_OBJS += util/wrapper.o 439LIB_OBJS += $(OUTPUT)util/strlist.o
420LIB_OBJS += util/sigchain.o 440LIB_OBJS += $(OUTPUT)util/usage.o
421LIB_OBJS += util/symbol.o 441LIB_OBJS += $(OUTPUT)util/wrapper.o
422LIB_OBJS += util/color.o 442LIB_OBJS += $(OUTPUT)util/sigchain.o
423LIB_OBJS += util/pager.o 443LIB_OBJS += $(OUTPUT)util/symbol.o
424LIB_OBJS += util/header.o 444LIB_OBJS += $(OUTPUT)util/color.o
425LIB_OBJS += util/callchain.o 445LIB_OBJS += $(OUTPUT)util/pager.o
426LIB_OBJS += util/values.o 446LIB_OBJS += $(OUTPUT)util/header.o
427LIB_OBJS += util/debug.o 447LIB_OBJS += $(OUTPUT)util/callchain.o
428LIB_OBJS += util/map.o 448LIB_OBJS += $(OUTPUT)util/values.o
429LIB_OBJS += util/session.o 449LIB_OBJS += $(OUTPUT)util/debug.o
430LIB_OBJS += util/thread.o 450LIB_OBJS += $(OUTPUT)util/map.o
431LIB_OBJS += util/trace-event-parse.o 451LIB_OBJS += $(OUTPUT)util/pstack.o
432LIB_OBJS += util/trace-event-read.o 452LIB_OBJS += $(OUTPUT)util/session.o
433LIB_OBJS += util/trace-event-info.o 453LIB_OBJS += $(OUTPUT)util/thread.o
434LIB_OBJS += util/trace-event-perl.o 454LIB_OBJS += $(OUTPUT)util/trace-event-parse.o
435LIB_OBJS += util/svghelper.o 455LIB_OBJS += $(OUTPUT)util/trace-event-read.o
436LIB_OBJS += util/sort.o 456LIB_OBJS += $(OUTPUT)util/trace-event-info.o
437LIB_OBJS += util/hist.o 457LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
438LIB_OBJS += util/data_map.o 458LIB_OBJS += $(OUTPUT)util/svghelper.o
439LIB_OBJS += util/probe-event.o 459LIB_OBJS += $(OUTPUT)util/sort.o
440 460LIB_OBJS += $(OUTPUT)util/hist.o
441BUILTIN_OBJS += builtin-annotate.o 461LIB_OBJS += $(OUTPUT)util/probe-event.o
442 462LIB_OBJS += $(OUTPUT)util/util.o
443BUILTIN_OBJS += builtin-bench.o 463LIB_OBJS += $(OUTPUT)util/cpumap.o
464
465BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
466
467BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
444 468
445# Benchmark modules 469# Benchmark modules
446BUILTIN_OBJS += bench/sched-messaging.o 470BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
447BUILTIN_OBJS += bench/sched-pipe.o 471BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
448BUILTIN_OBJS += bench/mem-memcpy.o 472BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
449 473
450BUILTIN_OBJS += builtin-diff.o 474BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
451BUILTIN_OBJS += builtin-help.o 475BUILTIN_OBJS += $(OUTPUT)builtin-help.o
452BUILTIN_OBJS += builtin-sched.o 476BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
453BUILTIN_OBJS += builtin-buildid-list.o 477BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
454BUILTIN_OBJS += builtin-list.o 478BUILTIN_OBJS += $(OUTPUT)builtin-buildid-cache.o
455BUILTIN_OBJS += builtin-record.o 479BUILTIN_OBJS += $(OUTPUT)builtin-list.o
456BUILTIN_OBJS += builtin-report.o 480BUILTIN_OBJS += $(OUTPUT)builtin-record.o
457BUILTIN_OBJS += builtin-stat.o 481BUILTIN_OBJS += $(OUTPUT)builtin-report.o
458BUILTIN_OBJS += builtin-timechart.o 482BUILTIN_OBJS += $(OUTPUT)builtin-stat.o
459BUILTIN_OBJS += builtin-top.o 483BUILTIN_OBJS += $(OUTPUT)builtin-timechart.o
460BUILTIN_OBJS += builtin-trace.o 484BUILTIN_OBJS += $(OUTPUT)builtin-top.o
461BUILTIN_OBJS += builtin-probe.o 485BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
462BUILTIN_OBJS += builtin-kmem.o 486BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
487BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
488BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
489BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
490BUILTIN_OBJS += $(OUTPUT)builtin-test.o
491BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
463 492
464PERFLIBS = $(LIB_FILE) 493PERFLIBS = $(LIB_FILE)
465 494
@@ -474,6 +503,16 @@ PERFLIBS = $(LIB_FILE)
474-include config.mak.autogen 503-include config.mak.autogen
475-include config.mak 504-include config.mak
476 505
506ifndef NO_DWARF
507FLAGS_DWARF=$(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf $(ALL_LDFLAGS) $(EXTLIBS)
508ifneq ($(call try-cc,$(SOURCE_DWARF),$(FLAGS_DWARF)),y)
509 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);
510 NO_DWARF := 1
511endif # Dwarf support
512endif # NO_DWARF
513
514-include arch/$(ARCH)/Makefile
515
477ifeq ($(uname_S),Darwin) 516ifeq ($(uname_S),Darwin)
478 ifndef NO_FINK 517 ifndef NO_FINK
479 ifeq ($(shell test -d /sw/lib && echo y),y) 518 ifeq ($(shell test -d /sw/lib && echo y),y)
@@ -490,62 +529,124 @@ ifeq ($(uname_S),Darwin)
490 PTHREAD_LIBS = 529 PTHREAD_LIBS =
491endif 530endif
492 531
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) 532ifneq ($(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) 533 BASIC_CFLAGS += -I$(OUTPUT)
495 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
496endif 534endif
497 535
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) 536FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
499 BASIC_CFLAGS += -DLIBELF_NO_MMAP 537ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y)
538 FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS)
539 ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y)
540 msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);
541 else
542 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel);
500 endif 543 endif
501else
502 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
503endif 544endif
504 545
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) 546ifneq ($(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); 547 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 548endif
513 549
514ifndef NO_LIBPERL 550ifndef NO_DWARF
515PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` 551ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined)
516PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 552 msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled);
553else
554 BASIC_CFLAGS += -I/usr/include/elfutils -DDWARF_SUPPORT
555 EXTLIBS += -lelf -ldw
556 LIB_OBJS += $(OUTPUT)util/probe-finder.o
557endif # PERF_HAVE_DWARF_REGS
558endif # NO_DWARF
559
560ifdef NO_NEWT
561 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
562else
563 FLAGS_NEWT=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lnewt
564 ifneq ($(call try-cc,$(SOURCE_NEWT),$(FLAGS_NEWT)),y)
565 msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev);
566 BASIC_CFLAGS += -DNO_NEWT_SUPPORT
567 else
568 # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
569 BASIC_CFLAGS += -I/usr/include/slang
570 EXTLIBS += -lnewt -lslang
571 LIB_OBJS += $(OUTPUT)util/ui/setup.o
572 LIB_OBJS += $(OUTPUT)util/ui/browser.o
573 LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
574 LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
575 LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
576 LIB_OBJS += $(OUTPUT)util/ui/helpline.o
577 LIB_OBJS += $(OUTPUT)util/ui/progress.o
578 LIB_OBJS += $(OUTPUT)util/ui/util.o
579 LIB_H += util/ui/browser.h
580 LIB_H += util/ui/browsers/map.h
581 LIB_H += util/ui/helpline.h
582 LIB_H += util/ui/libslang.h
583 LIB_H += util/ui/progress.h
584 LIB_H += util/ui/util.h
585 endif
517endif 586endif
518 587
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) 588ifdef NO_LIBPERL
520 BASIC_CFLAGS += -DNO_LIBPERL 589 BASIC_CFLAGS += -DNO_LIBPERL
521else 590else
522 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS) 591 PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
523 LIB_OBJS += scripts/perl/Perf-Trace-Util/Context.o 592 PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
593 FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
594
595 ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y)
596 BASIC_CFLAGS += -DNO_LIBPERL
597 else
598 ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
599 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
600 LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
601 endif
602endif
603
604ifdef NO_LIBPYTHON
605 BASIC_CFLAGS += -DNO_LIBPYTHON
606else
607 PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null`
608 PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
609 FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
610 ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
611 BASIC_CFLAGS += -DNO_LIBPYTHON
612 else
613 ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS)
614 LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
615 LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
616 endif
524endif 617endif
525 618
526ifdef NO_DEMANGLE 619ifdef NO_DEMANGLE
527 BASIC_CFLAGS += -DNO_DEMANGLE 620 BASIC_CFLAGS += -DNO_DEMANGLE
528else 621else
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") 622 ifdef HAVE_CPLUS_DEMANGLE
530 623 EXTLIBS += -liberty
531 ifeq ($(has_bfd),y) 624 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
532 EXTLIBS += -lbfd 625 else
533 else 626 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") 627 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
535 ifeq ($(has_bfd_iberty),y) 628 ifeq ($(has_bfd),y)
536 EXTLIBS += -lbfd -liberty 629 EXTLIBS += -lbfd
537 else 630 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") 631 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
539 ifeq ($(has_bfd_iberty_z),y) 632 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY))
540 EXTLIBS += -lbfd -liberty -lz 633 ifeq ($(has_bfd_iberty),y)
634 EXTLIBS += -lbfd -liberty
541 else 635 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") 636 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
543 ifeq ($(has_cplus_demangle),y) 637 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z))
544 EXTLIBS += -liberty 638 ifeq ($(has_bfd_iberty_z),y)
545 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE 639 EXTLIBS += -lbfd -liberty -lz
546 else 640 else
547 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) 641 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
548 BASIC_CFLAGS += -DNO_DEMANGLE 642 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE))
643 ifeq ($(has_cplus_demangle),y)
644 EXTLIBS += -liberty
645 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
646 else
647 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
648 BASIC_CFLAGS += -DNO_DEMANGLE
649 endif
549 endif 650 endif
550 endif 651 endif
551 endif 652 endif
@@ -591,53 +692,53 @@ ifdef NO_C99_FORMAT
591endif 692endif
592ifdef SNPRINTF_RETURNS_BOGUS 693ifdef SNPRINTF_RETURNS_BOGUS
593 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS 694 COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
594 COMPAT_OBJS += compat/snprintf.o 695 COMPAT_OBJS += $(OUTPUT)compat/snprintf.o
595endif 696endif
596ifdef FREAD_READS_DIRECTORIES 697ifdef FREAD_READS_DIRECTORIES
597 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES 698 COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
598 COMPAT_OBJS += compat/fopen.o 699 COMPAT_OBJS += $(OUTPUT)compat/fopen.o
599endif 700endif
600ifdef NO_SYMLINK_HEAD 701ifdef NO_SYMLINK_HEAD
601 BASIC_CFLAGS += -DNO_SYMLINK_HEAD 702 BASIC_CFLAGS += -DNO_SYMLINK_HEAD
602endif 703endif
603ifdef NO_STRCASESTR 704ifdef NO_STRCASESTR
604 COMPAT_CFLAGS += -DNO_STRCASESTR 705 COMPAT_CFLAGS += -DNO_STRCASESTR
605 COMPAT_OBJS += compat/strcasestr.o 706 COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o
606endif 707endif
607ifdef NO_STRTOUMAX 708ifdef NO_STRTOUMAX
608 COMPAT_CFLAGS += -DNO_STRTOUMAX 709 COMPAT_CFLAGS += -DNO_STRTOUMAX
609 COMPAT_OBJS += compat/strtoumax.o 710 COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o
610endif 711endif
611ifdef NO_STRTOULL 712ifdef NO_STRTOULL
612 COMPAT_CFLAGS += -DNO_STRTOULL 713 COMPAT_CFLAGS += -DNO_STRTOULL
613endif 714endif
614ifdef NO_SETENV 715ifdef NO_SETENV
615 COMPAT_CFLAGS += -DNO_SETENV 716 COMPAT_CFLAGS += -DNO_SETENV
616 COMPAT_OBJS += compat/setenv.o 717 COMPAT_OBJS += $(OUTPUT)compat/setenv.o
617endif 718endif
618ifdef NO_MKDTEMP 719ifdef NO_MKDTEMP
619 COMPAT_CFLAGS += -DNO_MKDTEMP 720 COMPAT_CFLAGS += -DNO_MKDTEMP
620 COMPAT_OBJS += compat/mkdtemp.o 721 COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o
621endif 722endif
622ifdef NO_UNSETENV 723ifdef NO_UNSETENV
623 COMPAT_CFLAGS += -DNO_UNSETENV 724 COMPAT_CFLAGS += -DNO_UNSETENV
624 COMPAT_OBJS += compat/unsetenv.o 725 COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o
625endif 726endif
626ifdef NO_SYS_SELECT_H 727ifdef NO_SYS_SELECT_H
627 BASIC_CFLAGS += -DNO_SYS_SELECT_H 728 BASIC_CFLAGS += -DNO_SYS_SELECT_H
628endif 729endif
629ifdef NO_MMAP 730ifdef NO_MMAP
630 COMPAT_CFLAGS += -DNO_MMAP 731 COMPAT_CFLAGS += -DNO_MMAP
631 COMPAT_OBJS += compat/mmap.o 732 COMPAT_OBJS += $(OUTPUT)compat/mmap.o
632else 733else
633 ifdef USE_WIN32_MMAP 734 ifdef USE_WIN32_MMAP
634 COMPAT_CFLAGS += -DUSE_WIN32_MMAP 735 COMPAT_CFLAGS += -DUSE_WIN32_MMAP
635 COMPAT_OBJS += compat/win32mmap.o 736 COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o
636 endif 737 endif
637endif 738endif
638ifdef NO_PREAD 739ifdef NO_PREAD
639 COMPAT_CFLAGS += -DNO_PREAD 740 COMPAT_CFLAGS += -DNO_PREAD
640 COMPAT_OBJS += compat/pread.o 741 COMPAT_OBJS += $(OUTPUT)compat/pread.o
641endif 742endif
642ifdef NO_FAST_WORKING_DIRECTORY 743ifdef NO_FAST_WORKING_DIRECTORY
643 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY 744 BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
@@ -659,10 +760,10 @@ else
659endif 760endif
660endif 761endif
661ifdef NO_INET_NTOP 762ifdef NO_INET_NTOP
662 LIB_OBJS += compat/inet_ntop.o 763 LIB_OBJS += $(OUTPUT)compat/inet_ntop.o
663endif 764endif
664ifdef NO_INET_PTON 765ifdef NO_INET_PTON
665 LIB_OBJS += compat/inet_pton.o 766 LIB_OBJS += $(OUTPUT)compat/inet_pton.o
666endif 767endif
667 768
668ifdef NO_ICONV 769ifdef NO_ICONV
@@ -679,15 +780,15 @@ endif
679 780
680ifdef PPC_SHA1 781ifdef PPC_SHA1
681 SHA1_HEADER = "ppc/sha1.h" 782 SHA1_HEADER = "ppc/sha1.h"
682 LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o 783 LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o
683else 784else
684ifdef ARM_SHA1 785ifdef ARM_SHA1
685 SHA1_HEADER = "arm/sha1.h" 786 SHA1_HEADER = "arm/sha1.h"
686 LIB_OBJS += arm/sha1.o arm/sha1_arm.o 787 LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o
687else 788else
688ifdef MOZILLA_SHA1 789ifdef MOZILLA_SHA1
689 SHA1_HEADER = "mozilla-sha1/sha1.h" 790 SHA1_HEADER = "mozilla-sha1/sha1.h"
690 LIB_OBJS += mozilla-sha1/sha1.o 791 LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o
691else 792else
692 SHA1_HEADER = <openssl/sha.h> 793 SHA1_HEADER = <openssl/sha.h>
693 EXTLIBS += $(LIB_4_CRYPTO) 794 EXTLIBS += $(LIB_4_CRYPTO)
@@ -699,15 +800,15 @@ ifdef NO_PERL_MAKEMAKER
699endif 800endif
700ifdef NO_HSTRERROR 801ifdef NO_HSTRERROR
701 COMPAT_CFLAGS += -DNO_HSTRERROR 802 COMPAT_CFLAGS += -DNO_HSTRERROR
702 COMPAT_OBJS += compat/hstrerror.o 803 COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o
703endif 804endif
704ifdef NO_MEMMEM 805ifdef NO_MEMMEM
705 COMPAT_CFLAGS += -DNO_MEMMEM 806 COMPAT_CFLAGS += -DNO_MEMMEM
706 COMPAT_OBJS += compat/memmem.o 807 COMPAT_OBJS += $(OUTPUT)compat/memmem.o
707endif 808endif
708ifdef INTERNAL_QSORT 809ifdef INTERNAL_QSORT
709 COMPAT_CFLAGS += -DINTERNAL_QSORT 810 COMPAT_CFLAGS += -DINTERNAL_QSORT
710 COMPAT_OBJS += compat/qsort.o 811 COMPAT_OBJS += $(OUTPUT)compat/qsort.o
711endif 812endif
712ifdef RUNTIME_PREFIX 813ifdef RUNTIME_PREFIX
713 COMPAT_CFLAGS += -DRUNTIME_PREFIX 814 COMPAT_CFLAGS += -DRUNTIME_PREFIX
@@ -738,6 +839,7 @@ ifndef V
738 QUIET_CC = @echo ' ' CC $@; 839 QUIET_CC = @echo ' ' CC $@;
739 QUIET_AR = @echo ' ' AR $@; 840 QUIET_AR = @echo ' ' AR $@;
740 QUIET_LINK = @echo ' ' LINK $@; 841 QUIET_LINK = @echo ' ' LINK $@;
842 QUIET_MKDIR = @echo ' ' MKDIR $@;
741 QUIET_BUILT_IN = @echo ' ' BUILTIN $@; 843 QUIET_BUILT_IN = @echo ' ' BUILTIN $@;
742 QUIET_GEN = @echo ' ' GEN $@; 844 QUIET_GEN = @echo ' ' GEN $@;
743 QUIET_SUBDIR0 = +@subdir= 845 QUIET_SUBDIR0 = +@subdir=
@@ -787,7 +889,7 @@ export TAR INSTALL DESTDIR SHELL_PATH
787 889
788SHELL = $(SHELL_PATH) 890SHELL = $(SHELL_PATH)
789 891
790all:: .perf.dev.null shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) PERF-BUILD-OPTIONS 892all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS
791ifneq (,$X) 893ifneq (,$X)
792 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) 894 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
793endif 895endif
@@ -799,51 +901,51 @@ please_set_SHELL_PATH_to_a_more_modern_shell:
799 901
800shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell 902shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
801 903
802strip: $(PROGRAMS) perf$X 904strip: $(PROGRAMS) $(OUTPUT)perf$X
803 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) perf$X 905 $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X
804 906
805perf.o: perf.c common-cmds.h PERF-CFLAGS 907$(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
806 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ 908 $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \
807 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 909 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
808 $(ALL_CFLAGS) -c $(filter %.c,$^) 910 $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
809 911
810perf$X: perf.o $(BUILTIN_OBJS) $(PERFLIBS) 912$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
811 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ perf.o \ 913 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(OUTPUT)perf.o \
812 $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) 914 $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
813 915
814builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS 916$(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
815 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ 917 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
816 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 918 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
817 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 919 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
818 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 920 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
819 921
820builtin-timechart.o: builtin-timechart.c common-cmds.h PERF-CFLAGS 922$(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
821 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ 923 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
822 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ 924 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
823 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 925 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
824 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 926 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
825 927
826$(BUILT_INS): perf$X 928$(BUILT_INS): $(OUTPUT)perf$X
827 $(QUIET_BUILT_IN)$(RM) $@ && \ 929 $(QUIET_BUILT_IN)$(RM) $@ && \
828 ln perf$X $@ 2>/dev/null || \ 930 ln perf$X $@ 2>/dev/null || \
829 ln -s perf$X $@ 2>/dev/null || \ 931 ln -s perf$X $@ 2>/dev/null || \
830 cp perf$X $@ 932 cp perf$X $@
831 933
832common-cmds.h: util/generate-cmdlist.sh command-list.txt 934$(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt
833 935
834common-cmds.h: $(wildcard Documentation/perf-*.txt) 936$(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt)
835 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ 937 $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
836 938
837$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh 939$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
838 $(QUIET_GEN)$(RM) $@ $@+ && \ 940 $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \
839 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ 941 sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
840 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ 942 -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
841 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ 943 -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \
842 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ 944 -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \
843 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ 945 -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
844 $@.sh >$@+ && \ 946 $@.sh > $(OUTPUT)$@+ && \
845 chmod +x $@+ && \ 947 chmod +x $(OUTPUT)$@+ && \
846 mv $@+ $@ 948 mv $(OUTPUT)$@+ $(OUTPUT)$@
847 949
848configure: configure.ac 950configure: configure.ac
849 $(QUIET_GEN)$(RM) $@ $<+ && \ 951 $(QUIET_GEN)$(RM) $@ $<+ && \
@@ -853,60 +955,73 @@ configure: configure.ac
853 $(RM) $<+ 955 $(RM) $<+
854 956
855# These can record PERF_VERSION 957# These can record PERF_VERSION
856perf.o perf.spec \ 958$(OUTPUT)perf.o perf.spec \
857 $(patsubst %.sh,%,$(SCRIPT_SH)) \ 959 $(patsubst %.sh,%,$(SCRIPT_SH)) \
858 $(patsubst %.perl,%,$(SCRIPT_PERL)) \ 960 $(patsubst %.perl,%,$(SCRIPT_PERL)) \
859 : PERF-VERSION-FILE 961 : $(OUTPUT)PERF-VERSION-FILE
860 962
861%.o: %.c PERF-CFLAGS 963$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
862 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< 964 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
863%.s: %.c PERF-CFLAGS 965$(OUTPUT)%.s: %.c $(OUTPUT)PERF-CFLAGS
864 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< 966 $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
865%.o: %.S 967$(OUTPUT)%.o: %.S
866 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $< 968 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
867 969
868util/exec_cmd.o: util/exec_cmd.c PERF-CFLAGS 970$(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
869 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ 971 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
870 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \ 972 '-DPERF_EXEC_PATH="$(perfexecdir_SQ)"' \
871 '-DBINDIR="$(bindir_relative_SQ)"' \ 973 '-DBINDIR="$(bindir_relative_SQ)"' \
872 '-DPREFIX="$(prefix_SQ)"' \ 974 '-DPREFIX="$(prefix_SQ)"' \
873 $< 975 $<
874 976
875builtin-init-db.o: builtin-init-db.c PERF-CFLAGS 977$(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)"' $< 978 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $<
979
980$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
981 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
877 982
878util/config.o: util/config.c PERF-CFLAGS 983$(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)"' $< 984 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
880 985
881util/rbtree.o: ../../lib/rbtree.c PERF-CFLAGS 986$(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)"' $< 987 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
883 988
884# some perf warning policies can't fit to lib/bitmap.c, eg: it warns about variable shadowing 989$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
885# from <string.h> that comes from kernel headers wrapping. 990 $(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 991
888util/bitmap.o: ../../lib/bitmap.c PERF-CFLAGS 992$(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)"' $< 993 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
890 994
891util/hweight.o: ../../lib/hweight.c PERF-CFLAGS 995$(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)"' $< 996 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
893 997
894util/find_next_bit.o: ../../lib/find_next_bit.c PERF-CFLAGS 998$(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)"' $< 999 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
896 1000
897util/trace-event-perl.o: util/trace-event-perl.c PERF-CFLAGS 1001$(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 $< 1002 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
899 1003
900scripts/perl/Perf-Trace-Util/Context.o: scripts/perl/Perf-Trace-Util/Context.c PERF-CFLAGS 1004$(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 $< 1005 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $<
902 1006
903perf-%$X: %.o $(PERFLIBS) 1007$(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS
1008 $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $<
1009
1010$(OUTPUT)perf-%$X: %.o $(PERFLIBS)
904 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) 1011 $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
905 1012
906$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) 1013$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
907$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) 1014$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
908builtin-revert.o wt-status.o: wt-status.h 1015builtin-revert.o wt-status.o: wt-status.h
909 1016
1017# we compile into subdirectories. if the target directory is not the source directory, they might not exists. So
1018# we depend the various files onto their directories.
1019DIRECTORY_DEPS = $(LIB_OBJS) $(BUILTIN_OBJS) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h
1020$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS)))
1021# In the second step, we make a rule to actually create these directories
1022$(sort $(dir $(DIRECTORY_DEPS))):
1023 $(QUIET_MKDIR)$(MKDIR) -p $@ 2>/dev/null
1024
910$(LIB_FILE): $(LIB_OBJS) 1025$(LIB_FILE): $(LIB_OBJS)
911 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) 1026 $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
912 1027
@@ -941,17 +1056,17 @@ cscope:
941TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ 1056TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
942 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) 1057 $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
943 1058
944PERF-CFLAGS: .FORCE-PERF-CFLAGS 1059$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
945 @FLAGS='$(TRACK_CFLAGS)'; \ 1060 @FLAGS='$(TRACK_CFLAGS)'; \
946 if test x"$$FLAGS" != x"`cat PERF-CFLAGS 2>/dev/null`" ; then \ 1061 if test x"$$FLAGS" != x"`cat $(OUTPUT)PERF-CFLAGS 2>/dev/null`" ; then \
947 echo 1>&2 " * new build flags or prefix"; \ 1062 echo 1>&2 " * new build flags or prefix"; \
948 echo "$$FLAGS" >PERF-CFLAGS; \ 1063 echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \
949 fi 1064 fi
950 1065
951# We need to apply sq twice, once to protect from the shell 1066# We need to apply sq twice, once to protect from the shell
952# that runs PERF-BUILD-OPTIONS, and then again to protect it 1067# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it
953# and the first level quoting from the shell that runs "echo". 1068# and the first level quoting from the shell that runs "echo".
954PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS 1069$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS
955 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ 1070 @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
956 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ 1071 @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
957 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ 1072 @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@
@@ -972,7 +1087,7 @@ all:: $(TEST_PROGRAMS)
972 1087
973export NO_SVN_TESTS 1088export NO_SVN_TESTS
974 1089
975check: common-cmds.h 1090check: $(OUTPUT)common-cmds.h
976 if sparse; \ 1091 if sparse; \
977 then \ 1092 then \
978 for i in *.c */*.c; \ 1093 for i in *.c */*.c; \
@@ -1006,17 +1121,24 @@ export perfexec_instdir
1006 1121
1007install: all 1122install: all
1008 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' 1123 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
1009 $(INSTALL) perf$X '$(DESTDIR_SQ)$(bindir_SQ)' 1124 $(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' 1125 $(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' 1126 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1127 $(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' 1128 $(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' 1129 $(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' 1130 $(INSTALL) scripts/perl/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin'
1131 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1132 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1133 $(INSTALL) scripts/python/Perf-Trace-Util/lib/Perf/Trace/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/Perf-Trace-Util/lib/Perf/Trace'
1134 $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'
1135 $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin'
1136
1015ifdef BUILT_INS 1137ifdef BUILT_INS
1016 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1138 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1017 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' 1139 $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
1018ifneq (,$X) 1140ifneq (,$X)
1019 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';) 1141 $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';)
1020endif 1142endif
1021endif 1143endif
1022 1144
@@ -1100,25 +1222,20 @@ clean:
1100 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) 1222 $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE)
1101 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X 1223 $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X
1102 $(RM) $(TEST_PROGRAMS) 1224 $(RM) $(TEST_PROGRAMS)
1103 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* 1225 $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
1104 $(RM) -r autom4te.cache 1226 $(RM) -r autom4te.cache
1105 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache 1227 $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
1106 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir 1228 $(RM) -r $(PERF_TARNAME) .doc-tmp-dir
1107 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz 1229 $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz
1108 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz 1230 $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
1109 $(MAKE) -C Documentation/ clean 1231 $(MAKE) -C Documentation/ clean
1110 $(RM) PERF-VERSION-FILE PERF-CFLAGS PERF-BUILD-OPTIONS 1232 $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS
1111 1233
1112.PHONY: all install clean strip 1234.PHONY: all install clean strip
1113.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell 1235.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 1236.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
1115.PHONY: .FORCE-PERF-BUILD-OPTIONS 1237.PHONY: .FORCE-PERF-BUILD-OPTIONS
1116 1238
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 1239### Make sure built-ins do not have dups and listed in perf.c
1123# 1240#
1124check-builtins:: 1241check-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/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.c b/tools/perf/bench/mem-memcpy.c
index 89773178e894..38dae7465142 100644
--- a/tools/perf/bench/mem-memcpy.c
+++ b/tools/perf/bench/mem-memcpy.c
@@ -10,7 +10,6 @@
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"
16 15
@@ -24,7 +23,7 @@
24 23
25static const char *length_str = "1MB"; 24static const char *length_str = "1MB";
26static const char *routine = "default"; 25static const char *routine = "default";
27static int use_clock = 0; 26static bool use_clock = false;
28static int clock_fd; 27static int clock_fd;
29 28
30static const struct option options[] = { 29static const struct option options[] = {
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..1478dc64bf15 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;
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
88 he->count++;
89
90 if (!sym || !he->map)
91 return;
92 53
93 priv = symbol__priv(sym); 54 he = __hists__add_entry(self, al, NULL, 1);
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 perf_session *session)
132{ 62{
133 struct addr_location al; 63 struct addr_location al;
64 struct sample_data data;
134 65
135 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 66 if (event__preprocess_sample(event, session, &al, &data, 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
171 c = strchr(line, '\n');
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 88
189 if (*tmp) { 89 if (self->offset != -1) {
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
378 if (!filename)
379 return;
380 287
381 if (verbose) 288 if (hist_entry__annotate(he, &head, 0) < 0)
382 fprintf(stderr, "%s: filename=%s, sym=%s, start=%Lx, end=%Lx\n", 289 return -1;
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,78 @@ 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 *first = rb_first(&self->entries), *nd = first;
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 if (is_exit_key(key))
446 * he->sym->hist to signal we already processed this symbol. 347 break;
447 */ 348 switch (key) {
448 free(priv->hist); 349 case KEY_RIGHT:
449 priv->hist = NULL; 350 case '\t':
351 nd = rb_next(nd);
352 break;
353 case KEY_LEFT:
354 if (nd == first)
355 continue;
356 nd = rb_prev(nd);
357 default:
358 break;
359 }
360 } else {
361 hist_entry__tty_annotate(he);
362 nd = rb_next(nd);
363 /*
364 * Since we have a hist_entry per IP for the same
365 * symbol, free he->ms.sym->hist to signal we already
366 * processed this symbol.
367 */
368 free(priv->hist);
369 priv->hist = NULL;
370 }
450 } 371 }
451} 372}
452 373
453static struct perf_event_ops event_ops = { 374static struct perf_event_ops event_ops = {
454 .process_sample_event = process_sample_event, 375 .sample = process_sample_event,
455 .process_mmap_event = event__process_mmap, 376 .mmap = event__process_mmap,
456 .process_comm_event = event__process_comm, 377 .comm = event__process_comm,
457 .process_fork_event = event__process_task, 378 .fork = event__process_task,
458}; 379};
459 380
460static int __cmd_annotate(void) 381static int __cmd_annotate(void)
@@ -462,7 +383,7 @@ static int __cmd_annotate(void)
462 int ret; 383 int ret;
463 struct perf_session *session; 384 struct perf_session *session;
464 385
465 session = perf_session__new(input_name, O_RDONLY, force); 386 session = perf_session__new(input_name, O_RDONLY, force, false);
466 if (session == NULL) 387 if (session == NULL)
467 return -ENOMEM; 388 return -ENOMEM;
468 389
@@ -471,7 +392,7 @@ static int __cmd_annotate(void)
471 goto out_delete; 392 goto out_delete;
472 393
473 if (dump_trace) { 394 if (dump_trace) {
474 event__print_totals(); 395 perf_session__fprintf_nr_events(session, stdout);
475 goto out_delete; 396 goto out_delete;
476 } 397 }
477 398
@@ -479,11 +400,11 @@ static int __cmd_annotate(void)
479 perf_session__fprintf(session, stdout); 400 perf_session__fprintf(session, stdout);
480 401
481 if (verbose > 2) 402 if (verbose > 2)
482 dsos__fprintf(stdout); 403 perf_session__fprintf_dsos(session, stdout);
483 404
484 perf_session__collapse_resort(session); 405 hists__collapse_resort(&session->hists);
485 perf_session__output_resort(session, session->event_total[0]); 406 hists__output_resort(&session->hists);
486 perf_session__find_annotations(session); 407 hists__find_annotations(&session->hists);
487out_delete: 408out_delete:
488 perf_session__delete(session); 409 perf_session__delete(session);
489 410
@@ -498,10 +419,12 @@ static const char * const annotate_usage[] = {
498static const struct option options[] = { 419static const struct option options[] = {
499 OPT_STRING('i', "input", &input_name, "file", 420 OPT_STRING('i', "input", &input_name, "file",
500 "input file name"), 421 "input file name"),
422 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
423 "only consider symbols in these dsos"),
501 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", 424 OPT_STRING('s', "symbol", &sym_hist_filter, "symbol",
502 "symbol to annotate"), 425 "symbol to annotate"),
503 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 426 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
504 OPT_BOOLEAN('v', "verbose", &verbose, 427 OPT_INCR('v', "verbose", &verbose,
505 "be more verbose (show symbol address, etc)"), 428 "be more verbose (show symbol address, etc)"),
506 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 429 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
507 "dump raw trace in ASCII"), 430 "dump raw trace in ASCII"),
@@ -520,6 +443,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
520{ 443{
521 argc = parse_options(argc, argv, options, annotate_usage, 0); 444 argc = parse_options(argc, argv, options, annotate_usage, 0);
522 445
446 setup_browser();
447
523 symbol_conf.priv_size = sizeof(struct sym_priv); 448 symbol_conf.priv_size = sizeof(struct sym_priv);
524 symbol_conf.try_vmlinux_path = true; 449 symbol_conf.try_vmlinux_path = true;
525 450
@@ -539,12 +464,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
539 sym_hist_filter = argv[0]; 464 sym_hist_filter = argv[0];
540 } 465 }
541 466
542 setup_pager();
543
544 if (field_sep && *field_sep == '.') { 467 if (field_sep && *field_sep == '.') {
545 fputs("'.' is the only non valid --field-separator argument\n", 468 pr_err("'.' is the only non valid --field-separator argument\n");
546 stderr); 469 return -1;
547 exit(129);
548 } 470 }
549 471
550 return __cmd_annotate(); 472 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..44a47e13bd67 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,47 +25,28 @@ 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; 39 int err = -1;
57 struct perf_session *session; 40 struct perf_session *session;
58 41
59 session = perf_session__new(input_name, O_RDONLY, force); 42 session = perf_session__new(input_name, O_RDONLY, force, false);
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 err;
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index bd71b8ceafb7..fca1d4402910 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -19,22 +19,15 @@
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, struct perf_session *session)
@@ -42,36 +35,31 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
42 struct addr_location al; 35 struct addr_location al;
43 struct sample_data data = { .period = 1, }; 36 struct sample_data data = { .period = 1, };
44 37
45 dump_printf("(IP, %d): %d: %p\n", event->header.misc, 38 if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
46 event->ip.pid, (void *)(long)event->ip.ip);
47
48 if (event__preprocess_sample(event, session, &al, NULL) < 0) {
49 pr_warning("problem processing %d event, skipping it.\n", 39 pr_warning("problem processing %d event, skipping it.\n",
50 event->header.type); 40 event->header.type);
51 return -1; 41 return -1;
52 } 42 }
53 43
54 if (al.filtered) 44 if (al.filtered || al.sym == NULL)
55 return 0; 45 return 0;
56 46
57 event__parse_sample(event, session->sample_type, &data); 47 if (hists__add_entry(&session->hists, &al, data.period)) {
58 48 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; 49 return -1;
62 } 50 }
63 51
64 session->events_stats.total += data.period; 52 session->hists.stats.total_period += data.period;
65 return 0; 53 return 0;
66} 54}
67 55
68static struct perf_event_ops event_ops = { 56static struct perf_event_ops event_ops = {
69 .process_sample_event = diff__process_sample_event, 57 .sample = diff__process_sample_event,
70 .process_mmap_event = event__process_mmap, 58 .mmap = event__process_mmap,
71 .process_comm_event = event__process_comm, 59 .comm = event__process_comm,
72 .process_exit_event = event__process_task, 60 .exit = event__process_task,
73 .process_fork_event = event__process_task, 61 .fork = event__process_task,
74 .process_lost_event = event__process_lost, 62 .lost = event__process_lost,
75}; 63};
76 64
77static void perf_session__insert_hist_entry_by_name(struct rb_root *root, 65static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
@@ -82,84 +70,69 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
82 struct hist_entry *iter; 70 struct hist_entry *iter;
83 71
84 while (*p != NULL) { 72 while (*p != NULL) {
85 int cmp;
86 parent = *p; 73 parent = *p;
87 iter = rb_entry(parent, struct hist_entry, rb_node); 74 iter = rb_entry(parent, struct hist_entry, rb_node);
88 75 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; 76 p = &(*p)->rb_left;
92 else if (cmp < 0) 77 else
93 p = &(*p)->rb_right; 78 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 } 79 }
102 80
103 rb_link_node(&he->rb_node, parent, p); 81 rb_link_node(&he->rb_node, parent, p);
104 rb_insert_color(&he->rb_node, root); 82 rb_insert_color(&he->rb_node, root);
105} 83}
106 84
107static void perf_session__resort_by_name(struct perf_session *self) 85static void hists__resort_entries(struct hists *self)
108{ 86{
109 unsigned long position = 1; 87 unsigned long position = 1;
110 struct rb_root tmp = RB_ROOT; 88 struct rb_root tmp = RB_ROOT;
111 struct rb_node *next = rb_first(&self->hists); 89 struct rb_node *next = rb_first(&self->entries);
112 90
113 while (next != NULL) { 91 while (next != NULL) {
114 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node); 92 struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
115 93
116 next = rb_next(&n->rb_node); 94 next = rb_next(&n->rb_node);
117 rb_erase(&n->rb_node, &self->hists); 95 rb_erase(&n->rb_node, &self->entries);
118 n->position = position++; 96 n->position = position++;
119 perf_session__insert_hist_entry_by_name(&tmp, n); 97 perf_session__insert_hist_entry_by_name(&tmp, n);
120 } 98 }
121 99
122 self->hists = tmp; 100 self->entries = tmp;
101}
102
103static void hists__set_positions(struct hists *self)
104{
105 hists__output_resort(self);
106 hists__resort_entries(self);
123} 107}
124 108
125static struct hist_entry * 109static struct hist_entry *hists__find_entry(struct hists *self,
126perf_session__find_hist_entry_by_name(struct perf_session *self, 110 struct hist_entry *he)
127 struct hist_entry *he)
128{ 111{
129 struct rb_node *n = self->hists.rb_node; 112 struct rb_node *n = self->entries.rb_node;
130 113
131 while (n) { 114 while (n) {
132 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node); 115 struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
133 int cmp = strcmp(he->map->dso->name, iter->map->dso->name); 116 int64_t cmp = hist_entry__cmp(he, iter);
134 117
135 if (cmp > 0) 118 if (cmp < 0)
136 n = n->rb_left; 119 n = n->rb_left;
137 else if (cmp < 0) 120 else if (cmp > 0)
138 n = n->rb_right; 121 n = n->rb_right;
139 else { 122 else
140 cmp = strcmp(he->sym->name, iter->sym->name); 123 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 } 124 }
149 125
150 return NULL; 126 return NULL;
151} 127}
152 128
153static void perf_session__match_hists(struct perf_session *old_session, 129static void hists__match(struct hists *older, struct hists *newer)
154 struct perf_session *new_session)
155{ 130{
156 struct rb_node *nd; 131 struct rb_node *nd;
157 132
158 perf_session__resort_by_name(old_session); 133 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); 134 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); 135 pos->pair = hists__find_entry(older, pos);
163 } 136 }
164} 137}
165 138
@@ -168,8 +141,8 @@ static int __cmd_diff(void)
168 int ret, i; 141 int ret, i;
169 struct perf_session *session[2]; 142 struct perf_session *session[2];
170 143
171 session[0] = perf_session__new(input_old, O_RDONLY, force); 144 session[0] = perf_session__new(input_old, O_RDONLY, force, false);
172 session[1] = perf_session__new(input_new, O_RDONLY, force); 145 session[1] = perf_session__new(input_new, O_RDONLY, force, false);
173 if (session[0] == NULL || session[1] == NULL) 146 if (session[0] == NULL || session[1] == NULL)
174 return -ENOMEM; 147 return -ENOMEM;
175 148
@@ -177,12 +150,15 @@ static int __cmd_diff(void)
177 ret = perf_session__process_events(session[i], &event_ops); 150 ret = perf_session__process_events(session[i], &event_ops);
178 if (ret) 151 if (ret)
179 goto out_delete; 152 goto out_delete;
180 perf_session__output_resort(session[i], session[i]->events_stats.total);
181 } 153 }
182 154
183 perf_session__match_hists(session[0], session[1]); 155 hists__output_resort(&session[1]->hists);
184 perf_session__fprintf_hists(session[1], session[0], 156 if (show_displacement)
185 show_displacement, stdout); 157 hists__set_positions(&session[0]->hists);
158
159 hists__match(&session[0]->hists, &session[1]->hists);
160 hists__fprintf(&session[1]->hists, &session[0]->hists,
161 show_displacement, stdout);
186out_delete: 162out_delete:
187 for (i = 0; i < 2; ++i) 163 for (i = 0; i < 2; ++i)
188 perf_session__delete(session[i]); 164 perf_session__delete(session[i]);
@@ -195,7 +171,7 @@ static const char * const diff_usage[] = {
195}; 171};
196 172
197static const struct option options[] = { 173static const struct option options[] = {
198 OPT_BOOLEAN('v', "verbose", &verbose, 174 OPT_INCR('v', "verbose", &verbose,
199 "be more verbose (show symbol address, etc)"), 175 "be more verbose (show symbol address, etc)"),
200 OPT_BOOLEAN('m', "displacement", &show_displacement, 176 OPT_BOOLEAN('m', "displacement", &show_displacement,
201 "Show position displacement relative to baseline"), 177 "Show position displacement relative to baseline"),
@@ -204,8 +180,6 @@ static const struct option options[] = {
204 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 180 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
205 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 181 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
206 "load module symbols - WARNING: use only with -k and LIVE kernel"), 182 "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...]", 183 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
210 "only consider symbols in these dsos"), 184 "only consider symbols in these dsos"),
211 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", 185 OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
@@ -232,6 +206,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix __used)
232 input_new = argv[1]; 206 input_new = argv[1];
233 } else 207 } else
234 input_new = argv[0]; 208 input_new = argv[0];
209 } else if (symbol_conf.default_guest_vmlinux_name ||
210 symbol_conf.default_guest_kallsyms) {
211 input_old = "perf.data.host";
212 input_new = "perf.data.guest";
235 } 213 }
236 214
237 symbol_conf.exclude_other = false; 215 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..8e3e47b064ce
--- /dev/null
+++ b/tools/perf/builtin-inject.c
@@ -0,0 +1,228 @@
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(event_t *event __used,
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_mmap(event_t *self, struct perf_session *session)
40{
41 int err;
42
43 err = event__process_mmap(self, session);
44 event__repipe(self, session);
45
46 return err;
47}
48
49static int event__repipe_task(event_t *self, struct perf_session *session)
50{
51 int err;
52
53 err = event__process_task(self, session);
54 event__repipe(self, session);
55
56 return err;
57}
58
59static int event__repipe_tracing_data(event_t *self,
60 struct perf_session *session)
61{
62 int err;
63
64 event__repipe(self, session);
65 err = event__process_tracing_data(self, session);
66
67 return err;
68}
69
70static int dso__read_build_id(struct dso *self)
71{
72 if (self->has_build_id)
73 return 0;
74
75 if (filename__read_build_id(self->long_name, self->build_id,
76 sizeof(self->build_id)) > 0) {
77 self->has_build_id = true;
78 return 0;
79 }
80
81 return -1;
82}
83
84static int dso__inject_build_id(struct dso *self, struct perf_session *session)
85{
86 u16 misc = PERF_RECORD_MISC_USER;
87 struct machine *machine;
88 int err;
89
90 if (dso__read_build_id(self) < 0) {
91 pr_debug("no build_id found for %s\n", self->long_name);
92 return -1;
93 }
94
95 machine = perf_session__find_host_machine(session);
96 if (machine == NULL) {
97 pr_err("Can't find machine for session\n");
98 return -1;
99 }
100
101 if (self->kernel)
102 misc = PERF_RECORD_MISC_KERNEL;
103
104 err = event__synthesize_build_id(self, misc, event__repipe,
105 machine, session);
106 if (err) {
107 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
108 return -1;
109 }
110
111 return 0;
112}
113
114static int event__inject_buildid(event_t *event, struct perf_session *session)
115{
116 struct addr_location al;
117 struct thread *thread;
118 u8 cpumode;
119
120 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
121
122 thread = perf_session__findnew(session, event->ip.pid);
123 if (thread == NULL) {
124 pr_err("problem processing %d event, skipping it.\n",
125 event->header.type);
126 goto repipe;
127 }
128
129 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
130 event->ip.pid, event->ip.ip, &al);
131
132 if (al.map != NULL) {
133 if (!al.map->dso->hit) {
134 al.map->dso->hit = 1;
135 if (map__load(al.map, NULL) >= 0) {
136 dso__inject_build_id(al.map->dso, session);
137 /*
138 * If this fails, too bad, let the other side
139 * account this as unresolved.
140 */
141 } else
142 pr_warning("no symbols found in %s, maybe "
143 "install a debug package?\n",
144 al.map->dso->long_name);
145 }
146 }
147
148repipe:
149 event__repipe(event, session);
150 return 0;
151}
152
153struct perf_event_ops inject_ops = {
154 .sample = event__repipe,
155 .mmap = event__repipe,
156 .comm = event__repipe,
157 .fork = event__repipe,
158 .exit = event__repipe,
159 .lost = event__repipe,
160 .read = event__repipe,
161 .throttle = event__repipe,
162 .unthrottle = event__repipe,
163 .attr = event__repipe,
164 .event_type = event__repipe,
165 .tracing_data = event__repipe,
166 .build_id = event__repipe,
167};
168
169extern volatile int session_done;
170
171static void sig_handler(int sig __attribute__((__unused__)))
172{
173 session_done = 1;
174}
175
176static int __cmd_inject(void)
177{
178 struct perf_session *session;
179 int ret = -EINVAL;
180
181 signal(SIGINT, sig_handler);
182
183 if (inject_build_ids) {
184 inject_ops.sample = event__inject_buildid;
185 inject_ops.mmap = event__repipe_mmap;
186 inject_ops.fork = event__repipe_task;
187 inject_ops.tracing_data = event__repipe_tracing_data;
188 }
189
190 session = perf_session__new(input_name, O_RDONLY, false, true);
191 if (session == NULL)
192 return -ENOMEM;
193
194 ret = perf_session__process_events(session, &inject_ops);
195
196 perf_session__delete(session);
197
198 return ret;
199}
200
201static const char * const report_usage[] = {
202 "perf inject [<options>]",
203 NULL
204};
205
206static const struct option options[] = {
207 OPT_BOOLEAN('b', "build-ids", &inject_build_ids,
208 "Inject build-ids into the output stream"),
209 OPT_INCR('v', "verbose", &verbose,
210 "be more verbose (show build ids, etc)"),
211 OPT_END()
212};
213
214int cmd_inject(int argc, const char **argv, const char *prefix __used)
215{
216 argc = parse_options(argc, argv, options, report_usage, 0);
217
218 /*
219 * Any (unrecognized) arguments left?
220 */
221 if (argc)
222 usage_with_options(report_usage, options);
223
224 if (symbol__init() < 0)
225 return -1;
226
227 return __cmd_inject();
228}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 93c67bf53d2c..31f60a2535e0 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 }
@@ -321,11 +316,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
321 316
322 event__parse_sample(event, session->sample_type, &data); 317 event__parse_sample(event, session->sample_type, &data);
323 318
324 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 319 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
325 event->header.misc, 320 data.pid, data.tid, data.ip, data.period);
326 data.pid, data.tid,
327 (void *)(long)data.ip,
328 (long long)data.period);
329 321
330 thread = perf_session__findnew(session, event->ip.pid); 322 thread = perf_session__findnew(session, event->ip.pid);
331 if (thread == NULL) { 323 if (thread == NULL) {
@@ -342,22 +334,10 @@ static int process_sample_event(event_t *event, struct perf_session *session)
342 return 0; 334 return 0;
343} 335}
344 336
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
354 return 0;
355}
356
357static struct perf_event_ops event_ops = { 337static struct perf_event_ops event_ops = {
358 .process_sample_event = process_sample_event, 338 .sample = process_sample_event,
359 .process_comm_event = event__process_comm, 339 .comm = event__process_comm,
360 .sample_type_check = sample_type_check, 340 .ordered_samples = true,
361}; 341};
362 342
363static double fragmentation(unsigned long n_req, unsigned long n_alloc) 343static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -372,6 +352,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
372 int n_lines, int is_caller) 352 int n_lines, int is_caller)
373{ 353{
374 struct rb_node *next; 354 struct rb_node *next;
355 struct machine *machine;
375 356
376 printf("%.102s\n", graph_dotted_line); 357 printf("%.102s\n", graph_dotted_line);
377 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); 358 printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
@@ -380,23 +361,29 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
380 361
381 next = rb_first(root); 362 next = rb_first(root);
382 363
364 machine = perf_session__find_host_machine(session);
365 if (!machine) {
366 pr_err("__print_result: couldn't find kernel information\n");
367 return;
368 }
383 while (next && n_lines--) { 369 while (next && n_lines--) {
384 struct alloc_stat *data = rb_entry(next, struct alloc_stat, 370 struct alloc_stat *data = rb_entry(next, struct alloc_stat,
385 node); 371 node);
386 struct symbol *sym = NULL; 372 struct symbol *sym = NULL;
373 struct map *map;
387 char buf[BUFSIZ]; 374 char buf[BUFSIZ];
388 u64 addr; 375 u64 addr;
389 376
390 if (is_caller) { 377 if (is_caller) {
391 addr = data->call_site; 378 addr = data->call_site;
392 if (!raw_ip) 379 if (!raw_ip)
393 sym = map_groups__find_function(&session->kmaps, session, addr, NULL); 380 sym = machine__find_kernel_function(machine, addr, &map, NULL);
394 } else 381 } else
395 addr = data->ptr; 382 addr = data->ptr;
396 383
397 if (sym != NULL) 384 if (sym != NULL)
398 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name, 385 snprintf(buf, sizeof(buf), "%s+%Lx", sym->name,
399 addr - sym->start); 386 addr - map->unmap_ip(map, sym->start));
400 else 387 else
401 snprintf(buf, sizeof(buf), "%#Lx", addr); 388 snprintf(buf, sizeof(buf), "%#Lx", addr);
402 printf(" %-34s |", buf); 389 printf(" %-34s |", buf);
@@ -504,11 +491,17 @@ static void sort_result(void)
504 491
505static int __cmd_kmem(void) 492static int __cmd_kmem(void)
506{ 493{
507 int err; 494 int err = -EINVAL;
508 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 495 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false);
509 if (session == NULL) 496 if (session == NULL)
510 return -ENOMEM; 497 return -ENOMEM;
511 498
499 if (perf_session__create_kernel_maps(session) < 0)
500 goto out_delete;
501
502 if (!perf_session__has_traces(session, "kmem record"))
503 goto out_delete;
504
512 setup_pager(); 505 setup_pager();
513 err = perf_session__process_events(session, &event_ops); 506 err = perf_session__process_events(session, &event_ops);
514 if (err != 0) 507 if (err != 0)
@@ -736,7 +729,6 @@ static const char *record_args[] = {
736 "record", 729 "record",
737 "-a", 730 "-a",
738 "-R", 731 "-R",
739 "-M",
740 "-f", 732 "-f",
741 "-c", "1", 733 "-c", "1",
742 "-e", "kmem:kmalloc", 734 "-e", "kmem:kmalloc",
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..821c1586a22b
--- /dev/null
+++ b/tools/perf/builtin-lock.c
@@ -0,0 +1,1005 @@
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 perf_session *s)
838{
839 struct sample_data data;
840 struct thread *thread;
841
842 bzero(&data, sizeof(data));
843 event__parse_sample(self, s->sample_type, &data);
844
845 thread = perf_session__findnew(s, data.tid);
846 if (thread == NULL) {
847 pr_debug("problem processing %d event, skipping it.\n",
848 self->header.type);
849 return -1;
850 }
851
852 process_raw_event(data.raw_data, data.cpu, data.time, thread);
853
854 return 0;
855}
856
857static struct perf_event_ops eops = {
858 .sample = process_sample_event,
859 .comm = event__process_comm,
860 .ordered_samples = true,
861};
862
863static int read_events(void)
864{
865 session = perf_session__new(input_name, O_RDONLY, 0, false);
866 if (!session)
867 die("Initializing perf session failed\n");
868
869 return perf_session__process_events(session, &eops);
870}
871
872static void sort_result(void)
873{
874 unsigned int i;
875 struct lock_stat *st;
876
877 for (i = 0; i < LOCKHASH_SIZE; i++) {
878 list_for_each_entry(st, &lockhash_table[i], hash_entry) {
879 insert_to_result(st, compare);
880 }
881 }
882}
883
884static void __cmd_report(void)
885{
886 setup_pager();
887 select_key();
888 read_events();
889 sort_result();
890 print_result();
891}
892
893static const char * const report_usage[] = {
894 "perf lock report [<options>]",
895 NULL
896};
897
898static const struct option report_options[] = {
899 OPT_STRING('k', "key", &sort_key, "acquired",
900 "key for sorting"),
901 /* TODO: type */
902 OPT_END()
903};
904
905static const char * const info_usage[] = {
906 "perf lock info [<options>]",
907 NULL
908};
909
910static const struct option info_options[] = {
911 OPT_BOOLEAN('t', "threads", &info_threads,
912 "dump thread list in perf.data"),
913 OPT_BOOLEAN('m', "map", &info_map,
914 "map of lock instances (name:address table)"),
915 OPT_END()
916};
917
918static const char * const lock_usage[] = {
919 "perf lock [<options>] {record|trace|report}",
920 NULL
921};
922
923static const struct option lock_options[] = {
924 OPT_STRING('i', "input", &input_name, "file", "input file name"),
925 OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"),
926 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"),
927 OPT_END()
928};
929
930static const char *record_args[] = {
931 "record",
932 "-R",
933 "-f",
934 "-m", "1024",
935 "-c", "1",
936 "-e", "lock:lock_acquire:r",
937 "-e", "lock:lock_acquired:r",
938 "-e", "lock:lock_contended:r",
939 "-e", "lock:lock_release:r",
940};
941
942static int __cmd_record(int argc, const char **argv)
943{
944 unsigned int rec_argc, i, j;
945 const char **rec_argv;
946
947 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
948 rec_argv = calloc(rec_argc + 1, sizeof(char *));
949
950 for (i = 0; i < ARRAY_SIZE(record_args); i++)
951 rec_argv[i] = strdup(record_args[i]);
952
953 for (j = 1; j < (unsigned int)argc; j++, i++)
954 rec_argv[i] = argv[j];
955
956 BUG_ON(i != rec_argc);
957
958 return cmd_record(i, rec_argv, NULL);
959}
960
961int cmd_lock(int argc, const char **argv, const char *prefix __used)
962{
963 unsigned int i;
964
965 symbol__init();
966 for (i = 0; i < LOCKHASH_SIZE; i++)
967 INIT_LIST_HEAD(lockhash_table + i);
968
969 argc = parse_options(argc, argv, lock_options, lock_usage,
970 PARSE_OPT_STOP_AT_NON_OPTION);
971 if (!argc)
972 usage_with_options(lock_usage, lock_options);
973
974 if (!strncmp(argv[0], "rec", 3)) {
975 return __cmd_record(argc, argv);
976 } else if (!strncmp(argv[0], "report", 6)) {
977 trace_handler = &report_lock_ops;
978 if (argc) {
979 argc = parse_options(argc, argv,
980 report_options, report_usage, 0);
981 if (argc)
982 usage_with_options(report_usage, report_options);
983 }
984 __cmd_report();
985 } else if (!strcmp(argv[0], "trace")) {
986 /* Aliased to 'perf trace' */
987 return cmd_trace(argc, argv, prefix);
988 } else if (!strcmp(argv[0], "info")) {
989 if (argc) {
990 argc = parse_options(argc, argv,
991 info_options, info_usage, 0);
992 if (argc)
993 usage_with_options(info_usage, info_options);
994 }
995 /* recycling report_lock_ops */
996 trace_handler = &report_lock_ops;
997 setup_pager();
998 read_events();
999 dump_info();
1000 } else {
1001 usage_with_options(lock_usage, lock_options);
1002 }
1003
1004 return 0;
1005}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c1e6774fd3ed..199d5e19554f 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -36,51 +36,50 @@
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 int nevents;
54 struct perf_probe_event events[MAX_PROBES];
60 struct strlist *dellist; 55 struct strlist *dellist;
61 struct perf_session *psession; 56 struct line_range line_range;
62 struct map *kmap; 57 int max_probe_points;
63} session; 58} params;
64 59
65 60
66/* Parse an event definition. Note that any error must die. */ 61/* Parse an event definition. Note that any error must die. */
67static void parse_probe_event(const char *str) 62static int parse_probe_event(const char *str)
68{ 63{
69 struct probe_point *pp = &session.probes[session.nr_probe]; 64 struct perf_probe_event *pev = &params.events[params.nevents];
65 int ret;
70 66
71 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str); 67 pr_debug("probe-definition(%d): %s\n", params.nevents, str);
72 if (++session.nr_probe == MAX_PROBES) 68 if (++params.nevents == MAX_PROBES) {
73 die("Too many probes (> %d) are specified.", MAX_PROBES); 69 pr_err("Too many probes (> %d) were specified.", MAX_PROBES);
70 return -1;
71 }
74 72
75 /* Parse perf-probe event into probe_point */ 73 /* Parse a perf-probe command into event */
76 parse_perf_probe_event(str, pp, &session.need_dwarf); 74 ret = parse_perf_probe_command(str, pev);
75 pr_debug("%d arguments\n", pev->nargs);
77 76
78 pr_debug("%d arguments\n", pp->nr_args); 77 return ret;
79} 78}
80 79
81static void parse_probe_event_argv(int argc, const char **argv) 80static int parse_probe_event_argv(int argc, const char **argv)
82{ 81{
83 int i, len; 82 int i, len, ret;
84 char *buf; 83 char *buf;
85 84
86 /* Bind up rest arguments */ 85 /* Bind up rest arguments */
@@ -88,54 +87,48 @@ static void parse_probe_event_argv(int argc, const char **argv)
88 for (i = 0; i < argc; i++) 87 for (i = 0; i < argc; i++)
89 len += strlen(argv[i]) + 1; 88 len += strlen(argv[i]) + 1;
90 buf = zalloc(len + 1); 89 buf = zalloc(len + 1);
91 if (!buf) 90 if (buf == NULL)
92 die("Failed to allocate memory for binding arguments."); 91 return -ENOMEM;
93 len = 0; 92 len = 0;
94 for (i = 0; i < argc; i++) 93 for (i = 0; i < argc; i++)
95 len += sprintf(&buf[len], "%s ", argv[i]); 94 len += sprintf(&buf[len], "%s ", argv[i]);
96 parse_probe_event(buf); 95 ret = parse_probe_event(buf);
97 free(buf); 96 free(buf);
97 return ret;
98} 98}
99 99
100static int opt_add_probe_event(const struct option *opt __used, 100static int opt_add_probe_event(const struct option *opt __used,
101 const char *str, int unset __used) 101 const char *str, int unset __used)
102{ 102{
103 if (str) 103 if (str)
104 parse_probe_event(str); 104 return parse_probe_event(str);
105 return 0; 105 else
106 return 0;
106} 107}
107 108
108static int opt_del_probe_event(const struct option *opt __used, 109static int opt_del_probe_event(const struct option *opt __used,
109 const char *str, int unset __used) 110 const char *str, int unset __used)
110{ 111{
111 if (str) { 112 if (str) {
112 if (!session.dellist) 113 if (!params.dellist)
113 session.dellist = strlist__new(true, NULL); 114 params.dellist = strlist__new(true, NULL);
114 strlist__add(session.dellist, str); 115 strlist__add(params.dellist, str);
115 } 116 }
116 return 0; 117 return 0;
117} 118}
118 119
119/* Currently just checking function name from symbol map */ 120#ifdef DWARF_SUPPORT
120static void evaluate_probe_point(struct probe_point *pp) 121static int opt_show_lines(const struct option *opt __used,
122 const char *str, int unset __used)
121{ 123{
122 struct symbol *sym; 124 int ret = 0;
123 sym = map__find_symbol_by_name(session.kmap, pp->function,
124 session.psession, NULL);
125 if (!sym)
126 die("Kernel symbol \'%s\' not found - probe not added.",
127 pp->function);
128}
129 125
130#ifndef NO_LIBDWARF 126 if (str)
131static int open_vmlinux(void) 127 ret = parse_line_range_desc(str, &params.line_range);
132{ 128 INIT_LIST_HEAD(&params.line_range.line_list);
133 if (map__load(session.kmap, session.psession, NULL) < 0) { 129 params.show_lines = true;
134 pr_debug("Failed to load kernel map.\n"); 130
135 return -EINVAL; 131 return ret;
136 }
137 pr_debug("Try to open %s\n", session.kmap->dso->long_name);
138 return open(session.kmap->dso->long_name, O_RDONLY);
139} 132}
140#endif 133#endif
141 134
@@ -144,54 +137,63 @@ static const char * const probe_usage[] = {
144 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 137 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
145 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 138 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
146 "perf probe --list", 139 "perf probe --list",
140#ifdef DWARF_SUPPORT
141 "perf probe --line 'LINEDESC'",
142#endif
147 NULL 143 NULL
148}; 144};
149 145
150static const struct option options[] = { 146static const struct option options[] = {
151 OPT_BOOLEAN('v', "verbose", &verbose, 147 OPT_INCR('v', "verbose", &verbose,
152 "be more verbose (show parsed arguments, etc)"), 148 "be more verbose (show parsed arguments, etc)"),
153#ifndef NO_LIBDWARF 149 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"), 150 "list up current probe events"),
159 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 151 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
160 opt_del_probe_event), 152 opt_del_probe_event),
161 OPT_CALLBACK('a', "add", NULL, 153 OPT_CALLBACK('a', "add", NULL,
162#ifdef NO_LIBDWARF 154#ifdef DWARF_SUPPORT
163 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]", 155 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
156 " [[NAME=]ARG ...]",
164#else 157#else
165 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 158 "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]",
166#endif 159#endif
167 "probe point definition, where\n" 160 "probe point definition, where\n"
168 "\t\tGROUP:\tGroup name (optional)\n" 161 "\t\tGROUP:\tGroup name (optional)\n"
169 "\t\tEVENT:\tEvent name\n" 162 "\t\tEVENT:\tEvent name\n"
170 "\t\tFUNC:\tFunction name\n" 163 "\t\tFUNC:\tFunction name\n"
171 "\t\tOFFS:\tOffset from function entry (in byte)\n" 164 "\t\tOFF:\tOffset from function entry (in byte)\n"
172 "\t\t%return:\tPut the probe at function return\n" 165 "\t\t%return:\tPut the probe at function return\n"
173#ifdef NO_LIBDWARF 166#ifdef DWARF_SUPPORT
174 "\t\tARG:\tProbe argument (only \n"
175#else
176 "\t\tSRC:\tSource code path\n" 167 "\t\tSRC:\tSource code path\n"
177 "\t\tRLN:\tRelative line number from function entry.\n" 168 "\t\tRL:\tRelative line number from function entry.\n"
178 "\t\tALN:\tAbsolute line number in file.\n" 169 "\t\tAL:\tAbsolute line number in file.\n"
170 "\t\tPT:\tLazy expression of line code.\n"
179 "\t\tARG:\tProbe argument (local variable name or\n" 171 "\t\tARG:\tProbe argument (local variable name or\n"
180#endif
181 "\t\t\tkprobe-tracer argument format.)\n", 172 "\t\t\tkprobe-tracer argument format.)\n",
173#else
174 "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
175#endif
182 opt_add_probe_event), 176 opt_add_probe_event),
183 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" 177 OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
184 " with existing name"), 178 " with existing name"),
179#ifdef DWARF_SUPPORT
180 OPT_CALLBACK('L', "line", NULL,
181 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
182 "Show source code lines.", opt_show_lines),
183 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
184 "file", "vmlinux pathname"),
185 OPT_STRING('s', "source", &symbol_conf.source_prefix,
186 "directory", "path to kernel source"),
187#endif
188 OPT__DRY_RUN(&probe_event_dry_run),
189 OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
190 "Set how many probe points can be found for a probe."),
185 OPT_END() 191 OPT_END()
186}; 192};
187 193
188int cmd_probe(int argc, const char **argv, const char *prefix __used) 194int cmd_probe(int argc, const char **argv, const char *prefix __used)
189{ 195{
190 int i, ret; 196 int ret;
191#ifndef NO_LIBDWARF
192 int fd;
193#endif
194 struct probe_point *pp;
195 197
196 argc = parse_options(argc, argv, options, probe_usage, 198 argc = parse_options(argc, argv, options, probe_usage,
197 PARSE_OPT_STOP_AT_NON_OPTION); 199 PARSE_OPT_STOP_AT_NON_OPTION);
@@ -200,110 +202,68 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
200 pr_warning(" Error: '-' is not supported.\n"); 202 pr_warning(" Error: '-' is not supported.\n");
201 usage_with_options(probe_usage, options); 203 usage_with_options(probe_usage, options);
202 } 204 }
203 parse_probe_event_argv(argc, argv); 205 ret = parse_probe_event_argv(argc, argv);
206 if (ret < 0) {
207 pr_err(" Error: Parse Error. (%d)\n", ret);
208 return ret;
209 }
204 } 210 }
205 211
206 if ((!session.nr_probe && !session.dellist && !session.list_events)) 212 if (params.max_probe_points == 0)
207 usage_with_options(probe_usage, options); 213 params.max_probe_points = MAX_PROBES;
208 214
209 if (debugfs_valid_mountpoint(debugfs_path) < 0) 215 if ((!params.nevents && !params.dellist && !params.list_events &&
210 die("Failed to find debugfs path."); 216 !params.show_lines))
217 usage_with_options(probe_usage, options);
211 218
212 if (session.list_events) { 219 if (params.list_events) {
213 if (session.nr_probe != 0 || session.dellist) { 220 if (params.nevents != 0 || params.dellist) {
214 pr_warning(" Error: Don't use --list with" 221 pr_err(" Error: Don't use --list with --add/--del.\n");
215 " --add/--del.\n");
216 usage_with_options(probe_usage, options); 222 usage_with_options(probe_usage, options);
217 } 223 }
218 show_perf_probe_events(); 224 if (params.show_lines) {
219 return 0; 225 pr_err(" Error: Don't use --list with --line.\n");
220 } 226 usage_with_options(probe_usage, options);
221 227 }
222 if (session.dellist) { 228 ret = show_perf_probe_events();
223 del_trace_kprobe_events(session.dellist); 229 if (ret < 0)
224 strlist__delete(session.dellist); 230 pr_err(" Error: Failed to show event list. (%d)\n",
225 if (session.nr_probe == 0) 231 ret);
226 return 0; 232 return ret;
227 } 233 }
228 234
229 /* Initialize symbol maps for vmlinux */ 235#ifdef DWARF_SUPPORT
230 symbol_conf.sort_by_name = true; 236 if (params.show_lines) {
231 if (symbol_conf.vmlinux_name == NULL) 237 if (params.nevents != 0 || params.dellist) {
232 symbol_conf.try_vmlinux_path = true; 238 pr_warning(" Error: Don't use --line with"
233 if (symbol__init() < 0) 239 " --add/--del.\n");
234 die("Failed to init symbol map."); 240 usage_with_options(probe_usage, options);
235 session.psession = perf_session__new(NULL, O_WRONLY, false); 241 }
236 if (session.psession == NULL)
237 die("Failed to init perf_session.");
238 session.kmap = map_groups__find_by_name(&session.psession->kmaps,
239 MAP__FUNCTION,
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 242
255 pr_debug("Could not open vmlinux/module file." 243 ret = show_line_range(&params.line_range);
256 " Try to use symbols.\n"); 244 if (ret < 0)
257 goto end_dwarf; 245 pr_err(" Error: Failed to show lines. (%d)\n", ret);
246 return ret;
258 } 247 }
248#endif
259 249
260 /* Searching probe points */ 250 if (params.dellist) {
261 for (i = 0; i < session.nr_probe; i++) { 251 ret = del_perf_probe_events(params.dellist);
262 pp = &session.probes[i]; 252 strlist__delete(params.dellist);
263 if (pp->found) 253 if (ret < 0) {
264 continue; 254 pr_err(" Error: Failed to delete events. (%d)\n", ret);
265 255 return ret;
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 } 256 }
281 pr_debug("An error occurred in debuginfo analysis."
282 " Try to use symbols.\n");
283 break;
284 } 257 }
285 close(fd);
286 258
287end_dwarf: 259 if (params.nevents) {
288#endif /* !NO_LIBDWARF */ 260 ret = add_perf_probe_events(params.events, params.nevents,
289 261 params.force_add,
290 /* Synthesize probes without dwarf */ 262 params.max_probe_points);
291 for (i = 0; i < session.nr_probe; i++) { 263 if (ret < 0) {
292 pp = &session.probes[i]; 264 pr_err(" Error: Failed to add events. (%d)\n", ret);
293 if (pp->found) /* This probe is already found. */ 265 return ret;
294 continue; 266 }
295
296 evaluate_probe_point(pp);
297 ret = synthesize_trace_kprobe_event(pp);
298 if (ret == -E2BIG)
299 die("probe point definition becomes too long.");
300 else if (ret < 0)
301 die("Failed to synthesize a probe point.");
302 } 267 }
303
304 /* Settng up probe points */
305 add_trace_kprobe_events(session.probes, session.nr_probe,
306 session.force_add);
307 return 0; 268 return 0;
308} 269}
309
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 265425322734..ff77b805de71 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -5,65 +5,76 @@
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"
19#include "util/debug.h" 21#include "util/debug.h"
20#include "util/session.h" 22#include "util/session.h"
21#include "util/symbol.h" 23#include "util/symbol.h"
24#include "util/cpumap.h"
22 25
23#include <unistd.h> 26#include <unistd.h>
24#include <sched.h> 27#include <sched.h>
28#include <sys/mman.h>
29
30enum write_mode_t {
31 WRITE_FORCE,
32 WRITE_APPEND
33};
25 34
26static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 35static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
27 36
28static long default_interval = 0; 37static u64 user_interval = ULLONG_MAX;
38static u64 default_interval = 0;
29 39
30static int nr_cpus = 0; 40static int nr_cpus = 0;
31static unsigned int page_size; 41static unsigned int page_size;
32static unsigned int mmap_pages = 128; 42static unsigned int mmap_pages = 128;
43static unsigned int user_freq = UINT_MAX;
33static int freq = 1000; 44static int freq = 1000;
34static int output; 45static int output;
46static int pipe_output = 0;
35static const char *output_name = "perf.data"; 47static const char *output_name = "perf.data";
36static int group = 0; 48static int group = 0;
37static unsigned int realtime_prio = 0; 49static int realtime_prio = 0;
38static int raw_samples = 0; 50static bool raw_samples = false;
39static int system_wide = 0; 51static bool system_wide = false;
40static int profile_cpu = -1;
41static pid_t target_pid = -1; 52static pid_t target_pid = -1;
53static pid_t target_tid = -1;
54static pid_t *all_tids = NULL;
55static int thread_num = 0;
42static pid_t child_pid = -1; 56static pid_t child_pid = -1;
43static int inherit = 1; 57static bool no_inherit = false;
44static int force = 0; 58static enum write_mode_t write_mode = WRITE_FORCE;
45static int append_file = 0; 59static bool call_graph = false;
46static int call_graph = 0; 60static bool inherit_stat = false;
47static int inherit_stat = 0; 61static bool no_samples = false;
48static int no_samples = 0; 62static bool sample_address = false;
49static int sample_address = 0; 63static bool no_buildid = false;
50static int multiplex = 0;
51static int multiplex_fd = -1;
52 64
53static long samples = 0; 65static long samples = 0;
54static struct timeval last_read;
55static struct timeval this_read;
56
57static u64 bytes_written = 0; 66static u64 bytes_written = 0;
58 67
59static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 68static struct pollfd *event_array;
60 69
61static int nr_poll = 0; 70static int nr_poll = 0;
62static int nr_cpu = 0; 71static int nr_cpu = 0;
63 72
64static int file_new = 1; 73static int file_new = 1;
74static off_t post_processing_offset;
65 75
66static struct perf_session *session; 76static struct perf_session *session;
77static const char *cpu_list;
67 78
68struct mmap_data { 79struct mmap_data {
69 int counter; 80 int counter;
@@ -72,7 +83,7 @@ struct mmap_data {
72 unsigned int prev; 83 unsigned int prev;
73}; 84};
74 85
75static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 86static struct mmap_data mmap_array[MAX_NR_CPUS];
76 87
77static unsigned long mmap_read_head(struct mmap_data *md) 88static unsigned long mmap_read_head(struct mmap_data *md)
78{ 89{
@@ -96,6 +107,11 @@ static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
96 pc->data_tail = tail; 107 pc->data_tail = tail;
97} 108}
98 109
110static void advance_output(size_t size)
111{
112 bytes_written += size;
113}
114
99static void write_output(void *buf, size_t size) 115static void write_output(void *buf, size_t size)
100{ 116{
101 while (size) { 117 while (size) {
@@ -111,22 +127,10 @@ static void write_output(void *buf, size_t size)
111 } 127 }
112} 128}
113 129
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, 130static int process_synthesized_event(event_t *event,
127 struct perf_session *self __used) 131 struct perf_session *self __used)
128{ 132{
129 write_event(event, event->header.size); 133 write_output(event, event->header.size);
130 return 0; 134 return 0;
131} 135}
132 136
@@ -139,8 +143,6 @@ static void mmap_read(struct mmap_data *md)
139 void *buf; 143 void *buf;
140 int diff; 144 int diff;
141 145
142 gettimeofday(&this_read, NULL);
143
144 /* 146 /*
145 * If we're further behind than half the buffer, there's a chance 147 * 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. 148 * the writer will bite our tail and mess up the samples under us.
@@ -151,23 +153,13 @@ static void mmap_read(struct mmap_data *md)
151 */ 153 */
152 diff = head - old; 154 diff = head - old;
153 if (diff < 0) { 155 if (diff < 0) {
154 struct timeval iv; 156 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 /* 157 /*
164 * head points to a known good entry, start there. 158 * head points to a known good entry, start there.
165 */ 159 */
166 old = head; 160 old = head;
167 } 161 }
168 162
169 last_read = this_read;
170
171 if (old != head) 163 if (old != head)
172 samples++; 164 samples++;
173 165
@@ -178,14 +170,14 @@ static void mmap_read(struct mmap_data *md)
178 size = md->mask + 1 - (old & md->mask); 170 size = md->mask + 1 - (old & md->mask);
179 old += size; 171 old += size;
180 172
181 write_event(buf, size); 173 write_output(buf, size);
182 } 174 }
183 175
184 buf = &data[old & md->mask]; 176 buf = &data[old & md->mask];
185 size = head - old; 177 size = head - old;
186 old += size; 178 old += size;
187 179
188 write_event(buf, size); 180 write_output(buf, size);
189 181
190 md->prev = old; 182 md->prev = old;
191 mmap_write_tail(md, old); 183 mmap_write_tail(md, old);
@@ -202,7 +194,7 @@ static void sig_handler(int sig)
202 194
203static void sig_atexit(void) 195static void sig_atexit(void)
204{ 196{
205 if (child_pid != -1) 197 if (child_pid > 0)
206 kill(child_pid, SIGTERM); 198 kill(child_pid, SIGTERM);
207 199
208 if (signr == -1) 200 if (signr == -1)
@@ -232,12 +224,13 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
232 return h_attr; 224 return h_attr;
233} 225}
234 226
235static void create_counter(int counter, int cpu, pid_t pid) 227static void create_counter(int counter, int cpu)
236{ 228{
237 char *filter = filters[counter]; 229 char *filter = filters[counter];
238 struct perf_event_attr *attr = attrs + counter; 230 struct perf_event_attr *attr = attrs + counter;
239 struct perf_header_attr *h_attr; 231 struct perf_header_attr *h_attr;
240 int track = !counter; /* only the first counter needs these */ 232 int track = !counter; /* only the first counter needs these */
233 int thread_index;
241 int ret; 234 int ret;
242 struct { 235 struct {
243 u64 count; 236 u64 count;
@@ -252,10 +245,22 @@ static void create_counter(int counter, int cpu, pid_t pid)
252 245
253 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 246 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID;
254 247
255 if (freq) { 248 if (nr_counters > 1)
256 attr->sample_type |= PERF_SAMPLE_PERIOD; 249 attr->sample_type |= PERF_SAMPLE_ID;
257 attr->freq = 1; 250
258 attr->sample_freq = freq; 251 /*
252 * We default some events to a 1 default interval. But keep
253 * it a weak assumption overridable by the user.
254 */
255 if (!attr->sample_period || (user_freq != UINT_MAX &&
256 user_interval != ULLONG_MAX)) {
257 if (freq) {
258 attr->sample_type |= PERF_SAMPLE_PERIOD;
259 attr->freq = 1;
260 attr->sample_freq = freq;
261 } else {
262 attr->sample_period = default_interval;
263 }
259 } 264 }
260 265
261 if (no_samples) 266 if (no_samples)
@@ -264,12 +269,17 @@ static void create_counter(int counter, int cpu, pid_t pid)
264 if (inherit_stat) 269 if (inherit_stat)
265 attr->inherit_stat = 1; 270 attr->inherit_stat = 1;
266 271
267 if (sample_address) 272 if (sample_address) {
268 attr->sample_type |= PERF_SAMPLE_ADDR; 273 attr->sample_type |= PERF_SAMPLE_ADDR;
274 attr->mmap_data = track;
275 }
269 276
270 if (call_graph) 277 if (call_graph)
271 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 278 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
272 279
280 if (system_wide)
281 attr->sample_type |= PERF_SAMPLE_CPU;
282
273 if (raw_samples) { 283 if (raw_samples) {
274 attr->sample_type |= PERF_SAMPLE_TIME; 284 attr->sample_type |= PERF_SAMPLE_TIME;
275 attr->sample_type |= PERF_SAMPLE_RAW; 285 attr->sample_type |= PERF_SAMPLE_RAW;
@@ -278,146 +288,229 @@ static void create_counter(int counter, int cpu, pid_t pid)
278 288
279 attr->mmap = track; 289 attr->mmap = track;
280 attr->comm = track; 290 attr->comm = track;
281 attr->inherit = inherit; 291 attr->inherit = !no_inherit;
282 attr->disabled = 1; 292 if (target_pid == -1 && target_tid == -1 && !system_wide) {
293 attr->disabled = 1;
294 attr->enable_on_exec = 1;
295 }
283 296
297 for (thread_index = 0; thread_index < thread_num; thread_index++) {
284try_again: 298try_again:
285 fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0); 299 fd[nr_cpu][counter][thread_index] = sys_perf_event_open(attr,
286 300 all_tids[thread_index], cpu, group_fd, 0);
287 if (fd[nr_cpu][counter] < 0) { 301
288 int err = errno; 302 if (fd[nr_cpu][counter][thread_index] < 0) {
289 303 int err = errno;
290 if (err == EPERM || err == EACCES) 304
291 die("Permission error - are you root?\n"); 305 if (err == EPERM || err == EACCES)
292 else if (err == ENODEV && profile_cpu != -1) 306 die("Permission error - are you root?\n"
293 die("No such device - did you specify an out-of-range profile CPU?\n"); 307 "\t Consider tweaking"
308 " /proc/sys/kernel/perf_event_paranoid.\n");
309 else if (err == ENODEV && cpu_list) {
310 die("No such device - did you specify"
311 " an out-of-range profile CPU?\n");
312 }
294 313
295 /* 314 /*
296 * If it's cycles then fall back to hrtimer 315 * If it's cycles then fall back to hrtimer
297 * based cpu-clock-tick sw counter, which 316 * based cpu-clock-tick sw counter, which
298 * is always available even if no PMU support: 317 * is always available even if no PMU support:
299 */ 318 */
300 if (attr->type == PERF_TYPE_HARDWARE 319 if (attr->type == PERF_TYPE_HARDWARE
301 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 320 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
302 321
303 if (verbose) 322 if (verbose)
304 warning(" ... trying to fall back to cpu-clock-ticks\n"); 323 warning(" ... trying to fall back to cpu-clock-ticks\n");
305 attr->type = PERF_TYPE_SOFTWARE; 324 attr->type = PERF_TYPE_SOFTWARE;
306 attr->config = PERF_COUNT_SW_CPU_CLOCK; 325 attr->config = PERF_COUNT_SW_CPU_CLOCK;
307 goto try_again; 326 goto try_again;
308 } 327 }
309 printf("\n"); 328 printf("\n");
310 error("perfcounter syscall returned with %d (%s)\n", 329 error("perfcounter syscall returned with %d (%s)\n",
311 fd[nr_cpu][counter], strerror(err)); 330 fd[nr_cpu][counter][thread_index], strerror(err));
312 331
313#if defined(__i386__) || defined(__x86_64__) 332#if defined(__i386__) || defined(__x86_64__)
314 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) 333 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"); 334 die("No hardware sampling interrupt available."
335 " No APIC? If so then you can boot the kernel"
336 " with the \"lapic\" boot parameter to"
337 " force-enable it.\n");
316#endif 338#endif
317 339
318 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 340 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); 341 exit(-1);
330 } 342 }
331 }
332 343
333 if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) { 344 h_attr = get_header_attr(attr, counter);
334 perror("Unable to read perf file descriptor\n"); 345 if (h_attr == NULL)
335 exit(-1); 346 die("nomem\n");
336 }
337 347
338 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { 348 if (!file_new) {
339 pr_warning("Not enough memory to add id\n"); 349 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
340 exit(-1); 350 fprintf(stderr, "incompatible append\n");
341 } 351 exit(-1);
352 }
353 }
342 354
343 assert(fd[nr_cpu][counter] >= 0); 355 if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) {
344 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 356 perror("Unable to read perf file descriptor\n");
357 exit(-1);
358 }
345 359
346 /* 360 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
347 * First counter acts as the group leader: 361 pr_warning("Not enough memory to add id\n");
348 */ 362 exit(-1);
349 if (group && group_fd == -1) 363 }
350 group_fd = fd[nr_cpu][counter];
351 if (multiplex && multiplex_fd == -1)
352 multiplex_fd = fd[nr_cpu][counter];
353 364
354 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { 365 assert(fd[nr_cpu][counter][thread_index] >= 0);
366 fcntl(fd[nr_cpu][counter][thread_index], F_SETFL, O_NONBLOCK);
355 367
356 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); 368 /*
357 assert(ret != -1); 369 * First counter acts as the group leader:
358 } else { 370 */
359 event_array[nr_poll].fd = fd[nr_cpu][counter]; 371 if (group && group_fd == -1)
360 event_array[nr_poll].events = POLLIN; 372 group_fd = fd[nr_cpu][counter][thread_index];
361 nr_poll++; 373
362 374 if (counter || thread_index) {
363 mmap_array[nr_cpu][counter].counter = counter; 375 ret = ioctl(fd[nr_cpu][counter][thread_index],
364 mmap_array[nr_cpu][counter].prev = 0; 376 PERF_EVENT_IOC_SET_OUTPUT,
365 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; 377 fd[nr_cpu][0][0]);
366 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, 378 if (ret) {
367 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); 379 error("failed to set output: %d (%s)\n", errno,
368 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { 380 strerror(errno));
369 error("failed to mmap with %d (%s)\n", errno, strerror(errno)); 381 exit(-1);
370 exit(-1); 382 }
383 } else {
384 mmap_array[nr_cpu].counter = counter;
385 mmap_array[nr_cpu].prev = 0;
386 mmap_array[nr_cpu].mask = mmap_pages*page_size - 1;
387 mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size,
388 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter][thread_index], 0);
389 if (mmap_array[nr_cpu].base == MAP_FAILED) {
390 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
391 exit(-1);
392 }
393
394 event_array[nr_poll].fd = fd[nr_cpu][counter][thread_index];
395 event_array[nr_poll].events = POLLIN;
396 nr_poll++;
371 } 397 }
372 }
373 398
374 if (filter != NULL) { 399 if (filter != NULL) {
375 ret = ioctl(fd[nr_cpu][counter], 400 ret = ioctl(fd[nr_cpu][counter][thread_index],
376 PERF_EVENT_IOC_SET_FILTER, filter); 401 PERF_EVENT_IOC_SET_FILTER, filter);
377 if (ret) { 402 if (ret) {
378 error("failed to set filter with %d (%s)\n", errno, 403 error("failed to set filter with %d (%s)\n", errno,
379 strerror(errno)); 404 strerror(errno));
380 exit(-1); 405 exit(-1);
406 }
381 } 407 }
382 } 408 }
383
384 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
385} 409}
386 410
387static void open_counters(int cpu, pid_t pid) 411static void open_counters(int cpu)
388{ 412{
389 int counter; 413 int counter;
390 414
391 group_fd = -1; 415 group_fd = -1;
392 for (counter = 0; counter < nr_counters; counter++) 416 for (counter = 0; counter < nr_counters; counter++)
393 create_counter(counter, cpu, pid); 417 create_counter(counter, cpu);
394 418
395 nr_cpu++; 419 nr_cpu++;
396} 420}
397 421
422static int process_buildids(void)
423{
424 u64 size = lseek(output, 0, SEEK_CUR);
425
426 if (size == 0)
427 return 0;
428
429 session->fd = output;
430 return __perf_session__process_events(session, post_processing_offset,
431 size - post_processing_offset,
432 size, &build_id__mark_dso_hit_ops);
433}
434
398static void atexit_header(void) 435static void atexit_header(void)
399{ 436{
400 session->header.data_size += bytes_written; 437 if (!pipe_output) {
438 session->header.data_size += bytes_written;
439
440 process_buildids();
441 perf_header__write(&session->header, output, true);
442 perf_session__delete(session);
443 symbol__exit();
444 }
445}
446
447static void event__synthesize_guest_os(struct machine *machine, void *data)
448{
449 int err;
450 struct perf_session *psession = data;
451
452 if (machine__is_host(machine))
453 return;
454
455 /*
456 *As for guest kernel when processing subcommand record&report,
457 *we arrange module mmap prior to guest kernel mmap and trigger
458 *a preload dso because default guest module symbols are loaded
459 *from guest kallsyms instead of /lib/modules/XXX/XXX. This
460 *method is used to avoid symbol missing when the first addr is
461 *in module instead of in guest kernel.
462 */
463 err = event__synthesize_modules(process_synthesized_event,
464 psession, machine);
465 if (err < 0)
466 pr_err("Couldn't record guest kernel [%d]'s reference"
467 " relocation symbol.\n", machine->pid);
468
469 /*
470 * We use _stext for guest kernel because guest kernel's /proc/kallsyms
471 * have no _text sometimes.
472 */
473 err = event__synthesize_kernel_mmap(process_synthesized_event,
474 psession, machine, "_text");
475 if (err < 0)
476 err = event__synthesize_kernel_mmap(process_synthesized_event,
477 psession, machine, "_stext");
478 if (err < 0)
479 pr_err("Couldn't record guest kernel [%d]'s reference"
480 " relocation symbol.\n", machine->pid);
481}
482
483static struct perf_event_header finished_round_event = {
484 .size = sizeof(struct perf_event_header),
485 .type = PERF_RECORD_FINISHED_ROUND,
486};
487
488static void mmap_read_all(void)
489{
490 int i;
491
492 for (i = 0; i < nr_cpu; i++) {
493 if (mmap_array[i].base)
494 mmap_read(&mmap_array[i]);
495 }
401 496
402 perf_header__write(&session->header, output, true); 497 if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO))
498 write_output(&finished_round_event, sizeof(finished_round_event));
403} 499}
404 500
405static int __cmd_record(int argc, const char **argv) 501static int __cmd_record(int argc, const char **argv)
406{ 502{
407 int i, counter; 503 int i, counter;
408 struct stat st; 504 struct stat st;
409 pid_t pid = 0;
410 int flags; 505 int flags;
411 int err; 506 int err;
412 unsigned long waking = 0; 507 unsigned long waking = 0;
413 int child_ready_pipe[2], go_pipe[2]; 508 int child_ready_pipe[2], go_pipe[2];
414 const bool forks = target_pid == -1 && argc > 0; 509 const bool forks = argc > 0;
415 char buf; 510 char buf;
511 struct machine *machine;
416 512
417 page_size = sysconf(_SC_PAGE_SIZE); 513 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 514
422 atexit(sig_atexit); 515 atexit(sig_atexit);
423 signal(SIGCHLD, sig_handler); 516 signal(SIGCHLD, sig_handler);
@@ -428,70 +521,66 @@ static int __cmd_record(int argc, const char **argv)
428 exit(-1); 521 exit(-1);
429 } 522 }
430 523
431 if (!stat(output_name, &st) && st.st_size) { 524 if (!strcmp(output_name, "-"))
432 if (!force) { 525 pipe_output = 1;
433 if (!append_file) { 526 else if (!stat(output_name, &st) && st.st_size) {
434 pr_err("Error, output file %s exists, use -A " 527 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]; 528 char oldname[PATH_MAX];
441 snprintf(oldname, sizeof(oldname), "%s.old", 529 snprintf(oldname, sizeof(oldname), "%s.old",
442 output_name); 530 output_name);
443 unlink(oldname); 531 unlink(oldname);
444 rename(output_name, oldname); 532 rename(output_name, oldname);
445 } 533 }
446 } else { 534 } else if (write_mode == WRITE_APPEND) {
447 append_file = 0; 535 write_mode = WRITE_FORCE;
448 } 536 }
449 537
450 flags = O_CREAT|O_RDWR; 538 flags = O_CREAT|O_RDWR;
451 if (append_file) 539 if (write_mode == WRITE_APPEND)
452 file_new = 0; 540 file_new = 0;
453 else 541 else
454 flags |= O_TRUNC; 542 flags |= O_TRUNC;
455 543
456 output = open(output_name, flags, S_IRUSR|S_IWUSR); 544 if (pipe_output)
545 output = STDOUT_FILENO;
546 else
547 output = open(output_name, flags, S_IRUSR | S_IWUSR);
457 if (output < 0) { 548 if (output < 0) {
458 perror("failed to create output file"); 549 perror("failed to create output file");
459 exit(-1); 550 exit(-1);
460 } 551 }
461 552
462 session = perf_session__new(output_name, O_WRONLY, force); 553 session = perf_session__new(output_name, O_WRONLY,
554 write_mode == WRITE_FORCE, false);
463 if (session == NULL) { 555 if (session == NULL) {
464 pr_err("Not enough memory for reading perf file header\n"); 556 pr_err("Not enough memory for reading perf file header\n");
465 return -1; 557 return -1;
466 } 558 }
467 559
468 if (!file_new) { 560 if (!file_new) {
469 err = perf_header__read(&session->header, output); 561 err = perf_header__read(session, output);
470 if (err < 0) 562 if (err < 0)
471 return err; 563 goto out_delete_session;
472 } 564 }
473 565
474 if (raw_samples) { 566 if (have_tracepoints(attrs, nr_counters))
475 perf_header__set_feat(&session->header, HEADER_TRACE_INFO); 567 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 568
569 /*
570 * perf_session__delete(session) will be called at atexit_header()
571 */
485 atexit(atexit_header); 572 atexit(atexit_header);
486 573
487 if (forks) { 574 if (forks) {
488 pid = fork(); 575 child_pid = fork();
489 if (pid < 0) { 576 if (child_pid < 0) {
490 perror("failed to fork"); 577 perror("failed to fork");
491 exit(-1); 578 exit(-1);
492 } 579 }
493 580
494 if (!pid) { 581 if (!child_pid) {
582 if (pipe_output)
583 dup2(2, 1);
495 close(child_ready_pipe[0]); 584 close(child_ready_pipe[0]);
496 close(go_pipe[1]); 585 close(go_pipe[1]);
497 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); 586 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
@@ -520,10 +609,8 @@ static int __cmd_record(int argc, const char **argv)
520 exit(-1); 609 exit(-1);
521 } 610 }
522 611
523 child_pid = pid; 612 if (!system_wide && target_tid == -1 && target_pid == -1)
524 613 all_tids[0] = child_pid;
525 if (!system_wide)
526 target_pid = pid;
527 614
528 close(child_ready_pipe[1]); 615 close(child_ready_pipe[1]);
529 close(go_pipe[0]); 616 close(go_pipe[0]);
@@ -537,22 +624,95 @@ static int __cmd_record(int argc, const char **argv)
537 close(child_ready_pipe[0]); 624 close(child_ready_pipe[0]);
538 } 625 }
539 626
627 nr_cpus = read_cpu_map(cpu_list);
628 if (nr_cpus < 1) {
629 perror("failed to collect number of CPUs\n");
630 return -1;
631 }
540 632
541 if ((!system_wide && !inherit) || profile_cpu != -1) { 633 if (!system_wide && no_inherit && !cpu_list) {
542 open_counters(profile_cpu, target_pid); 634 open_counters(-1);
543 } else { 635 } else {
544 for (i = 0; i < nr_cpus; i++) 636 for (i = 0; i < nr_cpus; i++)
545 open_counters(i, target_pid); 637 open_counters(cpumap[i]);
546 } 638 }
547 639
548 if (file_new) { 640 if (pipe_output) {
641 err = perf_header__write_pipe(output);
642 if (err < 0)
643 return err;
644 } else if (file_new) {
549 err = perf_header__write(&session->header, output, false); 645 err = perf_header__write(&session->header, output, false);
550 if (err < 0) 646 if (err < 0)
551 return err; 647 return err;
552 } 648 }
553 649
554 if (!system_wide && profile_cpu == -1) 650 post_processing_offset = lseek(output, 0, SEEK_CUR);
555 event__synthesize_thread(pid, process_synthesized_event, 651
652 if (pipe_output) {
653 err = event__synthesize_attrs(&session->header,
654 process_synthesized_event,
655 session);
656 if (err < 0) {
657 pr_err("Couldn't synthesize attrs.\n");
658 return err;
659 }
660
661 err = event__synthesize_event_types(process_synthesized_event,
662 session);
663 if (err < 0) {
664 pr_err("Couldn't synthesize event_types.\n");
665 return err;
666 }
667
668 if (have_tracepoints(attrs, nr_counters)) {
669 /*
670 * FIXME err <= 0 here actually means that
671 * there were no tracepoints so its not really
672 * an error, just that we don't need to
673 * synthesize anything. We really have to
674 * return this more properly and also
675 * propagate errors that now are calling die()
676 */
677 err = event__synthesize_tracing_data(output, attrs,
678 nr_counters,
679 process_synthesized_event,
680 session);
681 if (err <= 0) {
682 pr_err("Couldn't record tracing data.\n");
683 return err;
684 }
685 advance_output(err);
686 }
687 }
688
689 machine = perf_session__find_host_machine(session);
690 if (!machine) {
691 pr_err("Couldn't find native kernel information.\n");
692 return -1;
693 }
694
695 err = event__synthesize_kernel_mmap(process_synthesized_event,
696 session, machine, "_text");
697 if (err < 0)
698 err = event__synthesize_kernel_mmap(process_synthesized_event,
699 session, machine, "_stext");
700 if (err < 0) {
701 pr_err("Couldn't record kernel reference relocation symbol.\n");
702 return err;
703 }
704
705 err = event__synthesize_modules(process_synthesized_event,
706 session, machine);
707 if (err < 0) {
708 pr_err("Couldn't record kernel reference relocation symbol.\n");
709 return err;
710 }
711 if (perf_guest)
712 perf_session__process_machines(session, event__synthesize_guest_os);
713
714 if (!system_wide)
715 event__synthesize_thread(target_tid, process_synthesized_event,
556 session); 716 session);
557 else 717 else
558 event__synthesize_threads(process_synthesized_event, session); 718 event__synthesize_threads(process_synthesized_event, session);
@@ -575,13 +735,9 @@ static int __cmd_record(int argc, const char **argv)
575 735
576 for (;;) { 736 for (;;) {
577 int hits = samples; 737 int hits = samples;
738 int thread;
578 739
579 for (i = 0; i < nr_cpu; i++) { 740 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 741
586 if (hits == samples) { 742 if (hits == samples) {
587 if (done) 743 if (done)
@@ -592,8 +748,15 @@ static int __cmd_record(int argc, const char **argv)
592 748
593 if (done) { 749 if (done) {
594 for (i = 0; i < nr_cpu; i++) { 750 for (i = 0; i < nr_cpu; i++) {
595 for (counter = 0; counter < nr_counters; counter++) 751 for (counter = 0;
596 ioctl(fd[i][counter], PERF_EVENT_IOC_DISABLE); 752 counter < nr_counters;
753 counter++) {
754 for (thread = 0;
755 thread < thread_num;
756 thread++)
757 ioctl(fd[i][counter][thread],
758 PERF_EVENT_IOC_DISABLE);
759 }
597 } 760 }
598 } 761 }
599 } 762 }
@@ -610,6 +773,10 @@ static int __cmd_record(int argc, const char **argv)
610 bytes_written / 24); 773 bytes_written / 24);
611 774
612 return 0; 775 return 0;
776
777out_delete_session:
778 perf_session__delete(session);
779 return err;
613} 780}
614 781
615static const char * const record_usage[] = { 782static const char * const record_usage[] = {
@@ -618,6 +785,8 @@ static const char * const record_usage[] = {
618 NULL 785 NULL
619}; 786};
620 787
788static bool force, append_file;
789
621static const struct option options[] = { 790static const struct option options[] = {
622 OPT_CALLBACK('e', "event", NULL, "event", 791 OPT_CALLBACK('e', "event", NULL, "event",
623 "event selector. use 'perf list' to list available events", 792 "event selector. use 'perf list' to list available events",
@@ -625,7 +794,9 @@ static const struct option options[] = {
625 OPT_CALLBACK(0, "filter", NULL, "filter", 794 OPT_CALLBACK(0, "filter", NULL, "filter",
626 "event filter", parse_filter), 795 "event filter", parse_filter),
627 OPT_INTEGER('p', "pid", &target_pid, 796 OPT_INTEGER('p', "pid", &target_pid,
628 "record events on existing pid"), 797 "record events on existing process id"),
798 OPT_INTEGER('t', "tid", &target_tid,
799 "record events on existing thread id"),
629 OPT_INTEGER('r', "realtime", &realtime_prio, 800 OPT_INTEGER('r', "realtime", &realtime_prio,
630 "collect data with this RT SCHED_FIFO priority"), 801 "collect data with this RT SCHED_FIFO priority"),
631 OPT_BOOLEAN('R', "raw-samples", &raw_samples, 802 OPT_BOOLEAN('R', "raw-samples", &raw_samples,
@@ -634,23 +805,20 @@ static const struct option options[] = {
634 "system-wide collection from all CPUs"), 805 "system-wide collection from all CPUs"),
635 OPT_BOOLEAN('A', "append", &append_file, 806 OPT_BOOLEAN('A', "append", &append_file,
636 "append to the output file to do incremental profiling"), 807 "append to the output file to do incremental profiling"),
637 OPT_INTEGER('C', "profile_cpu", &profile_cpu, 808 OPT_STRING('C', "cpu", &cpu_list, "cpu",
638 "CPU to profile on"), 809 "list of cpus to monitor"),
639 OPT_BOOLEAN('f', "force", &force, 810 OPT_BOOLEAN('f', "force", &force,
640 "overwrite existing data file"), 811 "overwrite existing data file (deprecated)"),
641 OPT_LONG('c', "count", &default_interval, 812 OPT_U64('c', "count", &user_interval, "event period to sample"),
642 "event period to sample"),
643 OPT_STRING('o', "output", &output_name, "file", 813 OPT_STRING('o', "output", &output_name, "file",
644 "output file name"), 814 "output file name"),
645 OPT_BOOLEAN('i', "inherit", &inherit, 815 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
646 "child tasks inherit counters"), 816 "child tasks do not inherit counters"),
647 OPT_INTEGER('F', "freq", &freq, 817 OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
648 "profile at this frequency"), 818 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, 819 OPT_BOOLEAN('g', "call-graph", &call_graph,
652 "do call-graph (stack chain/backtrace) recording"), 820 "do call-graph (stack chain/backtrace) recording"),
653 OPT_BOOLEAN('v', "verbose", &verbose, 821 OPT_INCR('v', "verbose", &verbose,
654 "be more verbose (show counter open errors, etc)"), 822 "be more verbose (show counter open errors, etc)"),
655 OPT_BOOLEAN('s', "stat", &inherit_stat, 823 OPT_BOOLEAN('s', "stat", &inherit_stat,
656 "per thread counts"), 824 "per thread counts"),
@@ -658,21 +826,34 @@ static const struct option options[] = {
658 "Sample addresses"), 826 "Sample addresses"),
659 OPT_BOOLEAN('n', "no-samples", &no_samples, 827 OPT_BOOLEAN('n', "no-samples", &no_samples,
660 "don't sample"), 828 "don't sample"),
661 OPT_BOOLEAN('M', "multiplex", &multiplex, 829 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid,
662 "multiplex counter output in a single channel"), 830 "do not update the buildid cache"),
663 OPT_END() 831 OPT_END()
664}; 832};
665 833
666int cmd_record(int argc, const char **argv, const char *prefix __used) 834int cmd_record(int argc, const char **argv, const char *prefix __used)
667{ 835{
668 int counter; 836 int i, j, err = -ENOMEM;
669 837
670 argc = parse_options(argc, argv, options, record_usage, 838 argc = parse_options(argc, argv, options, record_usage,
671 PARSE_OPT_STOP_AT_NON_OPTION); 839 PARSE_OPT_STOP_AT_NON_OPTION);
672 if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1) 840 if (!argc && target_pid == -1 && target_tid == -1 &&
841 !system_wide && !cpu_list)
673 usage_with_options(record_usage, options); 842 usage_with_options(record_usage, options);
674 843
844 if (force && append_file) {
845 fprintf(stderr, "Can't overwrite and append at the same time."
846 " You need to choose between -f and -A");
847 usage_with_options(record_usage, options);
848 } else if (append_file) {
849 write_mode = WRITE_APPEND;
850 } else {
851 write_mode = WRITE_FORCE;
852 }
853
675 symbol__init(); 854 symbol__init();
855 if (no_buildid)
856 disable_buildid_cache();
676 857
677 if (!nr_counters) { 858 if (!nr_counters) {
678 nr_counters = 1; 859 nr_counters = 1;
@@ -680,6 +861,40 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
680 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 861 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
681 } 862 }
682 863
864 if (target_pid != -1) {
865 target_tid = target_pid;
866 thread_num = find_all_tid(target_pid, &all_tids);
867 if (thread_num <= 0) {
868 fprintf(stderr, "Can't find all threads of pid %d\n",
869 target_pid);
870 usage_with_options(record_usage, options);
871 }
872 } else {
873 all_tids=malloc(sizeof(pid_t));
874 if (!all_tids)
875 goto out_symbol_exit;
876
877 all_tids[0] = target_tid;
878 thread_num = 1;
879 }
880
881 for (i = 0; i < MAX_NR_CPUS; i++) {
882 for (j = 0; j < MAX_COUNTERS; j++) {
883 fd[i][j] = malloc(sizeof(int)*thread_num);
884 if (!fd[i][j])
885 goto out_free_fd;
886 }
887 }
888 event_array = malloc(
889 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
890 if (!event_array)
891 goto out_free_fd;
892
893 if (user_interval != ULLONG_MAX)
894 default_interval = user_interval;
895 if (user_freq != UINT_MAX)
896 freq = user_freq;
897
683 /* 898 /*
684 * User specified count overrides default frequency. 899 * User specified count overrides default frequency.
685 */ 900 */
@@ -689,15 +904,22 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
689 default_interval = freq; 904 default_interval = freq;
690 } else { 905 } else {
691 fprintf(stderr, "frequency and count are zero, aborting\n"); 906 fprintf(stderr, "frequency and count are zero, aborting\n");
692 exit(EXIT_FAILURE); 907 err = -EINVAL;
908 goto out_free_event_array;
693 } 909 }
694 910
695 for (counter = 0; counter < nr_counters; counter++) { 911 err = __cmd_record(argc, argv);
696 if (attrs[counter].sample_period)
697 continue;
698 912
699 attrs[counter].sample_period = default_interval; 913out_free_event_array:
914 free(event_array);
915out_free_fd:
916 for (i = 0; i < MAX_NR_CPUS; i++) {
917 for (j = 0; j < MAX_COUNTERS; j++)
918 free(fd[i][j]);
700 } 919 }
701 920 free(all_tids);
702 return __cmd_record(argc, argv); 921 all_tids = NULL;
922out_symbol_exit:
923 symbol__exit();
924 return err;
703} 925}
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index db10c0e8ecae..55fc1f46892a 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,54 +32,120 @@
33 32
34static char const *input_name = "perf.data"; 33static char const *input_name = "perf.data";
35 34
36static int force; 35static bool force;
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 = append_chain(he->callchain, data->callchain, syms, data->period);
66 callchain_init(&he->callchain); 111 if (err)
67 append_chain(&he->callchain, chain, syms); 112 goto out_free_syms;
68 free(syms);
69 } 113 }
70 114 /*
71 return 0; 115 * Only in the newt browser we are doing integrated annotation,
116 * so we don't allocated the extra space needed because the stdio
117 * code will not use it.
118 */
119 if (use_browser > 0)
120 err = hist_entry__inc_addr_samples(he, al->addr);
121out_free_syms:
122 free(syms);
123 return err;
72} 124}
73 125
74static int validate_chain(struct ip_callchain *chain, event_t *event) 126static int add_event_total(struct perf_session *session,
127 struct sample_data *data,
128 struct perf_event_attr *attr)
75{ 129{
76 unsigned int chain_size; 130 struct hists *hists;
77 131
78 chain_size = event->header.size; 132 if (attr)
79 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; 133 hists = perf_session__hists_findnew(session, data->id,
134 attr->type, attr->config);
135 else
136 hists = perf_session__hists_findnew(session, data->id, 0, 0);
80 137
81 if (chain->nr*sizeof(u64) > chain_size) 138 if (!hists)
82 return -1; 139 return -ENOMEM;
83 140
141 hists->stats.total_period += data->period;
142 /*
143 * FIXME: add_event_total should be moved from here to
144 * perf_session__process_event so that the proper hist is passed to
145 * the event_op methods.
146 */
147 hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
148 session->hists.stats.total_period += data->period;
84 return 0; 149 return 0;
85} 150}
86 151
@@ -88,48 +153,29 @@ static int process_sample_event(event_t *event, struct perf_session *session)
88{ 153{
89 struct sample_data data = { .period = 1, }; 154 struct sample_data data = { .period = 1, };
90 struct addr_location al; 155 struct addr_location al;
156 struct perf_event_attr *attr;
91 157
92 event__parse_sample(event, session->sample_type, &data); 158 if (event__preprocess_sample(event, session, &al, &data, 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", 159 fprintf(stderr, "problem processing %d event, skipping it.\n",
120 event->header.type); 160 event->header.type);
121 return -1; 161 return -1;
122 } 162 }
123 163
124 if (al.filtered) 164 if (al.filtered || (hide_unresolved && al.sym == NULL))
125 return 0; 165 return 0;
126 166
127 if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { 167 if (perf_session__add_hist_entry(session, &al, &data)) {
128 pr_debug("problem incrementing symbol count, skipping event\n"); 168 pr_debug("problem incrementing symbol period, skipping event\n");
169 return -1;
170 }
171
172 attr = perf_header__find_attr(data.id, &session->header);
173
174 if (add_event_total(session, &data, attr)) {
175 pr_debug("problem adding event period\n");
129 return -1; 176 return -1;
130 } 177 }
131 178
132 session->events_stats.total += data.period;
133 return 0; 179 return 0;
134} 180}
135 181
@@ -156,14 +202,14 @@ static int process_read_event(event_t *event, struct perf_session *session __use
156 return 0; 202 return 0;
157} 203}
158 204
159static int sample_type_check(struct perf_session *session) 205static int perf_session__setup_sample_type(struct perf_session *self)
160{ 206{
161 if (!(session->sample_type & PERF_SAMPLE_CALLCHAIN)) { 207 if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
162 if (sort__has_parent) { 208 if (sort__has_parent) {
163 fprintf(stderr, "selected --sort parent, but no" 209 fprintf(stderr, "selected --sort parent, but no"
164 " callchain data. Did you call" 210 " callchain data. Did you call"
165 " perf record without -g?\n"); 211 " perf record without -g?\n");
166 return -1; 212 return -EINVAL;
167 } 213 }
168 if (symbol_conf.use_callchain) { 214 if (symbol_conf.use_callchain) {
169 fprintf(stderr, "selected -g but no callchain data." 215 fprintf(stderr, "selected -g but no callchain data."
@@ -171,12 +217,13 @@ static int sample_type_check(struct perf_session *session)
171 " -g?\n"); 217 " -g?\n");
172 return -1; 218 return -1;
173 } 219 }
174 } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { 220 } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
221 !symbol_conf.use_callchain) {
175 symbol_conf.use_callchain = true; 222 symbol_conf.use_callchain = true;
176 if (register_callchain_param(&callchain_param) < 0) { 223 if (register_callchain_param(&callchain_param) < 0) {
177 fprintf(stderr, "Can't register callchain" 224 fprintf(stderr, "Can't register callchain"
178 " params\n"); 225 " params\n");
179 return -1; 226 return -EINVAL;
180 } 227 }
181 } 228 }
182 229
@@ -184,35 +231,98 @@ static int sample_type_check(struct perf_session *session)
184} 231}
185 232
186static struct perf_event_ops event_ops = { 233static struct perf_event_ops event_ops = {
187 .process_sample_event = process_sample_event, 234 .sample = process_sample_event,
188 .process_mmap_event = event__process_mmap, 235 .mmap = event__process_mmap,
189 .process_comm_event = event__process_comm, 236 .comm = event__process_comm,
190 .process_exit_event = event__process_task, 237 .exit = event__process_task,
191 .process_fork_event = event__process_task, 238 .fork = event__process_task,
192 .process_lost_event = event__process_lost, 239 .lost = event__process_lost,
193 .process_read_event = process_read_event, 240 .read = process_read_event,
194 .sample_type_check = sample_type_check, 241 .attr = event__process_attr,
242 .event_type = event__process_event_type,
243 .tracing_data = event__process_tracing_data,
244 .build_id = event__process_build_id,
195}; 245};
196 246
247extern volatile int session_done;
248
249static void sig_handler(int sig __used)
250{
251 session_done = 1;
252}
253
254static size_t hists__fprintf_nr_sample_events(struct hists *self,
255 const char *evname, FILE *fp)
256{
257 size_t ret;
258 char unit;
259 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
260
261 nr_events = convert_unit(nr_events, &unit);
262 ret = fprintf(fp, "# Events: %lu%c", nr_events, unit);
263 if (evname != NULL)
264 ret += fprintf(fp, " %s", evname);
265 return ret + fprintf(fp, "\n#\n");
266}
267
268static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
269{
270 struct rb_node *next = rb_first(tree);
271
272 while (next) {
273 struct hists *hists = rb_entry(next, struct hists, rb_node);
274 const char *evname = NULL;
275
276 if (rb_first(&hists->entries) != rb_last(&hists->entries))
277 evname = __event_name(hists->type, hists->config);
278
279 hists__fprintf_nr_sample_events(hists, evname, stdout);
280 hists__fprintf(hists, NULL, false, stdout);
281 fprintf(stdout, "\n\n");
282 next = rb_next(&hists->rb_node);
283 }
284
285 if (sort_order == default_sort_order &&
286 parent_pattern == default_parent_pattern) {
287 fprintf(stdout, "#\n# (%s)\n#\n", help);
288
289 if (show_threads) {
290 bool style = !strcmp(pretty_printing_style, "raw");
291 perf_read_values_display(stdout, &show_threads_values,
292 style);
293 perf_read_values_destroy(&show_threads_values);
294 }
295 }
296
297 return 0;
298}
197 299
198static int __cmd_report(void) 300static int __cmd_report(void)
199{ 301{
200 int ret; 302 int ret = -EINVAL;
201 struct perf_session *session; 303 struct perf_session *session;
304 struct rb_node *next;
305 const char *help = "For a higher level overview, try: perf report --sort comm,dso";
306
307 signal(SIGINT, sig_handler);
202 308
203 session = perf_session__new(input_name, O_RDONLY, force); 309 session = perf_session__new(input_name, O_RDONLY, force, false);
204 if (session == NULL) 310 if (session == NULL)
205 return -ENOMEM; 311 return -ENOMEM;
206 312
207 if (show_threads) 313 if (show_threads)
208 perf_read_values_init(&show_threads_values); 314 perf_read_values_init(&show_threads_values);
209 315
316 ret = perf_session__setup_sample_type(session);
317 if (ret)
318 goto out_delete;
319
210 ret = perf_session__process_events(session, &event_ops); 320 ret = perf_session__process_events(session, &event_ops);
211 if (ret) 321 if (ret)
212 goto out_delete; 322 goto out_delete;
213 323
214 if (dump_trace) { 324 if (dump_trace) {
215 event__print_totals(); 325 perf_session__fprintf_nr_events(session, stdout);
216 goto out_delete; 326 goto out_delete;
217 } 327 }
218 328
@@ -220,34 +330,54 @@ static int __cmd_report(void)
220 perf_session__fprintf(session, stdout); 330 perf_session__fprintf(session, stdout);
221 331
222 if (verbose > 2) 332 if (verbose > 2)
223 dsos__fprintf(stdout); 333 perf_session__fprintf_dsos(session, stdout);
224 334
225 perf_session__collapse_resort(session); 335 next = rb_first(&session->hists_tree);
226 perf_session__output_resort(session, session->events_stats.total); 336 while (next) {
227 fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total); 337 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 338
233 if (show_threads) { 339 hists = rb_entry(next, struct hists, rb_node);
234 bool raw_printing_style = !strcmp(pretty_printing_style, "raw"); 340 hists__collapse_resort(hists);
235 perf_read_values_display(stdout, &show_threads_values, 341 hists__output_resort(hists);
236 raw_printing_style); 342 next = rb_next(&hists->rb_node);
237 perf_read_values_destroy(&show_threads_values);
238 } 343 }
344
345 if (use_browser > 0)
346 hists__tui_browse_tree(&session->hists_tree, help);
347 else
348 hists__tty_browse_tree(&session->hists_tree, help);
349
239out_delete: 350out_delete:
240 perf_session__delete(session); 351 /*
352 * Speed up the exit process, for large files this can
353 * take quite a while.
354 *
355 * XXX Enable this when using valgrind or if we ever
356 * librarize this command.
357 *
358 * Also experiment with obstacks to see how much speed
359 * up we'll get here.
360 *
361 * perf_session__delete(session);
362 */
241 return ret; 363 return ret;
242} 364}
243 365
244static int 366static int
245parse_callchain_opt(const struct option *opt __used, const char *arg, 367parse_callchain_opt(const struct option *opt __used, const char *arg,
246 int unset __used) 368 int unset)
247{ 369{
248 char *tok; 370 char *tok, *tok2;
249 char *endptr; 371 char *endptr;
250 372
373 /*
374 * --no-call-graph
375 */
376 if (unset) {
377 dont_use_callchains = true;
378 return 0;
379 }
380
251 symbol_conf.use_callchain = true; 381 symbol_conf.use_callchain = true;
252 382
253 if (!arg) 383 if (!arg)
@@ -269,7 +399,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
269 399
270 else if (!strncmp(tok, "none", strlen(arg))) { 400 else if (!strncmp(tok, "none", strlen(arg))) {
271 callchain_param.mode = CHAIN_NONE; 401 callchain_param.mode = CHAIN_NONE;
272 symbol_conf.use_callchain = true; 402 symbol_conf.use_callchain = false;
273 403
274 return 0; 404 return 0;
275 } 405 }
@@ -282,10 +412,13 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
282 if (!tok) 412 if (!tok)
283 goto setup; 413 goto setup;
284 414
415 tok2 = strtok(NULL, ",");
285 callchain_param.min_percent = strtod(tok, &endptr); 416 callchain_param.min_percent = strtod(tok, &endptr);
286 if (tok == endptr) 417 if (tok == endptr)
287 return -1; 418 return -1;
288 419
420 if (tok2)
421 callchain_param.print_limit = strtod(tok2, &endptr);
289setup: 422setup:
290 if (register_callchain_param(&callchain_param) < 0) { 423 if (register_callchain_param(&callchain_param) < 0) {
291 fprintf(stderr, "Can't register callchain params\n"); 424 fprintf(stderr, "Can't register callchain params\n");
@@ -302,7 +435,7 @@ static const char * const report_usage[] = {
302static const struct option options[] = { 435static const struct option options[] = {
303 OPT_STRING('i', "input", &input_name, "file", 436 OPT_STRING('i', "input", &input_name, "file",
304 "input file name"), 437 "input file name"),
305 OPT_BOOLEAN('v', "verbose", &verbose, 438 OPT_INCR('v', "verbose", &verbose,
306 "be more verbose (show symbol address, etc)"), 439 "be more verbose (show symbol address, etc)"),
307 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 440 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
308 "dump raw trace in ASCII"), 441 "dump raw trace in ASCII"),
@@ -319,14 +452,14 @@ static const struct option options[] = {
319 "pretty printing style key: normal raw"), 452 "pretty printing style key: normal raw"),
320 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 453 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
321 "sort by key(s): pid, comm, dso, symbol, parent"), 454 "sort by key(s): pid, comm, dso, symbol, parent"),
322 OPT_BOOLEAN('P', "full-paths", &event_ops.full_paths, 455 OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
323 "Don't shorten the pathnames taking into account the cwd"), 456 "Show sample percentage for different cpu modes"),
324 OPT_STRING('p', "parent", &parent_pattern, "regex", 457 OPT_STRING('p', "parent", &parent_pattern, "regex",
325 "regex filter to identify parent, see: '--sort parent'"), 458 "regex filter to identify parent, see: '--sort parent'"),
326 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 459 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
327 "Only display entries with parent-match"), 460 "Only display entries with parent-match"),
328 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 461 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
329 "Display callchains using output_type and min percent threshold. " 462 "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), 463 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
331 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", 464 OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
332 "only consider symbols in these dsos"), 465 "only consider symbols in these dsos"),
@@ -340,6 +473,8 @@ static const struct option options[] = {
340 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", 473 OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
341 "separator for columns, no spaces will be added between " 474 "separator for columns, no spaces will be added between "
342 "columns '.' is reserved."), 475 "columns '.' is reserved."),
476 OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved,
477 "Only display entries resolved to a symbol"),
343 OPT_END() 478 OPT_END()
344}; 479};
345 480
@@ -347,7 +482,31 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
347{ 482{
348 argc = parse_options(argc, argv, options, report_usage, 0); 483 argc = parse_options(argc, argv, options, report_usage, 0);
349 484
350 setup_pager(); 485 if (strcmp(input_name, "-") != 0)
486 setup_browser();
487 /*
488 * Only in the newt browser we are doing integrated annotation,
489 * so don't allocate extra space that won't be used in the stdio
490 * implementation.
491 */
492 if (use_browser > 0) {
493 symbol_conf.priv_size = sizeof(struct sym_priv);
494 /*
495 * For searching by name on the "Browse map details".
496 * providing it only in verbose mode not to bloat too
497 * much struct symbol.
498 */
499 if (verbose) {
500 /*
501 * XXX: Need to provide a less kludgy way to ask for
502 * more space per symbol, the u32 is for the index on
503 * the ui browser.
504 * See symbol__browser_index.
505 */
506 symbol_conf.priv_size += sizeof(u32);
507 symbol_conf.sort_by_name = true;
508 }
509 }
351 510
352 if (symbol__init() < 0) 511 if (symbol__init() < 0)
353 return -1; 512 return -1;
@@ -355,7 +514,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
355 setup_sorting(report_usage, options); 514 setup_sorting(report_usage, options);
356 515
357 if (parent_pattern != default_parent_pattern) { 516 if (parent_pattern != default_parent_pattern) {
358 sort_dimension__add("parent"); 517 if (sort_dimension__add("parent") < 0)
518 return -1;
359 sort_parent.elide = 1; 519 sort_parent.elide = 1;
360 } else 520 } else
361 symbol_conf.exclude_other = false; 521 symbol_conf.exclude_other = false;
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 80209df6cfe8..55f3b5dcc731 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;
@@ -1621,11 +1621,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
1621 1621
1622 event__parse_sample(event, session->sample_type, &data); 1622 event__parse_sample(event, session->sample_type, &data);
1623 1623
1624 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 1624 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
1625 event->header.misc, 1625 data.pid, data.tid, data.ip, data.period);
1626 data.pid, data.tid,
1627 (void *)(long)data.ip,
1628 (long long)data.period);
1629 1626
1630 thread = perf_session__findnew(session, data.pid); 1627 thread = perf_session__findnew(session, data.pid);
1631 if (thread == NULL) { 1628 if (thread == NULL) {
@@ -1644,42 +1641,28 @@ static int process_sample_event(event_t *event, struct perf_session *session)
1644 return 0; 1641 return 0;
1645} 1642}
1646 1643
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
1665 return 0;
1666}
1667
1668static struct perf_event_ops event_ops = { 1644static struct perf_event_ops event_ops = {
1669 .process_sample_event = process_sample_event, 1645 .sample = process_sample_event,
1670 .process_comm_event = event__process_comm, 1646 .comm = event__process_comm,
1671 .process_lost_event = process_lost_event, 1647 .lost = event__process_lost,
1672 .sample_type_check = sample_type_check, 1648 .fork = event__process_task,
1649 .ordered_samples = true,
1673}; 1650};
1674 1651
1675static int read_events(void) 1652static int read_events(void)
1676{ 1653{
1677 int err; 1654 int err = -EINVAL;
1678 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 1655 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false);
1679 if (session == NULL) 1656 if (session == NULL)
1680 return -ENOMEM; 1657 return -ENOMEM;
1681 1658
1682 err = perf_session__process_events(session, &event_ops); 1659 if (perf_session__has_traces(session, "record -R")) {
1660 err = perf_session__process_events(session, &event_ops);
1661 nr_events = session->hists.stats.nr_events[0];
1662 nr_lost_events = session->hists.stats.total_lost;
1663 nr_lost_chunks = session->hists.stats.nr_events[PERF_RECORD_LOST];
1664 }
1665
1683 perf_session__delete(session); 1666 perf_session__delete(session);
1684 return err; 1667 return err;
1685} 1668}
@@ -1804,7 +1787,7 @@ static const char * const sched_usage[] = {
1804static const struct option sched_options[] = { 1787static const struct option sched_options[] = {
1805 OPT_STRING('i', "input", &input_name, "file", 1788 OPT_STRING('i', "input", &input_name, "file",
1806 "input file name"), 1789 "input file name"),
1807 OPT_BOOLEAN('v', "verbose", &verbose, 1790 OPT_INCR('v', "verbose", &verbose,
1808 "be more verbose (show symbol address, etc)"), 1791 "be more verbose (show symbol address, etc)"),
1809 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1792 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1810 "dump raw trace in ASCII"), 1793 "dump raw trace in ASCII"),
@@ -1819,7 +1802,7 @@ static const char * const latency_usage[] = {
1819static const struct option latency_options[] = { 1802static const struct option latency_options[] = {
1820 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1803 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1821 "sort by key(s): runtime, switch, avg, max"), 1804 "sort by key(s): runtime, switch, avg, max"),
1822 OPT_BOOLEAN('v', "verbose", &verbose, 1805 OPT_INCR('v', "verbose", &verbose,
1823 "be more verbose (show symbol address, etc)"), 1806 "be more verbose (show symbol address, etc)"),
1824 OPT_INTEGER('C', "CPU", &profile_cpu, 1807 OPT_INTEGER('C', "CPU", &profile_cpu,
1825 "CPU to profile on"), 1808 "CPU to profile on"),
@@ -1834,9 +1817,9 @@ static const char * const replay_usage[] = {
1834}; 1817};
1835 1818
1836static const struct option replay_options[] = { 1819static const struct option replay_options[] = {
1837 OPT_INTEGER('r', "repeat", &replay_repeat, 1820 OPT_UINTEGER('r', "repeat", &replay_repeat,
1838 "repeat the workload replay N times (-1: infinite)"), 1821 "repeat the workload replay N times (-1: infinite)"),
1839 OPT_BOOLEAN('v', "verbose", &verbose, 1822 OPT_INCR('v', "verbose", &verbose,
1840 "be more verbose (show symbol address, etc)"), 1823 "be more verbose (show symbol address, etc)"),
1841 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1824 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1842 "dump raw trace in ASCII"), 1825 "dump raw trace in ASCII"),
@@ -1864,7 +1847,6 @@ static const char *record_args[] = {
1864 "record", 1847 "record",
1865 "-a", 1848 "-a",
1866 "-R", 1849 "-R",
1867 "-M",
1868 "-f", 1850 "-f",
1869 "-m", "1024", 1851 "-m", "1024",
1870 "-c", "1", 1852 "-c", "1",
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index c70d72003557..a6b4d44f9502 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -44,9 +44,13 @@
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/debug.h" 46#include "util/debug.h"
47#include "util/header.h"
48#include "util/cpumap.h"
49#include "util/thread.h"
47 50
48#include <sys/prctl.h> 51#include <sys/prctl.h>
49#include <math.h> 52#include <math.h>
53#include <locale.h>
50 54
51static struct perf_event_attr default_attrs[] = { 55static struct perf_event_attr default_attrs[] = {
52 56
@@ -64,21 +68,29 @@ static struct perf_event_attr default_attrs[] = {
64 68
65}; 69};
66 70
67static int system_wide = 0; 71static bool system_wide = false;
68static unsigned int nr_cpus = 0; 72static int nr_cpus = 0;
69static int run_idx = 0; 73static int run_idx = 0;
70 74
71static int run_count = 1; 75static int run_count = 1;
72static int inherit = 1; 76static bool no_inherit = false;
73static int scale = 1; 77static bool scale = true;
74static pid_t target_pid = -1; 78static pid_t target_pid = -1;
79static pid_t target_tid = -1;
80static pid_t *all_tids = NULL;
81static int thread_num = 0;
75static pid_t child_pid = -1; 82static pid_t child_pid = -1;
76static int null_run = 0; 83static bool null_run = false;
84static bool big_num = false;
85static const char *cpu_list;
77 86
78static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 87
88static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
79 89
80static int event_scaled[MAX_COUNTERS]; 90static int event_scaled[MAX_COUNTERS];
81 91
92static volatile int done = 0;
93
82struct stats 94struct stats
83{ 95{
84 double n, mean, M2; 96 double n, mean, M2;
@@ -136,33 +148,47 @@ struct stats runtime_branches_stats;
136#define ERR_PERF_OPEN \ 148#define ERR_PERF_OPEN \
137"Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n" 149"Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n"
138 150
139static void create_perf_stat_counter(int counter, int pid) 151static int create_perf_stat_counter(int counter)
140{ 152{
141 struct perf_event_attr *attr = attrs + counter; 153 struct perf_event_attr *attr = attrs + counter;
154 int thread;
155 int ncreated = 0;
142 156
143 if (scale) 157 if (scale)
144 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 158 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
145 PERF_FORMAT_TOTAL_TIME_RUNNING; 159 PERF_FORMAT_TOTAL_TIME_RUNNING;
146 160
147 if (system_wide) { 161 if (system_wide) {
148 unsigned int cpu; 162 int cpu;
149 163
150 for (cpu = 0; cpu < nr_cpus; cpu++) { 164 for (cpu = 0; cpu < nr_cpus; cpu++) {
151 fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0); 165 fd[cpu][counter][0] = sys_perf_event_open(attr,
152 if (fd[cpu][counter] < 0 && verbose) 166 -1, cpumap[cpu], -1, 0);
153 fprintf(stderr, ERR_PERF_OPEN, counter, 167 if (fd[cpu][counter][0] < 0)
154 fd[cpu][counter], strerror(errno)); 168 pr_debug(ERR_PERF_OPEN, counter,
169 fd[cpu][counter][0], strerror(errno));
170 else
171 ++ncreated;
155 } 172 }
156 } else { 173 } else {
157 attr->inherit = inherit; 174 attr->inherit = !no_inherit;
158 attr->disabled = 1; 175 if (target_pid == -1 && target_tid == -1) {
159 attr->enable_on_exec = 1; 176 attr->disabled = 1;
160 177 attr->enable_on_exec = 1;
161 fd[0][counter] = sys_perf_event_open(attr, pid, -1, -1, 0); 178 }
162 if (fd[0][counter] < 0 && verbose) 179 for (thread = 0; thread < thread_num; thread++) {
163 fprintf(stderr, ERR_PERF_OPEN, counter, 180 fd[0][counter][thread] = sys_perf_event_open(attr,
164 fd[0][counter], strerror(errno)); 181 all_tids[thread], -1, -1, 0);
182 if (fd[0][counter][thread] < 0)
183 pr_debug(ERR_PERF_OPEN, counter,
184 fd[0][counter][thread],
185 strerror(errno));
186 else
187 ++ncreated;
188 }
165 } 189 }
190
191 return ncreated;
166} 192}
167 193
168/* 194/*
@@ -183,28 +209,31 @@ static inline int nsec_counter(int counter)
183static void read_counter(int counter) 209static void read_counter(int counter)
184{ 210{
185 u64 count[3], single_count[3]; 211 u64 count[3], single_count[3];
186 unsigned int cpu; 212 int cpu;
187 size_t res, nv; 213 size_t res, nv;
188 int scaled; 214 int scaled;
189 int i; 215 int i, thread;
190 216
191 count[0] = count[1] = count[2] = 0; 217 count[0] = count[1] = count[2] = 0;
192 218
193 nv = scale ? 3 : 1; 219 nv = scale ? 3 : 1;
194 for (cpu = 0; cpu < nr_cpus; cpu++) { 220 for (cpu = 0; cpu < nr_cpus; cpu++) {
195 if (fd[cpu][counter] < 0) 221 for (thread = 0; thread < thread_num; thread++) {
196 continue; 222 if (fd[cpu][counter][thread] < 0)
197 223 continue;
198 res = read(fd[cpu][counter], single_count, nv * sizeof(u64)); 224
199 assert(res == nv * sizeof(u64)); 225 res = read(fd[cpu][counter][thread],
200 226 single_count, nv * sizeof(u64));
201 close(fd[cpu][counter]); 227 assert(res == nv * sizeof(u64));
202 fd[cpu][counter] = -1; 228
203 229 close(fd[cpu][counter][thread]);
204 count[0] += single_count[0]; 230 fd[cpu][counter][thread] = -1;
205 if (scale) { 231
206 count[1] += single_count[1]; 232 count[0] += single_count[0];
207 count[2] += single_count[2]; 233 if (scale) {
234 count[1] += single_count[1];
235 count[2] += single_count[2];
236 }
208 } 237 }
209 } 238 }
210 239
@@ -246,72 +275,88 @@ static int run_perf_stat(int argc __used, const char **argv)
246{ 275{
247 unsigned long long t0, t1; 276 unsigned long long t0, t1;
248 int status = 0; 277 int status = 0;
249 int counter; 278 int counter, ncreated = 0;
250 int pid;
251 int child_ready_pipe[2], go_pipe[2]; 279 int child_ready_pipe[2], go_pipe[2];
280 const bool forks = (argc > 0);
252 char buf; 281 char buf;
253 282
254 if (!system_wide) 283 if (!system_wide)
255 nr_cpus = 1; 284 nr_cpus = 1;
256 285
257 if (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0) { 286 if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
258 perror("failed to create pipes"); 287 perror("failed to create pipes");
259 exit(1); 288 exit(1);
260 } 289 }
261 290
262 if ((pid = fork()) < 0) 291 if (forks) {
263 perror("failed to fork"); 292 if ((child_pid = fork()) < 0)
293 perror("failed to fork");
294
295 if (!child_pid) {
296 close(child_ready_pipe[0]);
297 close(go_pipe[1]);
298 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
299
300 /*
301 * Do a dummy execvp to get the PLT entry resolved,
302 * so we avoid the resolver overhead on the real
303 * execvp call.
304 */
305 execvp("", (char **)argv);
306
307 /*
308 * Tell the parent we're ready to go
309 */
310 close(child_ready_pipe[1]);
311
312 /*
313 * Wait until the parent tells us to go.
314 */
315 if (read(go_pipe[0], &buf, 1) == -1)
316 perror("unable to read pipe");
317
318 execvp(argv[0], (char **)argv);
319
320 perror(argv[0]);
321 exit(-1);
322 }
264 323
265 if (!pid) { 324 if (target_tid == -1 && target_pid == -1 && !system_wide)
266 close(child_ready_pipe[0]); 325 all_tids[0] = child_pid;
267 close(go_pipe[1]);
268 fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
269 326
270 /* 327 /*
271 * Do a dummy execvp to get the PLT entry resolved, 328 * Wait for the child to be ready to exec.
272 * so we avoid the resolver overhead on the real
273 * execvp call.
274 */
275 execvp("", (char **)argv);
276
277 /*
278 * Tell the parent we're ready to go
279 */ 329 */
280 close(child_ready_pipe[1]); 330 close(child_ready_pipe[1]);
281 331 close(go_pipe[0]);
282 /* 332 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"); 333 perror("unable to read pipe");
287 334 close(child_ready_pipe[0]);
288 execvp(argv[0], (char **)argv);
289
290 perror(argv[0]);
291 exit(-1);
292 } 335 }
293 336
294 child_pid = pid;
295
296 /*
297 * Wait for the child to be ready to exec.
298 */
299 close(child_ready_pipe[1]);
300 close(go_pipe[0]);
301 if (read(child_ready_pipe[0], &buf, 1) == -1)
302 perror("unable to read pipe");
303 close(child_ready_pipe[0]);
304
305 for (counter = 0; counter < nr_counters; counter++) 337 for (counter = 0; counter < nr_counters; counter++)
306 create_perf_stat_counter(counter, pid); 338 ncreated += create_perf_stat_counter(counter);
339
340 if (ncreated == 0) {
341 pr_err("No permission to collect %sstats.\n"
342 "Consider tweaking /proc/sys/kernel/perf_event_paranoid.\n",
343 system_wide ? "system-wide " : "");
344 if (child_pid != -1)
345 kill(child_pid, SIGTERM);
346 return -1;
347 }
307 348
308 /* 349 /*
309 * Enable counters and exec the command: 350 * Enable counters and exec the command:
310 */ 351 */
311 t0 = rdclock(); 352 t0 = rdclock();
312 353
313 close(go_pipe[1]); 354 if (forks) {
314 wait(&status); 355 close(go_pipe[1]);
356 wait(&status);
357 } else {
358 while(!done) sleep(1);
359 }
315 360
316 t1 = rdclock(); 361 t1 = rdclock();
317 362
@@ -336,7 +381,7 @@ static void nsec_printout(int counter, double avg)
336{ 381{
337 double msecs = avg / 1e6; 382 double msecs = avg / 1e6;
338 383
339 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter)); 384 fprintf(stderr, " %18.6f %-24s", msecs, event_name(counter));
340 385
341 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { 386 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
342 fprintf(stderr, " # %10.3f CPUs ", 387 fprintf(stderr, " # %10.3f CPUs ",
@@ -348,7 +393,10 @@ static void abs_printout(int counter, double avg)
348{ 393{
349 double total, ratio = 0.0; 394 double total, ratio = 0.0;
350 395
351 fprintf(stderr, " %14.0f %-24s", avg, event_name(counter)); 396 if (big_num)
397 fprintf(stderr, " %'18.0f %-24s", avg, event_name(counter));
398 else
399 fprintf(stderr, " %18.0f %-24s", avg, event_name(counter));
352 400
353 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { 401 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
354 total = avg_stats(&runtime_cycles_stats); 402 total = avg_stats(&runtime_cycles_stats);
@@ -385,7 +433,7 @@ static void print_counter(int counter)
385 int scaled = event_scaled[counter]; 433 int scaled = event_scaled[counter];
386 434
387 if (scaled == -1) { 435 if (scaled == -1) {
388 fprintf(stderr, " %14s %-24s\n", 436 fprintf(stderr, " %18s %-24s\n",
389 "<not counted>", event_name(counter)); 437 "<not counted>", event_name(counter));
390 return; 438 return;
391 } 439 }
@@ -417,10 +465,15 @@ static void print_stat(int argc, const char **argv)
417 fflush(stdout); 465 fflush(stdout);
418 466
419 fprintf(stderr, "\n"); 467 fprintf(stderr, "\n");
420 fprintf(stderr, " Performance counter stats for \'%s", argv[0]); 468 fprintf(stderr, " Performance counter stats for ");
421 469 if(target_pid == -1 && target_tid == -1) {
422 for (i = 1; i < argc; i++) 470 fprintf(stderr, "\'%s", argv[0]);
423 fprintf(stderr, " %s", argv[i]); 471 for (i = 1; i < argc; i++)
472 fprintf(stderr, " %s", argv[i]);
473 } else if (target_pid != -1)
474 fprintf(stderr, "process id \'%d", target_pid);
475 else
476 fprintf(stderr, "thread id \'%d", target_tid);
424 477
425 fprintf(stderr, "\'"); 478 fprintf(stderr, "\'");
426 if (run_count > 1) 479 if (run_count > 1)
@@ -431,7 +484,7 @@ static void print_stat(int argc, const char **argv)
431 print_counter(counter); 484 print_counter(counter);
432 485
433 fprintf(stderr, "\n"); 486 fprintf(stderr, "\n");
434 fprintf(stderr, " %14.9f seconds time elapsed", 487 fprintf(stderr, " %18.9f seconds time elapsed",
435 avg_stats(&walltime_nsecs_stats)/1e9); 488 avg_stats(&walltime_nsecs_stats)/1e9);
436 if (run_count > 1) { 489 if (run_count > 1) {
437 fprintf(stderr, " ( +- %7.3f%% )", 490 fprintf(stderr, " ( +- %7.3f%% )",
@@ -445,6 +498,9 @@ static volatile int signr = -1;
445 498
446static void skip_signal(int signo) 499static void skip_signal(int signo)
447{ 500{
501 if(child_pid == -1)
502 done = 1;
503
448 signr = signo; 504 signr = signo;
449} 505}
450 506
@@ -461,7 +517,7 @@ static void sig_atexit(void)
461} 517}
462 518
463static const char * const stat_usage[] = { 519static const char * const stat_usage[] = {
464 "perf stat [<options>] <command>", 520 "perf stat [<options>] [<command>]",
465 NULL 521 NULL
466}; 522};
467 523
@@ -469,30 +525,39 @@ static const struct option options[] = {
469 OPT_CALLBACK('e', "event", NULL, "event", 525 OPT_CALLBACK('e', "event", NULL, "event",
470 "event selector. use 'perf list' to list available events", 526 "event selector. use 'perf list' to list available events",
471 parse_events), 527 parse_events),
472 OPT_BOOLEAN('i', "inherit", &inherit, 528 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
473 "child tasks inherit counters"), 529 "child tasks do not inherit counters"),
474 OPT_INTEGER('p', "pid", &target_pid, 530 OPT_INTEGER('p', "pid", &target_pid,
475 "stat events on existing pid"), 531 "stat events on existing process id"),
532 OPT_INTEGER('t', "tid", &target_tid,
533 "stat events on existing thread id"),
476 OPT_BOOLEAN('a', "all-cpus", &system_wide, 534 OPT_BOOLEAN('a', "all-cpus", &system_wide,
477 "system-wide collection from all CPUs"), 535 "system-wide collection from all CPUs"),
478 OPT_BOOLEAN('c', "scale", &scale, 536 OPT_BOOLEAN('c', "scale", &scale,
479 "scale/normalize counters"), 537 "scale/normalize counters"),
480 OPT_BOOLEAN('v', "verbose", &verbose, 538 OPT_INCR('v', "verbose", &verbose,
481 "be more verbose (show counter open errors, etc)"), 539 "be more verbose (show counter open errors, etc)"),
482 OPT_INTEGER('r', "repeat", &run_count, 540 OPT_INTEGER('r', "repeat", &run_count,
483 "repeat command and print average + stddev (max: 100)"), 541 "repeat command and print average + stddev (max: 100)"),
484 OPT_BOOLEAN('n', "null", &null_run, 542 OPT_BOOLEAN('n', "null", &null_run,
485 "null run - dont start any counters"), 543 "null run - dont start any counters"),
544 OPT_BOOLEAN('B', "big-num", &big_num,
545 "print large numbers with thousands\' separators"),
546 OPT_STRING('C', "cpu", &cpu_list, "cpu",
547 "list of cpus to monitor in system-wide"),
486 OPT_END() 548 OPT_END()
487}; 549};
488 550
489int cmd_stat(int argc, const char **argv, const char *prefix __used) 551int cmd_stat(int argc, const char **argv, const char *prefix __used)
490{ 552{
491 int status; 553 int status;
554 int i,j;
555
556 setlocale(LC_ALL, "");
492 557
493 argc = parse_options(argc, argv, options, stat_usage, 558 argc = parse_options(argc, argv, options, stat_usage,
494 PARSE_OPT_STOP_AT_NON_OPTION); 559 PARSE_OPT_STOP_AT_NON_OPTION);
495 if (!argc) 560 if (!argc && target_pid == -1 && target_tid == -1)
496 usage_with_options(stat_usage, options); 561 usage_with_options(stat_usage, options);
497 if (run_count <= 0) 562 if (run_count <= 0)
498 usage_with_options(stat_usage, options); 563 usage_with_options(stat_usage, options);
@@ -503,9 +568,38 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
503 nr_counters = ARRAY_SIZE(default_attrs); 568 nr_counters = ARRAY_SIZE(default_attrs);
504 } 569 }
505 570
506 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 571 if (system_wide)
507 assert(nr_cpus <= MAX_NR_CPUS); 572 nr_cpus = read_cpu_map(cpu_list);
508 assert((int)nr_cpus >= 0); 573 else
574 nr_cpus = 1;
575
576 if (nr_cpus < 1)
577 usage_with_options(stat_usage, options);
578
579 if (target_pid != -1) {
580 target_tid = target_pid;
581 thread_num = find_all_tid(target_pid, &all_tids);
582 if (thread_num <= 0) {
583 fprintf(stderr, "Can't find all threads of pid %d\n",
584 target_pid);
585 usage_with_options(stat_usage, options);
586 }
587 } else {
588 all_tids=malloc(sizeof(pid_t));
589 if (!all_tids)
590 return -ENOMEM;
591
592 all_tids[0] = target_tid;
593 thread_num = 1;
594 }
595
596 for (i = 0; i < MAX_NR_CPUS; i++) {
597 for (j = 0; j < MAX_COUNTERS; j++) {
598 fd[i][j] = malloc(sizeof(int)*thread_num);
599 if (!fd[i][j])
600 return -ENOMEM;
601 }
602 }
509 603
510 /* 604 /*
511 * We dont want to block the signals - that would cause 605 * We dont want to block the signals - that would cause
@@ -525,7 +619,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
525 status = run_perf_stat(argc, argv); 619 status = run_perf_stat(argc, argv);
526 } 620 }
527 621
528 print_stat(argc, argv); 622 if (status != -1)
623 print_stat(argc, argv);
529 624
530 return status; 625 return status;
531} 626}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
new file mode 100644
index 000000000000..035b9fa063a9
--- /dev/null
+++ b/tools/perf/builtin-test.c
@@ -0,0 +1,281 @@
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;
123
124 sym = rb_entry(nd, struct symbol, rb_node);
125 pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
126
127 if (pair && pair->start == sym->start) {
128next_pair:
129 if (strcmp(sym->name, pair->name) == 0) {
130 /*
131 * kallsyms don't have the symbol end, so we
132 * set that by using the next symbol start - 1,
133 * in some cases we get this up to a page
134 * wrong, trace_kmalloc when I was developing
135 * this code was one such example, 2106 bytes
136 * off the real size. More than that and we
137 * _really_ have a problem.
138 */
139 s64 skew = sym->end - pair->end;
140 if (llabs(skew) < page_size)
141 continue;
142
143 pr_debug("%#Lx: diff end addr for %s v: %#Lx k: %#Lx\n",
144 sym->start, sym->name, sym->end, pair->end);
145 } else {
146 struct rb_node *nnd = rb_prev(&pair->rb_node);
147
148 if (nnd) {
149 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
150
151 if (next->start == sym->start) {
152 pair = next;
153 goto next_pair;
154 }
155 }
156 pr_debug("%#Lx: diff name v: %s k: %s\n",
157 sym->start, sym->name, pair->name);
158 }
159 } else
160 pr_debug("%#Lx: %s not on kallsyms\n", sym->start, sym->name);
161
162 err = -1;
163 }
164
165 if (!verbose)
166 goto out;
167
168 pr_info("Maps only in vmlinux:\n");
169
170 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
171 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
172 /*
173 * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
174 * the kernel will have the path for the vmlinux file being used,
175 * so use the short name, less descriptive but the same ("[kernel]" in
176 * both cases.
177 */
178 pair = map_groups__find_by_name(&kallsyms.kmaps, type,
179 (pos->dso->kernel ?
180 pos->dso->short_name :
181 pos->dso->name));
182 if (pair)
183 pair->priv = 1;
184 else
185 map__fprintf(pos, stderr);
186 }
187
188 pr_info("Maps in vmlinux with a different name in kallsyms:\n");
189
190 for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
191 struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
192
193 pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
194 if (pair == NULL || pair->priv)
195 continue;
196
197 if (pair->start == pos->start) {
198 pair->priv = 1;
199 pr_info(" %Lx-%Lx %Lx %s in kallsyms as",
200 pos->start, pos->end, pos->pgoff, pos->dso->name);
201 if (pos->pgoff != pair->pgoff || pos->end != pair->end)
202 pr_info(": \n*%Lx-%Lx %Lx",
203 pair->start, pair->end, pair->pgoff);
204 pr_info(" %s\n", pair->dso->name);
205 pair->priv = 1;
206 }
207 }
208
209 pr_info("Maps only in kallsyms:\n");
210
211 for (nd = rb_first(&kallsyms.kmaps.maps[type]);
212 nd; nd = rb_next(nd)) {
213 struct map *pos = rb_entry(nd, struct map, rb_node);
214
215 if (!pos->priv)
216 map__fprintf(pos, stderr);
217 }
218out:
219 return err;
220}
221
222static struct test {
223 const char *desc;
224 int (*func)(void);
225} tests[] = {
226 {
227 .desc = "vmlinux symtab matches kallsyms",
228 .func = test__vmlinux_matches_kallsyms,
229 },
230 {
231 .func = NULL,
232 },
233};
234
235static int __cmd_test(void)
236{
237 int i = 0;
238
239 page_size = sysconf(_SC_PAGE_SIZE);
240
241 while (tests[i].func) {
242 int err;
243 pr_info("%2d: %s:", i + 1, tests[i].desc);
244 pr_debug("\n--- start ---\n");
245 err = tests[i].func();
246 pr_debug("---- end ----\n%s:", tests[i].desc);
247 pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
248 ++i;
249 }
250
251 return 0;
252}
253
254static const char * const test_usage[] = {
255 "perf test [<options>]",
256 NULL,
257};
258
259static const struct option test_options[] = {
260 OPT_INTEGER('v', "verbose", &verbose,
261 "be more verbose (show symbol address, etc)"),
262 OPT_END()
263};
264
265int cmd_test(int argc, const char **argv, const char *prefix __used)
266{
267 argc = parse_options(argc, argv, test_options, test_usage, 0);
268 if (argc)
269 usage_with_options(test_usage, test_options);
270
271 symbol_conf.priv_size = sizeof(int);
272 symbol_conf.sort_by_name = true;
273 symbol_conf.try_vmlinux_path = true;
274
275 if (symbol__init() < 0)
276 return -1;
277
278 setup_pager();
279
280 return __cmd_test();
281}
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 3f8bbcfb1e9b..9bcc38f0b706 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
@@ -43,7 +42,7 @@ static u64 turbo_frequency;
43 42
44static u64 first_time, last_time; 43static u64 first_time, last_time;
45 44
46static int power_only; 45static bool power_only;
47 46
48 47
49struct per_pid; 48struct per_pid;
@@ -78,8 +77,6 @@ struct per_pid {
78 77
79 struct per_pidcomm *all; 78 struct per_pidcomm *all;
80 struct per_pidcomm *current; 79 struct per_pidcomm *current;
81
82 int painted;
83}; 80};
84 81
85 82
@@ -146,9 +143,6 @@ struct wake_event {
146static struct power_event *power_events; 143static struct power_event *power_events;
147static struct wake_event *wake_events; 144static struct wake_event *wake_events;
148 145
149struct sample_wrapper *all_samples;
150
151
152struct process_filter; 146struct process_filter;
153struct process_filter { 147struct process_filter {
154 char *name; 148 char *name;
@@ -306,8 +300,9 @@ struct trace_entry {
306 300
307struct power_entry { 301struct power_entry {
308 struct trace_entry te; 302 struct trace_entry te;
309 s64 type; 303 u64 type;
310 s64 value; 304 u64 value;
305 u64 cpu_id;
311}; 306};
312 307
313#define TASK_COMM_LEN 16 308#define TASK_COMM_LEN 16
@@ -460,8 +455,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
460 if (p->current->state != TYPE_NONE) 455 if (p->current->state != TYPE_NONE)
461 pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp); 456 pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp);
462 457
463 p->current->state_since = timestamp; 458 p->current->state_since = timestamp;
464 p->current->state = TYPE_RUNNING; 459 p->current->state = TYPE_RUNNING;
465 } 460 }
466 461
467 if (prev_p->current) { 462 if (prev_p->current) {
@@ -504,13 +499,13 @@ static int process_sample_event(event_t *event, struct perf_session *session)
504 return 0; 499 return 0;
505 500
506 if (strcmp(event_str, "power:power_start") == 0) 501 if (strcmp(event_str, "power:power_start") == 0)
507 c_state_start(data.cpu, data.time, pe->value); 502 c_state_start(pe->cpu_id, data.time, pe->value);
508 503
509 if (strcmp(event_str, "power:power_end") == 0) 504 if (strcmp(event_str, "power:power_end") == 0)
510 c_state_end(data.cpu, data.time); 505 c_state_end(pe->cpu_id, data.time);
511 506
512 if (strcmp(event_str, "power:power_frequency") == 0) 507 if (strcmp(event_str, "power:power_frequency") == 0)
513 p_state_change(data.cpu, data.time, pe->value); 508 p_state_change(pe->cpu_id, data.time, pe->value);
514 509
515 if (strcmp(event_str, "sched:sched_wakeup") == 0) 510 if (strcmp(event_str, "sched:sched_wakeup") == 0)
516 sched_wakeup(data.cpu, data.time, data.pid, te); 511 sched_wakeup(data.cpu, data.time, data.pid, te);
@@ -569,88 +564,6 @@ static void end_sample_processing(void)
569 } 564 }
570} 565}
571 566
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/* 567/*
655 * Sort the pid datastructure 568 * Sort the pid datastructure
656 */ 569 */
@@ -1014,54 +927,29 @@ static void write_svg_file(const char *filename)
1014 svg_close(); 927 svg_close();
1015} 928}
1016 929
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 = { 930static struct perf_event_ops event_ops = {
1044 .process_comm_event = process_comm_event, 931 .comm = process_comm_event,
1045 .process_fork_event = process_fork_event, 932 .fork = process_fork_event,
1046 .process_exit_event = process_exit_event, 933 .exit = process_exit_event,
1047 .process_sample_event = queue_sample_event, 934 .sample = process_sample_event,
1048 .sample_type_check = sample_type_check, 935 .ordered_samples = true,
1049}; 936};
1050 937
1051static int __cmd_timechart(void) 938static int __cmd_timechart(void)
1052{ 939{
1053 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0); 940 struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0, false);
1054 int ret; 941 int ret = -EINVAL;
1055 942
1056 if (session == NULL) 943 if (session == NULL)
1057 return -ENOMEM; 944 return -ENOMEM;
1058 945
946 if (!perf_session__has_traces(session, "timechart record"))
947 goto out_delete;
948
1059 ret = perf_session__process_events(session, &event_ops); 949 ret = perf_session__process_events(session, &event_ops);
1060 if (ret) 950 if (ret)
1061 goto out_delete; 951 goto out_delete;
1062 952
1063 process_samples(session);
1064
1065 end_sample_processing(); 953 end_sample_processing();
1066 954
1067 sort_pids(); 955 sort_pids();
@@ -1084,7 +972,6 @@ static const char *record_args[] = {
1084 "record", 972 "record",
1085 "-a", 973 "-a",
1086 "-R", 974 "-R",
1087 "-M",
1088 "-f", 975 "-f",
1089 "-c", "1", 976 "-c", "1",
1090 "-e", "power:power_start", 977 "-e", "power:power_start",
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ddc584b64871..b513e40974f4 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -28,6 +28,7 @@
28#include <linux/rbtree.h> 28#include <linux/rbtree.h>
29#include "util/parse-options.h" 29#include "util/parse-options.h"
30#include "util/parse-events.h" 30#include "util/parse-events.h"
31#include "util/cpumap.h"
31 32
32#include "util/debug.h" 33#include "util/debug.h"
33 34
@@ -54,9 +55,9 @@
54#include <linux/unistd.h> 55#include <linux/unistd.h>
55#include <linux/types.h> 56#include <linux/types.h>
56 57
57static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 58static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
58 59
59static int system_wide = 0; 60static bool system_wide = false;
60 61
61static int default_interval = 0; 62static int default_interval = 0;
62 63
@@ -64,18 +65,21 @@ static int count_filter = 5;
64static int print_entries; 65static int print_entries;
65 66
66static int target_pid = -1; 67static int target_pid = -1;
67static int inherit = 0; 68static int target_tid = -1;
69static pid_t *all_tids = NULL;
70static int thread_num = 0;
71static bool inherit = false;
68static int profile_cpu = -1; 72static int profile_cpu = -1;
69static int nr_cpus = 0; 73static int nr_cpus = 0;
70static unsigned int realtime_prio = 0; 74static int realtime_prio = 0;
71static int group = 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,13 @@ 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;
99static int display_weighted = -1; 104static int display_weighted = -1;
105static const char *cpu_list;
100 106
101/* 107/*
102 * Symbols 108 * Symbols
@@ -131,7 +137,7 @@ static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
131 return ((void *)self) + symbol_conf.priv_size; 137 return ((void *)self) + symbol_conf.priv_size;
132} 138}
133 139
134static void get_term_dimensions(struct winsize *ws) 140void get_term_dimensions(struct winsize *ws)
135{ 141{
136 char *s = getenv("LINES"); 142 char *s = getenv("LINES");
137 143
@@ -167,7 +173,7 @@ static void sig_winch_handler(int sig __used)
167 update_print_entries(&winsize); 173 update_print_entries(&winsize);
168} 174}
169 175
170static void parse_source(struct sym_entry *syme) 176static int parse_source(struct sym_entry *syme)
171{ 177{
172 struct symbol *sym; 178 struct symbol *sym;
173 struct sym_entry_source *source; 179 struct sym_entry_source *source;
@@ -178,12 +184,21 @@ static void parse_source(struct sym_entry *syme)
178 u64 len; 184 u64 len;
179 185
180 if (!syme) 186 if (!syme)
181 return; 187 return -1;
188
189 sym = sym_entry__symbol(syme);
190 map = syme->map;
191
192 /*
193 * We can't annotate with just /proc/kallsyms
194 */
195 if (map->dso->origin == DSO__ORIG_KERNEL)
196 return -1;
182 197
183 if (syme->src == NULL) { 198 if (syme->src == NULL) {
184 syme->src = zalloc(sizeof(*source)); 199 syme->src = zalloc(sizeof(*source));
185 if (syme->src == NULL) 200 if (syme->src == NULL)
186 return; 201 return -1;
187 pthread_mutex_init(&syme->src->lock, NULL); 202 pthread_mutex_init(&syme->src->lock, NULL);
188 } 203 }
189 204
@@ -193,29 +208,25 @@ static void parse_source(struct sym_entry *syme)
193 pthread_mutex_lock(&source->lock); 208 pthread_mutex_lock(&source->lock);
194 goto out_assign; 209 goto out_assign;
195 } 210 }
196
197 sym = sym_entry__symbol(syme);
198 map = syme->map;
199 path = map->dso->long_name; 211 path = map->dso->long_name;
200 212
201 len = sym->end - sym->start; 213 len = sym->end - sym->start;
202 214
203 sprintf(command, 215 sprintf(command,
204 "objdump --start-address=0x%016Lx " 216 "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s",
205 "--stop-address=0x%016Lx -dS %s", 217 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start),
206 map->unmap_ip(map, sym->start), 218 BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path);
207 map->unmap_ip(map, sym->end), path);
208 219
209 file = popen(command, "r"); 220 file = popen(command, "r");
210 if (!file) 221 if (!file)
211 return; 222 return -1;
212 223
213 pthread_mutex_lock(&source->lock); 224 pthread_mutex_lock(&source->lock);
214 source->lines_tail = &source->lines; 225 source->lines_tail = &source->lines;
215 while (!feof(file)) { 226 while (!feof(file)) {
216 struct source_line *src; 227 struct source_line *src;
217 size_t dummy = 0; 228 size_t dummy = 0;
218 char *c; 229 char *c, *sep;
219 230
220 src = malloc(sizeof(struct source_line)); 231 src = malloc(sizeof(struct source_line));
221 assert(src != NULL); 232 assert(src != NULL);
@@ -234,19 +245,17 @@ static void parse_source(struct sym_entry *syme)
234 *source->lines_tail = src; 245 *source->lines_tail = src;
235 source->lines_tail = &src->next; 246 source->lines_tail = &src->next;
236 247
237 if (strlen(src->line)>8 && src->line[8] == ':') { 248 src->eip = strtoull(src->line, &sep, 16);
238 src->eip = strtoull(src->line, NULL, 16); 249 if (*sep == ':')
239 src->eip = map->unmap_ip(map, src->eip); 250 src->eip = map__objdump_2ip(map, src->eip);
240 } 251 else /* this line has no ip info (e.g. source line) */
241 if (strlen(src->line)>8 && src->line[16] == ':') { 252 src->eip = 0;
242 src->eip = strtoull(src->line, NULL, 16);
243 src->eip = map->unmap_ip(map, src->eip);
244 }
245 } 253 }
246 pclose(file); 254 pclose(file);
247out_assign: 255out_assign:
248 sym_filter_entry = syme; 256 sym_filter_entry = syme;
249 pthread_mutex_unlock(&source->lock); 257 pthread_mutex_unlock(&source->lock);
258 return 0;
250} 259}
251 260
252static void __zero_source_counters(struct sym_entry *syme) 261static void __zero_source_counters(struct sym_entry *syme)
@@ -276,6 +285,9 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
276 goto out_unlock; 285 goto out_unlock;
277 286
278 for (line = syme->src->lines; line; line = line->next) { 287 for (line = syme->src->lines; line; line = line->next) {
288 /* skip lines without IP info */
289 if (line->eip == 0)
290 continue;
279 if (line->eip == ip) { 291 if (line->eip == ip) {
280 line->count[counter]++; 292 line->count[counter]++;
281 break; 293 break;
@@ -287,17 +299,20 @@ out_unlock:
287 pthread_mutex_unlock(&syme->src->lock); 299 pthread_mutex_unlock(&syme->src->lock);
288} 300}
289 301
302#define PATTERN_LEN (BITS_PER_LONG / 4 + 2)
303
290static void lookup_sym_source(struct sym_entry *syme) 304static void lookup_sym_source(struct sym_entry *syme)
291{ 305{
292 struct symbol *symbol = sym_entry__symbol(syme); 306 struct symbol *symbol = sym_entry__symbol(syme);
293 struct source_line *line; 307 struct source_line *line;
294 char pattern[PATH_MAX]; 308 char pattern[PATTERN_LEN + 1];
295 309
296 sprintf(pattern, "<%s>:", symbol->name); 310 sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4,
311 map__rip_2objdump(syme->map, symbol->start));
297 312
298 pthread_mutex_lock(&syme->src->lock); 313 pthread_mutex_lock(&syme->src->lock);
299 for (line = syme->src->lines; line; line = line->next) { 314 for (line = syme->src->lines; line; line = line->next) {
300 if (strstr(line->line, pattern)) { 315 if (memcmp(line->line, pattern, PATTERN_LEN) == 0) {
301 syme->src->source = line; 316 syme->src->source = line;
302 break; 317 break;
303 } 318 }
@@ -406,7 +421,9 @@ static double sym_weight(const struct sym_entry *sym)
406} 421}
407 422
408static long samples; 423static long samples;
409static long userspace_samples; 424static long kernel_samples, us_samples;
425static long exact_samples;
426static long guest_us_samples, guest_kernel_samples;
410static const char CONSOLE_CLEAR[] = ""; 427static const char CONSOLE_CLEAR[] = "";
411 428
412static void __list_insert_active_sym(struct sym_entry *syme) 429static void __list_insert_active_sym(struct sym_entry *syme)
@@ -446,15 +463,20 @@ static void print_sym_table(void)
446 int printed = 0, j; 463 int printed = 0, j;
447 int counter, snap = !display_weighted ? sym_counter : 0; 464 int counter, snap = !display_weighted ? sym_counter : 0;
448 float samples_per_sec = samples/delay_secs; 465 float samples_per_sec = samples/delay_secs;
449 float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 466 float ksamples_per_sec = kernel_samples/delay_secs;
467 float us_samples_per_sec = (us_samples)/delay_secs;
468 float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
469 float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
470 float esamples_percent = (100.0*exact_samples)/samples;
450 float sum_ksamples = 0.0; 471 float sum_ksamples = 0.0;
451 struct sym_entry *syme, *n; 472 struct sym_entry *syme, *n;
452 struct rb_root tmp = RB_ROOT; 473 struct rb_root tmp = RB_ROOT;
453 struct rb_node *nd; 474 struct rb_node *nd;
454 int sym_width = 0, dso_width = 0, max_dso_width; 475 int sym_width = 0, dso_width = 0, dso_short_width = 0;
455 const int win_width = winsize.ws_col - 1; 476 const int win_width = winsize.ws_col - 1;
456 477
457 samples = userspace_samples = 0; 478 samples = us_samples = kernel_samples = exact_samples = 0;
479 guest_kernel_samples = guest_us_samples = 0;
458 480
459 /* Sort the active symbols */ 481 /* Sort the active symbols */
460 pthread_mutex_lock(&active_symbols_lock); 482 pthread_mutex_lock(&active_symbols_lock);
@@ -485,9 +507,30 @@ static void print_sym_table(void)
485 puts(CONSOLE_CLEAR); 507 puts(CONSOLE_CLEAR);
486 508
487 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 509 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
488 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", 510 if (!perf_guest) {
489 samples_per_sec, 511 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
490 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 512 " exact: %4.1f%% [",
513 samples_per_sec,
514 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
515 samples_per_sec)),
516 esamples_percent);
517 } else {
518 printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
519 " guest kernel:%4.1f%% guest us:%4.1f%%"
520 " exact: %4.1f%% [",
521 samples_per_sec,
522 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
523 samples_per_sec)),
524 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
525 samples_per_sec)),
526 100.0 - (100.0 * ((samples_per_sec -
527 guest_kernel_samples_per_sec) /
528 samples_per_sec)),
529 100.0 - (100.0 * ((samples_per_sec -
530 guest_us_samples_per_sec) /
531 samples_per_sec)),
532 esamples_percent);
533 }
491 534
492 if (nr_counters == 1 || !display_weighted) { 535 if (nr_counters == 1 || !display_weighted) {
493 printf("%Ld", (u64)attrs[0].sample_period); 536 printf("%Ld", (u64)attrs[0].sample_period);
@@ -510,13 +553,15 @@ static void print_sym_table(void)
510 553
511 if (target_pid != -1) 554 if (target_pid != -1)
512 printf(" (target_pid: %d", target_pid); 555 printf(" (target_pid: %d", target_pid);
556 else if (target_tid != -1)
557 printf(" (target_tid: %d", target_tid);
513 else 558 else
514 printf(" (all"); 559 printf(" (all");
515 560
516 if (profile_cpu != -1) 561 if (profile_cpu != -1)
517 printf(", cpu: %d)\n", profile_cpu); 562 printf(", cpu: %d)\n", profile_cpu);
518 else { 563 else {
519 if (target_pid != -1) 564 if (target_tid != -1)
520 printf(")\n"); 565 printf(")\n");
521 else 566 else
522 printf(", %d CPUs)\n", nr_cpus); 567 printf(", %d CPUs)\n", nr_cpus);
@@ -541,15 +586,20 @@ static void print_sym_table(void)
541 if (syme->map->dso->long_name_len > dso_width) 586 if (syme->map->dso->long_name_len > dso_width)
542 dso_width = syme->map->dso->long_name_len; 587 dso_width = syme->map->dso->long_name_len;
543 588
589 if (syme->map->dso->short_name_len > dso_short_width)
590 dso_short_width = syme->map->dso->short_name_len;
591
544 if (syme->name_len > sym_width) 592 if (syme->name_len > sym_width)
545 sym_width = syme->name_len; 593 sym_width = syme->name_len;
546 } 594 }
547 595
548 printed = 0; 596 printed = 0;
549 597
550 max_dso_width = winsize.ws_col - sym_width - 29; 598 if (sym_width + dso_width > winsize.ws_col - 29) {
551 if (dso_width > max_dso_width) 599 dso_width = dso_short_width;
552 dso_width = max_dso_width; 600 if (sym_width + dso_width > winsize.ws_col - 29)
601 sym_width = winsize.ws_col - dso_width - 29;
602 }
553 putchar('\n'); 603 putchar('\n');
554 if (nr_counters == 1) 604 if (nr_counters == 1)
555 printf(" samples pcnt"); 605 printf(" samples pcnt");
@@ -573,7 +623,6 @@ static void print_sym_table(void)
573 623
574 syme = rb_entry(nd, struct sym_entry, rb_node); 624 syme = rb_entry(nd, struct sym_entry, rb_node);
575 sym = sym_entry__symbol(syme); 625 sym = sym_entry__symbol(syme);
576
577 if (++printed > print_entries || (int)syme->snap_count < count_filter) 626 if (++printed > print_entries || (int)syme->snap_count < count_filter)
578 continue; 627 continue;
579 628
@@ -667,7 +716,7 @@ static void prompt_symbol(struct sym_entry **target, const char *msg)
667 } 716 }
668 717
669 if (!found) { 718 if (!found) {
670 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter); 719 fprintf(stderr, "Sorry, %s is not active.\n", buf);
671 sleep(1); 720 sleep(1);
672 return; 721 return;
673 } else 722 } else
@@ -695,17 +744,15 @@ static void print_mapped_keys(void)
695 744
696 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 745 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
697 746
698 if (symbol_conf.vmlinux_name) { 747 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); 748 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
700 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 749 fprintf(stdout, "\t[S] stop annotation.\n");
701 fprintf(stdout, "\t[S] stop annotation.\n");
702 }
703 750
704 if (nr_counters > 1) 751 if (nr_counters > 1)
705 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 752 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
706 753
707 fprintf(stdout, 754 fprintf(stdout,
708 "\t[K] hide kernel_symbols symbols. \t(%s)\n", 755 "\t[K] hide kernel_symbols symbols. \t(%s)\n",
709 hide_kernel_symbols ? "yes" : "no"); 756 hide_kernel_symbols ? "yes" : "no");
710 fprintf(stdout, 757 fprintf(stdout,
711 "\t[U] hide user symbols. \t(%s)\n", 758 "\t[U] hide user symbols. \t(%s)\n",
@@ -725,14 +772,13 @@ static int key_mapped(int c)
725 case 'Q': 772 case 'Q':
726 case 'K': 773 case 'K':
727 case 'U': 774 case 'U':
775 case 'F':
776 case 's':
777 case 'S':
728 return 1; 778 return 1;
729 case 'E': 779 case 'E':
730 case 'w': 780 case 'w':
731 return nr_counters > 1 ? 1 : 0; 781 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: 782 default:
737 break; 783 break;
738 } 784 }
@@ -740,7 +786,7 @@ static int key_mapped(int c)
740 return 0; 786 return 0;
741} 787}
742 788
743static void handle_keypress(int c) 789static void handle_keypress(struct perf_session *session, int c)
744{ 790{
745 if (!key_mapped(c)) { 791 if (!key_mapped(c)) {
746 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 792 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -809,7 +855,7 @@ static void handle_keypress(int c)
809 case 'Q': 855 case 'Q':
810 printf("exiting.\n"); 856 printf("exiting.\n");
811 if (dump_symtab) 857 if (dump_symtab)
812 dsos__fprintf(stderr); 858 perf_session__fprintf_dsos(session, stderr);
813 exit(0); 859 exit(0);
814 case 's': 860 case 's':
815 prompt_symbol(&sym_filter_entry, "Enter details symbol"); 861 prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -833,7 +879,7 @@ static void handle_keypress(int c)
833 display_weighted = ~display_weighted; 879 display_weighted = ~display_weighted;
834 break; 880 break;
835 case 'z': 881 case 'z':
836 zero = ~zero; 882 zero = !zero;
837 break; 883 break;
838 default: 884 default:
839 break; 885 break;
@@ -845,6 +891,7 @@ static void *display_thread(void *arg __used)
845 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 891 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
846 struct termios tc, save; 892 struct termios tc, save;
847 int delay_msecs, c; 893 int delay_msecs, c;
894 struct perf_session *session = (struct perf_session *) arg;
848 895
849 tcgetattr(0, &save); 896 tcgetattr(0, &save);
850 tc = save; 897 tc = save;
@@ -865,7 +912,7 @@ repeat:
865 c = getc(stdin); 912 c = getc(stdin);
866 tcsetattr(0, TCSAFLUSH, &save); 913 tcsetattr(0, TCSAFLUSH, &save);
867 914
868 handle_keypress(c); 915 handle_keypress(session, c);
869 goto repeat; 916 goto repeat;
870 917
871 return NULL; 918 return NULL;
@@ -910,8 +957,12 @@ static int symbol_filter(struct map *map, struct symbol *sym)
910 syme = symbol__priv(sym); 957 syme = symbol__priv(sym);
911 syme->map = map; 958 syme->map = map;
912 syme->src = NULL; 959 syme->src = NULL;
913 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) 960
914 sym_filter_entry = syme; 961 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) {
962 /* schedule initial sym_filter_entry setup */
963 sym_filter_entry_sched = syme;
964 sym_filter = NULL;
965 }
915 966
916 for (i = 0; skip_symbols[i]; i++) { 967 for (i = 0; skip_symbols[i]; i++) {
917 if (!strcmp(skip_symbols[i], name)) { 968 if (!strcmp(skip_symbols[i], name)) {
@@ -932,24 +983,92 @@ static void event__process_sample(const event_t *self,
932 u64 ip = self->ip.ip; 983 u64 ip = self->ip.ip;
933 struct sym_entry *syme; 984 struct sym_entry *syme;
934 struct addr_location al; 985 struct addr_location al;
986 struct sample_data data;
987 struct machine *machine;
935 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 988 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
936 989
990 ++samples;
991
937 switch (origin) { 992 switch (origin) {
938 case PERF_RECORD_MISC_USER: 993 case PERF_RECORD_MISC_USER:
994 ++us_samples;
939 if (hide_user_symbols) 995 if (hide_user_symbols)
940 return; 996 return;
997 machine = perf_session__find_host_machine(session);
941 break; 998 break;
942 case PERF_RECORD_MISC_KERNEL: 999 case PERF_RECORD_MISC_KERNEL:
1000 ++kernel_samples;
943 if (hide_kernel_symbols) 1001 if (hide_kernel_symbols)
944 return; 1002 return;
1003 machine = perf_session__find_host_machine(session);
1004 break;
1005 case PERF_RECORD_MISC_GUEST_KERNEL:
1006 ++guest_kernel_samples;
1007 machine = perf_session__find_machine(session, self->ip.pid);
945 break; 1008 break;
1009 case PERF_RECORD_MISC_GUEST_USER:
1010 ++guest_us_samples;
1011 /*
1012 * TODO: we don't process guest user from host side
1013 * except simple counting.
1014 */
1015 return;
946 default: 1016 default:
947 return; 1017 return;
948 } 1018 }
949 1019
950 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || 1020 if (!machine && perf_guest) {
951 al.sym == NULL || al.filtered) 1021 pr_err("Can't find guest [%d]'s kernel information\n",
1022 self->ip.pid);
952 return; 1023 return;
1024 }
1025
1026 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP)
1027 exact_samples++;
1028
1029 if (event__preprocess_sample(self, session, &al, &data,
1030 symbol_filter) < 0 ||
1031 al.filtered)
1032 return;
1033
1034 if (al.sym == NULL) {
1035 /*
1036 * As we do lazy loading of symtabs we only will know if the
1037 * specified vmlinux file is invalid when we actually have a
1038 * hit in kernel space and then try to load it. So if we get
1039 * here and there are _no_ symbols in the DSO backing the
1040 * kernel map, bail out.
1041 *
1042 * We may never get here, for instance, if we use -K/
1043 * --hide-kernel-symbols, even if the user specifies an
1044 * invalid --vmlinux ;-)
1045 */
1046 if (al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
1047 RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
1048 pr_err("The %s file can't be used\n",
1049 symbol_conf.vmlinux_name);
1050 exit(1);
1051 }
1052
1053 return;
1054 }
1055
1056 /* let's see, whether we need to install initial sym_filter_entry */
1057 if (sym_filter_entry_sched) {
1058 sym_filter_entry = sym_filter_entry_sched;
1059 sym_filter_entry_sched = NULL;
1060 if (parse_source(sym_filter_entry) < 0) {
1061 struct symbol *sym = sym_entry__symbol(sym_filter_entry);
1062
1063 pr_err("Can't annotate %s", sym->name);
1064 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) {
1065 pr_err(": No vmlinux file was found in the path:\n");
1066 machine__fprintf_vmlinux_path(machine, stderr);
1067 } else
1068 pr_err(".\n");
1069 exit(1);
1070 }
1071 }
953 1072
954 syme = symbol__priv(al.sym); 1073 syme = symbol__priv(al.sym);
955 if (!syme->skip) { 1074 if (!syme->skip) {
@@ -960,28 +1079,9 @@ static void event__process_sample(const event_t *self,
960 if (list_empty(&syme->node) || !syme->node.next) 1079 if (list_empty(&syme->node) || !syme->node.next)
961 __list_insert_active_sym(syme); 1080 __list_insert_active_sym(syme);
962 pthread_mutex_unlock(&active_symbols_lock); 1081 pthread_mutex_unlock(&active_symbols_lock);
963 if (origin == PERF_RECORD_MISC_USER)
964 ++userspace_samples;
965 ++samples;
966 } 1082 }
967} 1083}
968 1084
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 { 1085struct mmap_data {
986 int counter; 1086 int counter;
987 void *base; 1087 void *base;
@@ -1063,16 +1163,21 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1063 md->prev = old; 1163 md->prev = old;
1064} 1164}
1065 1165
1066static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 1166static struct pollfd *event_array;
1067static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 1167static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
1068 1168
1069static void perf_session__mmap_read(struct perf_session *self) 1169static void perf_session__mmap_read(struct perf_session *self)
1070{ 1170{
1071 int i, counter; 1171 int i, counter, thread_index;
1072 1172
1073 for (i = 0; i < nr_cpus; i++) { 1173 for (i = 0; i < nr_cpus; i++) {
1074 for (counter = 0; counter < nr_counters; counter++) 1174 for (counter = 0; counter < nr_counters; counter++)
1075 perf_session__mmap_read_counter(self, &mmap_array[i][counter]); 1175 for (thread_index = 0;
1176 thread_index < thread_num;
1177 thread_index++) {
1178 perf_session__mmap_read_counter(self,
1179 &mmap_array[i][counter][thread_index]);
1180 }
1076 } 1181 }
1077} 1182}
1078 1183
@@ -1083,10 +1188,11 @@ static void start_counter(int i, int counter)
1083{ 1188{
1084 struct perf_event_attr *attr; 1189 struct perf_event_attr *attr;
1085 int cpu; 1190 int cpu;
1191 int thread_index;
1086 1192
1087 cpu = profile_cpu; 1193 cpu = profile_cpu;
1088 if (target_pid == -1 && profile_cpu == -1) 1194 if (target_tid == -1 && profile_cpu == -1)
1089 cpu = i; 1195 cpu = cpumap[i];
1090 1196
1091 attr = attrs + counter; 1197 attr = attrs + counter;
1092 1198
@@ -1101,55 +1207,58 @@ static void start_counter(int i, int counter)
1101 attr->inherit = (cpu < 0) && inherit; 1207 attr->inherit = (cpu < 0) && inherit;
1102 attr->mmap = 1; 1208 attr->mmap = 1;
1103 1209
1210 for (thread_index = 0; thread_index < thread_num; thread_index++) {
1104try_again: 1211try_again:
1105 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0); 1212 fd[i][counter][thread_index] = sys_perf_event_open(attr,
1106 1213 all_tids[thread_index], cpu, group_fd, 0);
1107 if (fd[i][counter] < 0) { 1214
1108 int err = errno; 1215 if (fd[i][counter][thread_index] < 0) {
1216 int err = errno;
1217
1218 if (err == EPERM || err == EACCES)
1219 die("No permission - are you root?\n");
1220 /*
1221 * If it's cycles then fall back to hrtimer
1222 * based cpu-clock-tick sw counter, which
1223 * is always available even if no PMU support:
1224 */
1225 if (attr->type == PERF_TYPE_HARDWARE
1226 && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
1227
1228 if (verbose)
1229 warning(" ... trying to fall back to cpu-clock-ticks\n");
1230
1231 attr->type = PERF_TYPE_SOFTWARE;
1232 attr->config = PERF_COUNT_SW_CPU_CLOCK;
1233 goto try_again;
1234 }
1235 printf("\n");
1236 error("perfcounter syscall returned with %d (%s)\n",
1237 fd[i][counter][thread_index], strerror(err));
1238 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1239 exit(-1);
1240 }
1241 assert(fd[i][counter][thread_index] >= 0);
1242 fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK);
1109 1243
1110 if (err == EPERM || err == EACCES)
1111 die("No permission - are you root?\n");
1112 /* 1244 /*
1113 * If it's cycles then fall back to hrtimer 1245 * 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 */ 1246 */
1117 if (attr->type == PERF_TYPE_HARDWARE 1247 if (group && group_fd == -1)
1118 && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 1248 group_fd = fd[i][counter][thread_index];
1119 1249
1120 if (verbose) 1250 event_array[nr_poll].fd = fd[i][counter][thread_index];
1121 warning(" ... trying to fall back to cpu-clock-ticks\n"); 1251 event_array[nr_poll].events = POLLIN;
1122 1252 nr_poll++;
1123 attr->type = PERF_TYPE_SOFTWARE; 1253
1124 attr->config = PERF_COUNT_SW_CPU_CLOCK; 1254 mmap_array[i][counter][thread_index].counter = counter;
1125 goto try_again; 1255 mmap_array[i][counter][thread_index].prev = 0;
1126 } 1256 mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1;
1127 printf("\n"); 1257 mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size,
1128 error("perfcounter syscall returned with %d (%s)\n", 1258 PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0);
1129 fd[i][counter], strerror(err)); 1259 if (mmap_array[i][counter][thread_index].base == MAP_FAILED)
1130 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 1260 die("failed to mmap with %d (%s)\n", errno, strerror(errno));
1131 exit(-1);
1132 } 1261 }
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} 1262}
1154 1263
1155static int __cmd_top(void) 1264static int __cmd_top(void)
@@ -1161,12 +1270,12 @@ static int __cmd_top(void)
1161 * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 1270 * 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. 1271 * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1163 */ 1272 */
1164 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false); 1273 struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false);
1165 if (session == NULL) 1274 if (session == NULL)
1166 return -ENOMEM; 1275 return -ENOMEM;
1167 1276
1168 if (target_pid != -1) 1277 if (target_tid != -1)
1169 event__synthesize_thread(target_pid, event__process, session); 1278 event__synthesize_thread(target_tid, event__process, session);
1170 else 1279 else
1171 event__synthesize_threads(event__process, session); 1280 event__synthesize_threads(event__process, session);
1172 1281
@@ -1177,11 +1286,11 @@ static int __cmd_top(void)
1177 } 1286 }
1178 1287
1179 /* Wait for a minimal set of events before starting the snapshot */ 1288 /* Wait for a minimal set of events before starting the snapshot */
1180 poll(event_array, nr_poll, 100); 1289 poll(&event_array[0], nr_poll, 100);
1181 1290
1182 perf_session__mmap_read(session); 1291 perf_session__mmap_read(session);
1183 1292
1184 if (pthread_create(&thread, NULL, display_thread, NULL)) { 1293 if (pthread_create(&thread, NULL, display_thread, session)) {
1185 printf("Could not create display thread.\n"); 1294 printf("Could not create display thread.\n");
1186 exit(-1); 1295 exit(-1);
1187 } 1296 }
@@ -1220,17 +1329,18 @@ static const struct option options[] = {
1220 OPT_INTEGER('c', "count", &default_interval, 1329 OPT_INTEGER('c', "count", &default_interval,
1221 "event period to sample"), 1330 "event period to sample"),
1222 OPT_INTEGER('p', "pid", &target_pid, 1331 OPT_INTEGER('p', "pid", &target_pid,
1223 "profile events on existing pid"), 1332 "profile events on existing process id"),
1333 OPT_INTEGER('t', "tid", &target_tid,
1334 "profile events on existing thread id"),
1224 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1335 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1225 "system-wide collection from all CPUs"), 1336 "system-wide collection from all CPUs"),
1226 OPT_INTEGER('C', "CPU", &profile_cpu, 1337 OPT_STRING('C', "cpu", &cpu_list, "cpu",
1227 "CPU to profile on"), 1338 "list of cpus to monitor"),
1228 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1339 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1229 "file", "vmlinux pathname"), 1340 "file", "vmlinux pathname"),
1230 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 1341 OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
1231 "hide kernel symbols"), 1342 "hide kernel symbols"),
1232 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1343 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, 1344 OPT_INTEGER('r', "realtime", &realtime_prio,
1235 "collect data with this RT SCHED_FIFO priority"), 1345 "collect data with this RT SCHED_FIFO priority"),
1236 OPT_INTEGER('d', "delay", &delay_secs, 1346 OPT_INTEGER('d', "delay", &delay_secs,
@@ -1244,7 +1354,7 @@ static const struct option options[] = {
1244 OPT_BOOLEAN('i', "inherit", &inherit, 1354 OPT_BOOLEAN('i', "inherit", &inherit,
1245 "child tasks inherit counters"), 1355 "child tasks inherit counters"),
1246 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 1356 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
1247 "symbol to annotate - requires -k option"), 1357 "symbol to annotate"),
1248 OPT_BOOLEAN('z', "zero", &zero, 1358 OPT_BOOLEAN('z', "zero", &zero,
1249 "zero history across updates"), 1359 "zero history across updates"),
1250 OPT_INTEGER('F', "freq", &freq, 1360 OPT_INTEGER('F', "freq", &freq,
@@ -1253,7 +1363,7 @@ static const struct option options[] = {
1253 "display this many functions"), 1363 "display this many functions"),
1254 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 1364 OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols,
1255 "hide user symbols"), 1365 "hide user symbols"),
1256 OPT_BOOLEAN('v', "verbose", &verbose, 1366 OPT_INCR('v', "verbose", &verbose,
1257 "be more verbose (show counter open errors, etc)"), 1367 "be more verbose (show counter open errors, etc)"),
1258 OPT_END() 1368 OPT_END()
1259}; 1369};
@@ -1261,6 +1371,7 @@ static const struct option options[] = {
1261int cmd_top(int argc, const char **argv, const char *prefix __used) 1371int cmd_top(int argc, const char **argv, const char *prefix __used)
1262{ 1372{
1263 int counter; 1373 int counter;
1374 int i,j;
1264 1375
1265 page_size = sysconf(_SC_PAGE_SIZE); 1376 page_size = sysconf(_SC_PAGE_SIZE);
1266 1377
@@ -1268,11 +1379,42 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1268 if (argc) 1379 if (argc)
1269 usage_with_options(top_usage, options); 1380 usage_with_options(top_usage, options);
1270 1381
1382 if (target_pid != -1) {
1383 target_tid = target_pid;
1384 thread_num = find_all_tid(target_pid, &all_tids);
1385 if (thread_num <= 0) {
1386 fprintf(stderr, "Can't find all threads of pid %d\n",
1387 target_pid);
1388 usage_with_options(top_usage, options);
1389 }
1390 } else {
1391 all_tids=malloc(sizeof(pid_t));
1392 if (!all_tids)
1393 return -ENOMEM;
1394
1395 all_tids[0] = target_tid;
1396 thread_num = 1;
1397 }
1398
1399 for (i = 0; i < MAX_NR_CPUS; i++) {
1400 for (j = 0; j < MAX_COUNTERS; j++) {
1401 fd[i][j] = malloc(sizeof(int)*thread_num);
1402 mmap_array[i][j] = zalloc(
1403 sizeof(struct mmap_data)*thread_num);
1404 if (!fd[i][j] || !mmap_array[i][j])
1405 return -ENOMEM;
1406 }
1407 }
1408 event_array = malloc(
1409 sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num);
1410 if (!event_array)
1411 return -ENOMEM;
1412
1271 /* CPU and PID are mutually exclusive */ 1413 /* CPU and PID are mutually exclusive */
1272 if (target_pid != -1 && profile_cpu != -1) { 1414 if (target_tid > 0 && cpu_list) {
1273 printf("WARNING: PID switch overriding CPU\n"); 1415 printf("WARNING: PID switch overriding CPU\n");
1274 sleep(1); 1416 sleep(1);
1275 profile_cpu = -1; 1417 cpu_list = NULL;
1276 } 1418 }
1277 1419
1278 if (!nr_counters) 1420 if (!nr_counters)
@@ -1280,16 +1422,14 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1280 1422
1281 symbol_conf.priv_size = (sizeof(struct sym_entry) + 1423 symbol_conf.priv_size = (sizeof(struct sym_entry) +
1282 (nr_counters + 1) * sizeof(unsigned long)); 1424 (nr_counters + 1) * sizeof(unsigned long));
1283 if (symbol_conf.vmlinux_name == NULL) 1425
1284 symbol_conf.try_vmlinux_path = true; 1426 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1285 if (symbol__init() < 0) 1427 if (symbol__init() < 0)
1286 return -1; 1428 return -1;
1287 1429
1288 if (delay_secs < 1) 1430 if (delay_secs < 1)
1289 delay_secs = 1; 1431 delay_secs = 1;
1290 1432
1291 parse_source(sym_filter_entry);
1292
1293 /* 1433 /*
1294 * User specified count overrides default frequency. 1434 * User specified count overrides default frequency.
1295 */ 1435 */
@@ -1312,12 +1452,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1312 attrs[counter].sample_period = default_interval; 1452 attrs[counter].sample_period = default_interval;
1313 } 1453 }
1314 1454
1315 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 1455 if (target_tid != -1)
1316 assert(nr_cpus <= MAX_NR_CPUS);
1317 assert(nr_cpus >= 0);
1318
1319 if (target_pid != -1 || profile_cpu != -1)
1320 nr_cpus = 1; 1456 nr_cpus = 1;
1457 else
1458 nr_cpus = read_cpu_map(cpu_list);
1459
1460 if (nr_cpus < 1)
1461 usage_with_options(top_usage, options);
1321 1462
1322 get_term_dimensions(&winsize); 1463 get_term_dimensions(&winsize);
1323 if (print_entries == 0) { 1464 if (print_entries == 0) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 574a215e800b..40a6a2992d15 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1,16 +1,22 @@
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/util.h"
11 14
12static char const *script_name; 15static char const *script_name;
13static char const *generate_script_lang; 16static char const *generate_script_lang;
17static bool debug_mode;
18static u64 last_timestamp;
19static u64 nr_unordered;
14 20
15static int default_start_script(const char *script __unused, 21static int default_start_script(const char *script __unused,
16 int argc __unused, 22 int argc __unused,
@@ -44,23 +50,18 @@ static void setup_scripting(void)
44 perf_set_argv_exec_path(perf_exec_path()); 50 perf_set_argv_exec_path(perf_exec_path());
45 51
46 setup_perl_scripting(); 52 setup_perl_scripting();
53 setup_python_scripting();
47 54
48 scripting_ops = &default_scripting_ops; 55 scripting_ops = &default_scripting_ops;
49} 56}
50 57
51static int cleanup_scripting(void) 58static int cleanup_scripting(void)
52{ 59{
60 pr_debug("\nperf trace script stopped\n");
61
53 return scripting_ops->stop_script(); 62 return scripting_ops->stop_script();
54} 63}
55 64
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"; 65static char const *input_name = "perf.data";
65 66
66static int process_sample_event(event_t *event, struct perf_session *session) 67static int process_sample_event(event_t *event, struct perf_session *session)
@@ -75,11 +76,8 @@ static int process_sample_event(event_t *event, struct perf_session *session)
75 76
76 event__parse_sample(event, session->sample_type, &data); 77 event__parse_sample(event, session->sample_type, &data);
77 78
78 dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", 79 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
79 event->header.misc, 80 data.pid, data.tid, data.ip, data.period);
80 data.pid, data.tid,
81 (void *)(long)data.ip,
82 (long long)data.period);
83 81
84 thread = perf_session__findnew(session, event->ip.pid); 82 thread = perf_session__findnew(session, event->ip.pid);
85 if (thread == NULL) { 83 if (thread == NULL) {
@@ -89,6 +87,16 @@ static int process_sample_event(event_t *event, struct perf_session *session)
89 } 87 }
90 88
91 if (session->sample_type & PERF_SAMPLE_RAW) { 89 if (session->sample_type & PERF_SAMPLE_RAW) {
90 if (debug_mode) {
91 if (data.time < last_timestamp) {
92 pr_err("Samples misordered, previous: %llu "
93 "this: %llu\n", last_timestamp,
94 data.time);
95 nr_unordered++;
96 }
97 last_timestamp = data.time;
98 return 0;
99 }
92 /* 100 /*
93 * FIXME: better resolve from pid from the struct trace_entry 101 * FIXME: better resolve from pid from the struct trace_entry
94 * field, although it should be the same than this perf 102 * field, although it should be the same than this perf
@@ -99,31 +107,51 @@ static int process_sample_event(event_t *event, struct perf_session *session)
99 data.time, thread->comm); 107 data.time, thread->comm);
100 } 108 }
101 109
102 session->events_stats.total += data.period; 110 session->hists.stats.total_period += data.period;
103 return 0; 111 return 0;
104} 112}
105 113
106static int sample_type_check(struct perf_session *session) 114static u64 nr_lost;
115
116static int process_lost_event(event_t *event, struct perf_session *session __used)
107{ 117{
108 if (!(session->sample_type & PERF_SAMPLE_RAW)) { 118 nr_lost += event->lost.lost;
109 fprintf(stderr,
110 "No trace sample to read. Did you call perf record "
111 "without -R?");
112 return -1;
113 }
114 119
115 return 0; 120 return 0;
116} 121}
117 122
118static struct perf_event_ops event_ops = { 123static struct perf_event_ops event_ops = {
119 .process_sample_event = process_sample_event, 124 .sample = process_sample_event,
120 .process_comm_event = event__process_comm, 125 .comm = event__process_comm,
121 .sample_type_check = sample_type_check, 126 .attr = event__process_attr,
127 .event_type = event__process_event_type,
128 .tracing_data = event__process_tracing_data,
129 .build_id = event__process_build_id,
130 .lost = process_lost_event,
131 .ordered_samples = true,
122}; 132};
123 133
134extern volatile int session_done;
135
136static void sig_handler(int sig __unused)
137{
138 session_done = 1;
139}
140
124static int __cmd_trace(struct perf_session *session) 141static int __cmd_trace(struct perf_session *session)
125{ 142{
126 return perf_session__process_events(session, &event_ops); 143 int ret;
144
145 signal(SIGINT, sig_handler);
146
147 ret = perf_session__process_events(session, &event_ops);
148
149 if (debug_mode) {
150 pr_err("Misordered timestamps: %llu\n", nr_unordered);
151 pr_err("Lost events: %llu\n", nr_lost);
152 }
153
154 return ret;
127} 155}
128 156
129struct script_spec { 157struct script_spec {
@@ -235,9 +263,9 @@ static int parse_scriptname(const struct option *opt __used,
235 const char *script, *ext; 263 const char *script, *ext;
236 int len; 264 int len;
237 265
238 if (strcmp(str, "list") == 0) { 266 if (strcmp(str, "lang") == 0) {
239 list_available_languages(); 267 list_available_languages();
240 return 0; 268 exit(0);
241 } 269 }
242 270
243 script = strchr(str, ':'); 271 script = strchr(str, ':');
@@ -520,7 +548,7 @@ static const char * const trace_usage[] = {
520static const struct option options[] = { 548static const struct option options[] = {
521 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 549 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
522 "dump raw trace in ASCII"), 550 "dump raw trace in ASCII"),
523 OPT_BOOLEAN('v', "verbose", &verbose, 551 OPT_INCR('v', "verbose", &verbose,
524 "be more verbose (show symbol address, etc)"), 552 "be more verbose (show symbol address, etc)"),
525 OPT_BOOLEAN('L', "Latency", &latency_format, 553 OPT_BOOLEAN('L', "Latency", &latency_format,
526 "show latency attributes (irqs/preemption disabled, etc)"), 554 "show latency attributes (irqs/preemption disabled, etc)"),
@@ -531,6 +559,10 @@ static const struct option options[] = {
531 parse_scriptname), 559 parse_scriptname),
532 OPT_STRING('g', "gen-script", &generate_script_lang, "lang", 560 OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
533 "generate perf-trace.xx script in specified language"), 561 "generate perf-trace.xx script in specified language"),
562 OPT_STRING('i', "input", &input_name, "file",
563 "input file name"),
564 OPT_BOOLEAN('d', "debug-mode", &debug_mode,
565 "do various checks like samples ordering and lost events"),
534 566
535 OPT_END() 567 OPT_END()
536}; 568};
@@ -561,6 +593,65 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
561 suffix = REPORT_SUFFIX; 593 suffix = REPORT_SUFFIX;
562 } 594 }
563 595
596 if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) {
597 char *record_script_path, *report_script_path;
598 int live_pipe[2];
599 pid_t pid;
600
601 record_script_path = get_script_path(argv[1], RECORD_SUFFIX);
602 if (!record_script_path) {
603 fprintf(stderr, "record script not found\n");
604 return -1;
605 }
606
607 report_script_path = get_script_path(argv[1], REPORT_SUFFIX);
608 if (!report_script_path) {
609 fprintf(stderr, "report script not found\n");
610 return -1;
611 }
612
613 if (pipe(live_pipe) < 0) {
614 perror("failed to create pipe");
615 exit(-1);
616 }
617
618 pid = fork();
619 if (pid < 0) {
620 perror("failed to fork");
621 exit(-1);
622 }
623
624 if (!pid) {
625 dup2(live_pipe[1], 1);
626 close(live_pipe[0]);
627
628 __argv = malloc(5 * sizeof(const char *));
629 __argv[0] = "/bin/sh";
630 __argv[1] = record_script_path;
631 __argv[2] = "-o";
632 __argv[3] = "-";
633 __argv[4] = NULL;
634
635 execvp("/bin/sh", (char **)__argv);
636 exit(-1);
637 }
638
639 dup2(live_pipe[0], 0);
640 close(live_pipe[1]);
641
642 __argv = malloc((argc + 3) * sizeof(const char *));
643 __argv[0] = "/bin/sh";
644 __argv[1] = report_script_path;
645 for (i = 2; i < argc; i++)
646 __argv[i] = argv[i];
647 __argv[i++] = "-i";
648 __argv[i++] = "-";
649 __argv[i++] = NULL;
650
651 execvp("/bin/sh", (char **)__argv);
652 exit(-1);
653 }
654
564 if (suffix) { 655 if (suffix) {
565 script_path = get_script_path(argv[2], suffix); 656 script_path = get_script_path(argv[2], suffix);
566 if (!script_path) { 657 if (!script_path) {
@@ -586,12 +677,17 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
586 677
587 if (symbol__init() < 0) 678 if (symbol__init() < 0)
588 return -1; 679 return -1;
589 setup_pager(); 680 if (!script_name)
681 setup_pager();
590 682
591 session = perf_session__new(input_name, O_RDONLY, 0); 683 session = perf_session__new(input_name, O_RDONLY, 0, false);
592 if (session == NULL) 684 if (session == NULL)
593 return -ENOMEM; 685 return -ENOMEM;
594 686
687 if (strcmp(input_name, "-") &&
688 !perf_session__has_traces(session, "record -R"))
689 return -EINVAL;
690
595 if (generate_script_lang) { 691 if (generate_script_lang) {
596 struct stat perf_stat; 692 struct stat perf_stat;
597 693
@@ -618,7 +714,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
618 return -1; 714 return -1;
619 } 715 }
620 716
621 perf_header__read(&session->header, input);
622 err = scripting_ops->generate_script("perf-trace"); 717 err = scripting_ops->generate_script("perf-trace");
623 goto out; 718 goto out;
624 } 719 }
@@ -627,6 +722,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
627 err = scripting_ops->start_script(script_name, argc, argv); 722 err = scripting_ops->start_script(script_name, argc, argv);
628 if (err) 723 if (err)
629 goto out; 724 goto out;
725 pr_debug("perf trace started with script %s\n\n", script_name);
630 } 726 }
631 727
632 err = __cmd_trace(session); 728 err = __cmd_trace(session);
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 18035b1f16c7..921245b28583 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);
@@ -30,5 +31,9 @@ extern int cmd_trace(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..949d77fc0b97 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
@@ -16,3 +19,6 @@ perf-top mainporcelain common
16perf-trace mainporcelain common 19perf-trace 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..7a7b60859053
--- /dev/null
+++ b/tools/perf/feature-tests.mak
@@ -0,0 +1,119 @@
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 <libdw.h>
13#include <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
113# try-cc
114# Usage: option = $(call try-cc, source-to-build, cc-options)
115try-cc = $(shell sh -c \
116 'TMP="$(OUTPUT)$(TMPOUT).$$$$"; \
117 echo "$(1)" | \
118 $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
119 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..cdd6c03f1e14 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 },
@@ -301,6 +327,10 @@ static void handle_internal_command(int argc, const char **argv)
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..01a64ad693f2 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.c
@@ -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..549cf0467d30 100644
--- a/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
+++ b/tools/perf/scripts/perl/Perf-Trace-Util/Context.xs
@@ -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/trace-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/lib/Perf/Trace/Util.pm b/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace/Util.pm
index 052f132ced24..d94b40c8ac85 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,6 +56,11 @@ 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
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..eb5846bcb565
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/failed-syscalls-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -a -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..e3a5e55d54ff
--- /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 trace $@ -s ~/libexec/perf-core/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..5bfaae5a6cba 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 -a -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..d83070b7eeb5 100644
--- a/tools/perf/scripts/perl/bin/rw-by-file-report
+++ b/tools/perf/scripts/perl/bin/rw-by-file-report
@@ -1,7 +1,13 @@
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 echo "usage: rw-by-file <comm>"
6 exit
7fi
8comm=$1
9shift
10perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $comm
5 11
6 12
7 13
diff --git a/tools/perf/scripts/perl/bin/rw-by-pid-record b/tools/perf/scripts/perl/bin/rw-by-pid-record
index 8903979c5b6c..6e0b2f7755ac 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 -a -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..7ef46983f62f 100644
--- a/tools/perf/scripts/perl/bin/rw-by-pid-report
+++ b/tools/perf/scripts/perl/bin/rw-by-pid-report
@@ -1,6 +1,6 @@
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 trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
4 4
5 5
6 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..6e0b2f7755ac
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rwtop-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -a -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..93e698cd3f38
--- /dev/null
+++ b/tools/perf/scripts/perl/bin/rwtop-report
@@ -0,0 +1,23 @@
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 trace $@ -s ~/libexec/perf-core/scripts/perl/rwtop.pl $interval
21
22
23
diff --git a/tools/perf/scripts/perl/bin/wakeup-latency-record b/tools/perf/scripts/perl/bin/wakeup-latency-record
index 6abedda911a4..9f2acaaae9f0 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 -a -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..a0d898f9ca1d 100644
--- a/tools/perf/scripts/perl/bin/wakeup-latency-report
+++ b/tools/perf/scripts/perl/bin/wakeup-latency-report
@@ -1,6 +1,6 @@
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 trace $@ -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
4 4
5 5
6 6
diff --git a/tools/perf/scripts/perl/bin/workqueue-stats-record b/tools/perf/scripts/perl/bin/workqueue-stats-record
index fce6637b19ba..85301f2471ff 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 -a -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..35081132ef97 100644
--- a/tools/perf/scripts/perl/bin/workqueue-stats-report
+++ b/tools/perf/scripts/perl/bin/workqueue-stats-report
@@ -1,6 +1,6 @@
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 trace $@ -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
4 4
5 5
6 6
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-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..b84b12699b70 100644
--- a/tools/perf/scripts/perl/workqueue-stats.pl
+++ b/tools/perf/scripts/perl/workqueue-stats.pl
@@ -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..957085dd5d8d
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/Context.c
@@ -0,0 +1,88 @@
1/*
2 * Context.c. Python interfaces for perf trace.
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..aad7525bca1d
--- /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 trace, 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..ae9a56e43e05
--- /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 trace, 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..9689bc0acd9f
--- /dev/null
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -0,0 +1,28 @@
1# Util.py - Python extension for perf trace, 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
9NSECS_PER_SEC = 1000000000
10
11def avg(total, n):
12 return total / n
13
14def nsecs(secs, nsecs):
15 return secs * NSECS_PER_SEC + nsecs
16
17def nsecs_secs(nsecs):
18 return nsecs / NSECS_PER_SEC
19
20def nsecs_nsecs(nsecs):
21 return nsecs % NSECS_PER_SEC
22
23def nsecs_str(nsecs):
24 str = "%5u.%09u" % (nsecs_secs(nsecs), nsecs_nsecs(nsecs)),
25 return str
26
27def clear_term():
28 print("\x1b[H\x1b[2J")
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..eb5846bcb565
--- /dev/null
+++ b/tools/perf/scripts/python/bin/failed-syscalls-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -a -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..30293545fcc2
--- /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 trace $@ -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $comm
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..17a3e9bd9e8f
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sched-migration-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -m 16384 -a -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..61d05f72e443
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sched-migration-report
@@ -0,0 +1,3 @@
1#!/bin/bash
2# description: sched migration overview
3perf trace $@ -s ~/libexec/perf-core/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..1fc5998b721d
--- /dev/null
+++ b/tools/perf/scripts/python/bin/sctop-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -a -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..b01c842ae7b4
--- /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 trace $@ -s ~/libexec/perf-core/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..1fc5998b721d
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-by-pid-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -a -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..9e9d8ddd72ce
--- /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 trace $@ -s ~/libexec/perf-core/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..1fc5998b721d
--- /dev/null
+++ b/tools/perf/scripts/python/bin/syscall-counts-record
@@ -0,0 +1,2 @@
1#!/bin/bash
2perf record -a -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..dc076b618796
--- /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 trace $@ -s ~/libexec/perf-core/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..d9f7893e315c
--- /dev/null
+++ b/tools/perf/scripts/python/check-perf-trace.py
@@ -0,0 +1,82 @@
1# perf trace event handlers, generated by perf trace -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..0ca02278fe69
--- /dev/null
+++ b/tools/perf/scripts/python/failed-syscalls-by-pid.py
@@ -0,0 +1,68 @@
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 *
16
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_error_totals()
34
35def raw_syscalls__sys_exit(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, ret):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41
42 if ret < 0:
43 try:
44 syscalls[common_comm][common_pid][id][ret] += 1
45 except TypeError:
46 syscalls[common_comm][common_pid][id][ret] = 1
47
48def print_error_totals():
49 if for_comm is not None:
50 print "\nsyscall errors for %s:\n\n" % (for_comm),
51 else:
52 print "\nsyscall errors:\n\n",
53
54 print "%-30s %10s\n" % ("comm [pid]", "count"),
55 print "%-30s %10s\n" % ("------------------------------", \
56 "----------"),
57
58 comm_keys = syscalls.keys()
59 for comm in comm_keys:
60 pid_keys = syscalls[comm].keys()
61 for pid in pid_keys:
62 print "\n%s [%d]\n" % (comm, pid),
63 id_keys = syscalls[comm][pid].keys()
64 for id in id_keys:
65 print " syscall: %-16d\n" % (id),
66 ret_keys = syscalls[comm][pid][id].keys()
67 for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k), reverse = True):
68 print " err = %-20d %10d\n" % (ret, val),
diff --git a/tools/perf/scripts/python/sched-migration.py b/tools/perf/scripts/python/sched-migration.py
new file mode 100644
index 000000000000..b934383c3364
--- /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 trace event handlers have been generated by perf trace -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..6cafad40c296
--- /dev/null
+++ b/tools/perf/scripts/python/sctop.py
@@ -0,0 +1,78 @@
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 thread
12import time
13import os
14import sys
15
16sys.path.append(os.environ['PERF_EXEC_PATH'] + \
17 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
18
19from perf_trace_context import *
20from Core import *
21from Util import *
22
23usage = "perf trace -s syscall-counts.py [comm] [interval]\n";
24
25for_comm = None
26default_interval = 3
27interval = default_interval
28
29if len(sys.argv) > 3:
30 sys.exit(usage)
31
32if len(sys.argv) > 2:
33 for_comm = sys.argv[1]
34 interval = int(sys.argv[2])
35elif len(sys.argv) > 1:
36 try:
37 interval = int(sys.argv[1])
38 except ValueError:
39 for_comm = sys.argv[1]
40 interval = default_interval
41
42syscalls = autodict()
43
44def trace_begin():
45 thread.start_new_thread(print_syscall_totals, (interval,))
46 pass
47
48def raw_syscalls__sys_enter(event_name, context, common_cpu,
49 common_secs, common_nsecs, common_pid, common_comm,
50 id, args):
51 if for_comm is not None:
52 if common_comm != for_comm:
53 return
54 try:
55 syscalls[id] += 1
56 except TypeError:
57 syscalls[id] = 1
58
59def print_syscall_totals(interval):
60 while 1:
61 clear_term()
62 if for_comm is not None:
63 print "\nsyscall events for %s:\n\n" % (for_comm),
64 else:
65 print "\nsyscall events:\n\n",
66
67 print "%-40s %10s\n" % ("event", "count"),
68 print "%-40s %10s\n" % ("----------------------------------------", \
69 "----------"),
70
71 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
72 reverse = True):
73 try:
74 print "%-40d %10d\n" % (id, val),
75 except TypeError:
76 pass
77 syscalls.clear()
78 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..af722d6a4b3f
--- /dev/null
+++ b/tools/perf/scripts/python/syscall-counts-by-pid.py
@@ -0,0 +1,64 @@
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
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 *
16
17usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_syscall_totals()
34
35def raw_syscalls__sys_enter(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, args):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41 try:
42 syscalls[common_comm][common_pid][id] += 1
43 except TypeError:
44 syscalls[common_comm][common_pid][id] = 1
45
46def print_syscall_totals():
47 if for_comm is not None:
48 print "\nsyscall events for %s:\n\n" % (for_comm),
49 else:
50 print "\nsyscall events by comm/pid:\n\n",
51
52 print "%-40s %10s\n" % ("comm [pid]/syscalls", "count"),
53 print "%-40s %10s\n" % ("----------------------------------------", \
54 "----------"),
55
56 comm_keys = syscalls.keys()
57 for comm in comm_keys:
58 pid_keys = syscalls[comm].keys()
59 for pid in pid_keys:
60 print "\n%s [%d]\n" % (comm, pid),
61 id_keys = syscalls[comm][pid].keys()
62 for id, val in sorted(syscalls[comm][pid].iteritems(), \
63 key = lambda(k, v): (v, k), reverse = True):
64 print " %-38d %10d\n" % (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..f977e85ff049
--- /dev/null
+++ b/tools/perf/scripts/python/syscall-counts.py
@@ -0,0 +1,58 @@
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 *
16
17usage = "perf trace -s syscall-counts.py [comm]\n";
18
19for_comm = None
20
21if len(sys.argv) > 2:
22 sys.exit(usage)
23
24if len(sys.argv) > 1:
25 for_comm = sys.argv[1]
26
27syscalls = autodict()
28
29def trace_begin():
30 pass
31
32def trace_end():
33 print_syscall_totals()
34
35def raw_syscalls__sys_enter(event_name, context, common_cpu,
36 common_secs, common_nsecs, common_pid, common_comm,
37 id, args):
38 if for_comm is not None:
39 if common_comm != for_comm:
40 return
41 try:
42 syscalls[id] += 1
43 except TypeError:
44 syscalls[id] = 1
45
46def print_syscall_totals():
47 if for_comm is not None:
48 print "\nsyscall events for %s:\n\n" % (for_comm),
49 else:
50 print "\nsyscall events:\n\n",
51
52 print "%-40s %10s\n" % ("event", "count"),
53 print "%-40s %10s\n" % ("----------------------------------------", \
54 "-----------"),
55
56 for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
57 reverse = True):
58 print "%-40d %10d\n" % (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..e437edb72417
--- /dev/null
+++ b/tools/perf/util/build-id.c
@@ -0,0 +1,77 @@
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, struct perf_session *session)
18{
19 struct addr_location al;
20 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
21 struct thread *thread = perf_session__findnew(session, event->ip.pid);
22
23 if (thread == NULL) {
24 pr_err("problem processing %d event, skipping it.\n",
25 event->header.type);
26 return -1;
27 }
28
29 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
30 event->ip.pid, event->ip.ip, &al);
31
32 if (al.map != NULL)
33 al.map->dso->hit = 1;
34
35 return 0;
36}
37
38static int event__exit_del_thread(event_t *self, struct perf_session *session)
39{
40 struct thread *thread = perf_session__findnew(session, self->fork.tid);
41
42 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
43 self->fork.ppid, self->fork.ptid);
44
45 if (thread) {
46 rb_erase(&thread->rb_node, &session->threads);
47 session->last_match = NULL;
48 thread__delete(thread);
49 }
50
51 return 0;
52}
53
54struct perf_event_ops build_id__mark_dso_hit_ops = {
55 .sample = build_id__mark_dso_hit,
56 .mmap = event__process_mmap,
57 .fork = event__process_task,
58 .exit = event__exit_del_thread,
59};
60
61char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
62{
63 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
64
65 if (!self->has_build_id)
66 return NULL;
67
68 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
69 if (bf == NULL) {
70 if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
71 build_id_hex, build_id_hex + 2) < 0)
72 return NULL;
73 } else
74 snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
75 build_id_hex, build_id_hex + 2);
76 return bf;
77}
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..27e9ebe4076e 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,22 +73,12 @@ 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
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index b3b71258272a..f231f43424d2 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,8 +15,16 @@
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
@@ -160,7 +168,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
160{ 168{
161 struct callchain_node *new; 169 struct callchain_node *new;
162 170
163 new = malloc(sizeof(*new)); 171 new = zalloc(sizeof(*new));
164 if (!new) { 172 if (!new) {
165 perror("not enough memory to create child for code path tree"); 173 perror("not enough memory to create child for code path tree");
166 return NULL; 174 return NULL;
@@ -183,25 +191,36 @@ create_child(struct callchain_node *parent, bool inherit_children)
183 return new; 191 return new;
184} 192}
185 193
194
195struct resolved_ip {
196 u64 ip;
197 struct map_symbol ms;
198};
199
200struct resolved_chain {
201 u64 nr;
202 struct resolved_ip ips[0];
203};
204
205
186/* 206/*
187 * Fill the node with callchain values 207 * Fill the node with callchain values
188 */ 208 */
189static void 209static void
190fill_node(struct callchain_node *node, struct ip_callchain *chain, 210fill_node(struct callchain_node *node, struct resolved_chain *chain, int start)
191 int start, struct symbol **syms)
192{ 211{
193 unsigned int i; 212 unsigned int i;
194 213
195 for (i = start; i < chain->nr; i++) { 214 for (i = start; i < chain->nr; i++) {
196 struct callchain_list *call; 215 struct callchain_list *call;
197 216
198 call = malloc(sizeof(*call)); 217 call = zalloc(sizeof(*call));
199 if (!call) { 218 if (!call) {
200 perror("not enough memory for the code path tree"); 219 perror("not enough memory for the code path tree");
201 return; 220 return;
202 } 221 }
203 call->ip = chain->ips[i]; 222 call->ip = chain->ips[i].ip;
204 call->sym = syms[i]; 223 call->ms = chain->ips[i].ms;
205 list_add_tail(&call->list, &node->val); 224 list_add_tail(&call->list, &node->val);
206 } 225 }
207 node->val_nr = chain->nr - start; 226 node->val_nr = chain->nr - start;
@@ -210,16 +229,16 @@ fill_node(struct callchain_node *node, struct ip_callchain *chain,
210} 229}
211 230
212static void 231static void
213add_child(struct callchain_node *parent, struct ip_callchain *chain, 232add_child(struct callchain_node *parent, struct resolved_chain *chain,
214 int start, struct symbol **syms) 233 int start, u64 period)
215{ 234{
216 struct callchain_node *new; 235 struct callchain_node *new;
217 236
218 new = create_child(parent, false); 237 new = create_child(parent, false);
219 fill_node(new, chain, start, syms); 238 fill_node(new, chain, start);
220 239
221 new->children_hit = 0; 240 new->children_hit = 0;
222 new->hit = 1; 241 new->hit = period;
223} 242}
224 243
225/* 244/*
@@ -228,9 +247,9 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,
228 * Then create another child to host the given callchain of new branch 247 * Then create another child to host the given callchain of new branch
229 */ 248 */
230static void 249static void
231split_add_child(struct callchain_node *parent, struct ip_callchain *chain, 250split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
232 struct callchain_list *to_split, int idx_parents, int idx_local, 251 struct callchain_list *to_split, int idx_parents, int idx_local,
233 struct symbol **syms) 252 u64 period)
234{ 253{
235 struct callchain_node *new; 254 struct callchain_node *new;
236 struct list_head *old_tail; 255 struct list_head *old_tail;
@@ -257,40 +276,41 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,
257 /* create a new child for the new branch if any */ 276 /* create a new child for the new branch if any */
258 if (idx_total < chain->nr) { 277 if (idx_total < chain->nr) {
259 parent->hit = 0; 278 parent->hit = 0;
260 add_child(parent, chain, idx_total, syms); 279 add_child(parent, chain, idx_total, period);
261 parent->children_hit++; 280 parent->children_hit += period;
262 } else { 281 } else {
263 parent->hit = 1; 282 parent->hit = period;
264 } 283 }
265} 284}
266 285
267static int 286static int
268__append_chain(struct callchain_node *root, struct ip_callchain *chain, 287__append_chain(struct callchain_node *root, struct resolved_chain *chain,
269 unsigned int start, struct symbol **syms); 288 unsigned int start, u64 period);
270 289
271static void 290static void
272__append_chain_children(struct callchain_node *root, struct ip_callchain *chain, 291__append_chain_children(struct callchain_node *root,
273 struct symbol **syms, unsigned int start) 292 struct resolved_chain *chain,
293 unsigned int start, u64 period)
274{ 294{
275 struct callchain_node *rnode; 295 struct callchain_node *rnode;
276 296
277 /* lookup in childrens */ 297 /* lookup in childrens */
278 chain_for_each_child(rnode, root) { 298 chain_for_each_child(rnode, root) {
279 unsigned int ret = __append_chain(rnode, chain, start, syms); 299 unsigned int ret = __append_chain(rnode, chain, start, period);
280 300
281 if (!ret) 301 if (!ret)
282 goto inc_children_hit; 302 goto inc_children_hit;
283 } 303 }
284 /* nothing in children, add to the current node */ 304 /* nothing in children, add to the current node */
285 add_child(root, chain, start, syms); 305 add_child(root, chain, start, period);
286 306
287inc_children_hit: 307inc_children_hit:
288 root->children_hit++; 308 root->children_hit += period;
289} 309}
290 310
291static int 311static int
292__append_chain(struct callchain_node *root, struct ip_callchain *chain, 312__append_chain(struct callchain_node *root, struct resolved_chain *chain,
293 unsigned int start, struct symbol **syms) 313 unsigned int start, u64 period)
294{ 314{
295 struct callchain_list *cnode; 315 struct callchain_list *cnode;
296 unsigned int i = start; 316 unsigned int i = start;
@@ -302,13 +322,19 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
302 * anywhere inside a function. 322 * anywhere inside a function.
303 */ 323 */
304 list_for_each_entry(cnode, &root->val, list) { 324 list_for_each_entry(cnode, &root->val, list) {
325 struct symbol *sym;
326
305 if (i == chain->nr) 327 if (i == chain->nr)
306 break; 328 break;
307 if (cnode->sym && syms[i]) { 329
308 if (cnode->sym->start != syms[i]->start) 330 sym = chain->ips[i].ms.sym;
331
332 if (cnode->ms.sym && sym) {
333 if (cnode->ms.sym->start != sym->start)
309 break; 334 break;
310 } else if (cnode->ip != chain->ips[i]) 335 } else if (cnode->ip != chain->ips[i].ip)
311 break; 336 break;
337
312 if (!found) 338 if (!found)
313 found = true; 339 found = true;
314 i++; 340 i++;
@@ -320,26 +346,61 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,
320 346
321 /* we match only a part of the node. Split it and add the new chain */ 347 /* we match only a part of the node. Split it and add the new chain */
322 if (i - start < root->val_nr) { 348 if (i - start < root->val_nr) {
323 split_add_child(root, chain, cnode, start, i - start, syms); 349 split_add_child(root, chain, cnode, start, i - start, period);
324 return 0; 350 return 0;
325 } 351 }
326 352
327 /* we match 100% of the path, increment the hit */ 353 /* we match 100% of the path, increment the hit */
328 if (i - start == root->val_nr && i == chain->nr) { 354 if (i - start == root->val_nr && i == chain->nr) {
329 root->hit++; 355 root->hit += period;
330 return 0; 356 return 0;
331 } 357 }
332 358
333 /* We match the node and still have a part remaining */ 359 /* We match the node and still have a part remaining */
334 __append_chain_children(root, chain, syms, i); 360 __append_chain_children(root, chain, i, period);
335 361
336 return 0; 362 return 0;
337} 363}
338 364
339void append_chain(struct callchain_node *root, struct ip_callchain *chain, 365static void filter_context(struct ip_callchain *old, struct resolved_chain *new,
340 struct symbol **syms) 366 struct map_symbol *syms)
341{ 367{
368 int i, j = 0;
369
370 for (i = 0; i < (int)old->nr; i++) {
371 if (old->ips[i] >= PERF_CONTEXT_MAX)
372 continue;
373
374 new->ips[j].ip = old->ips[i];
375 new->ips[j].ms = syms[i];
376 j++;
377 }
378
379 new->nr = j;
380}
381
382
383int append_chain(struct callchain_node *root, struct ip_callchain *chain,
384 struct map_symbol *syms, u64 period)
385{
386 struct resolved_chain *filtered;
387
342 if (!chain->nr) 388 if (!chain->nr)
343 return; 389 return 0;
344 __append_chain_children(root, chain, syms, 0); 390
391 filtered = zalloc(sizeof(*filtered) +
392 chain->nr * sizeof(struct resolved_ip));
393 if (!filtered)
394 return -ENOMEM;
395
396 filter_context(chain, filtered, syms);
397
398 if (!filtered->nr)
399 goto end;
400
401 __append_chain_children(root, filtered, 0, period);
402end:
403 free(filtered);
404
405 return 0;
345} 406}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index ad4626de4c2b..6de4313924fb 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 {
@@ -33,13 +33,14 @@ typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
33 33
34struct callchain_param { 34struct callchain_param {
35 enum chain_mode mode; 35 enum chain_mode mode;
36 u32 print_limit;
36 double min_percent; 37 double min_percent;
37 sort_chain_func_t sort; 38 sort_chain_func_t sort;
38}; 39};
39 40
40struct callchain_list { 41struct callchain_list {
41 u64 ip; 42 u64 ip;
42 struct symbol *sym; 43 struct map_symbol ms;
43 struct list_head list; 44 struct list_head list;
44}; 45};
45 46
@@ -48,6 +49,10 @@ static inline void callchain_init(struct callchain_node *node)
48 INIT_LIST_HEAD(&node->brothers); 49 INIT_LIST_HEAD(&node->brothers);
49 INIT_LIST_HEAD(&node->children); 50 INIT_LIST_HEAD(&node->children);
50 INIT_LIST_HEAD(&node->val); 51 INIT_LIST_HEAD(&node->val);
52
53 node->children_hit = 0;
54 node->parent = NULL;
55 node->hit = 0;
51} 56}
52 57
53static inline u64 cumul_hits(struct callchain_node *node) 58static inline u64 cumul_hits(struct callchain_node *node)
@@ -56,6 +61,8 @@ static inline u64 cumul_hits(struct callchain_node *node)
56} 61}
57 62
58int register_callchain_param(struct callchain_param *param); 63int register_callchain_param(struct callchain_param *param);
59void append_chain(struct callchain_node *root, struct ip_callchain *chain, 64int append_chain(struct callchain_node *root, struct ip_callchain *chain,
60 struct symbol **syms); 65 struct map_symbol *syms, u64 period);
66
67bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
61#endif /* __PERF_CALLCHAIN_H */ 68#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..0f9b8d7a7d7e
--- /dev/null
+++ b/tools/perf/util/cpumap.c
@@ -0,0 +1,114 @@
1#include "util.h"
2#include "../perf.h"
3#include "cpumap.h"
4#include <assert.h>
5#include <stdio.h>
6
7int cpumap[MAX_NR_CPUS];
8
9static int default_cpu_map(void)
10{
11 int nr_cpus, i;
12
13 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
14 assert(nr_cpus <= MAX_NR_CPUS);
15 assert((int)nr_cpus >= 0);
16
17 for (i = 0; i < nr_cpus; ++i)
18 cpumap[i] = i;
19
20 return nr_cpus;
21}
22
23static int read_all_cpu_map(void)
24{
25 FILE *onlnf;
26 int nr_cpus = 0;
27 int n, cpu, prev;
28 char sep;
29
30 onlnf = fopen("/sys/devices/system/cpu/online", "r");
31 if (!onlnf)
32 return default_cpu_map();
33
34 sep = 0;
35 prev = -1;
36 for (;;) {
37 n = fscanf(onlnf, "%u%c", &cpu, &sep);
38 if (n <= 0)
39 break;
40 if (prev >= 0) {
41 assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS);
42 while (++prev < cpu)
43 cpumap[nr_cpus++] = prev;
44 }
45 assert (nr_cpus < MAX_NR_CPUS);
46 cpumap[nr_cpus++] = cpu;
47 if (n == 2 && sep == '-')
48 prev = cpu;
49 else
50 prev = -1;
51 if (n == 1 || sep == '\n')
52 break;
53 }
54 fclose(onlnf);
55 if (nr_cpus > 0)
56 return nr_cpus;
57
58 return default_cpu_map();
59}
60
61int read_cpu_map(const char *cpu_list)
62{
63 unsigned long start_cpu, end_cpu = 0;
64 char *p = NULL;
65 int i, nr_cpus = 0;
66
67 if (!cpu_list)
68 return read_all_cpu_map();
69
70 if (!isdigit(*cpu_list))
71 goto invalid;
72
73 while (isdigit(*cpu_list)) {
74 p = NULL;
75 start_cpu = strtoul(cpu_list, &p, 0);
76 if (start_cpu >= INT_MAX
77 || (*p != '\0' && *p != ',' && *p != '-'))
78 goto invalid;
79
80 if (*p == '-') {
81 cpu_list = ++p;
82 p = NULL;
83 end_cpu = strtoul(cpu_list, &p, 0);
84
85 if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
86 goto invalid;
87
88 if (end_cpu < start_cpu)
89 goto invalid;
90 } else {
91 end_cpu = start_cpu;
92 }
93
94 for (; start_cpu <= end_cpu; start_cpu++) {
95 /* check for duplicates */
96 for (i = 0; i < nr_cpus; i++)
97 if (cpumap[i] == (int)start_cpu)
98 goto invalid;
99
100 assert(nr_cpus < MAX_NR_CPUS);
101 cpumap[nr_cpus++] = (int)start_cpu;
102 }
103 if (*p)
104 ++p;
105
106 cpu_list = p;
107 }
108 if (nr_cpus > 0)
109 return nr_cpus;
110
111 return default_cpu_map();
112invalid:
113 return -1;
114}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
new file mode 100644
index 000000000000..3e60f56e490e
--- /dev/null
+++ b/tools/perf/util/cpumap.h
@@ -0,0 +1,7 @@
1#ifndef __PERF_CPUMAP_H
2#define __PERF_CPUMAP_H
3
4extern int read_cpu_map(const char *cpu_list);
5extern int cpumap[];
6
7#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..f9c7e3ad1aa7 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 = 0;
14int dump_trace = 0; 16bool dump_trace = 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
@@ -81,12 +86,10 @@ void trace_event(event_t *event)
81 dump_printf_color(" ", color); 86 dump_printf_color(" ", color);
82 for (j = 0; j < 15-(i & 15); j++) 87 for (j = 0; j < 15-(i & 15); j++)
83 dump_printf_color(" ", color); 88 dump_printf_color(" ", color);
84 for (j = 0; j < (i & 15); j++) { 89 for (j = i & ~15; j <= i; j++) {
85 if (isprint(raw_event[i-15+j])) 90 dump_printf_color("%c", color,
86 dump_printf_color("%c", color, 91 isprint(raw_event[j]) ?
87 raw_event[i-15+j]); 92 raw_event[j] : '.');
88 else
89 dump_printf_color(".", color);
90 } 93 }
91 dump_printf_color("\n", color); 94 dump_printf_color("\n", color);
92 } 95 }
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index c6c24c522dea..7a17ee061bcb 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -2,14 +2,37 @@
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 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
15#endif /* __PERF_DEBUG_H */ 38#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..dab9e754a281 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -7,9 +7,25 @@
7#include "strlist.h" 7#include "strlist.h"
8#include "thread.h" 8#include "thread.h"
9 9
10const char *event__name[] = {
11 [0] = "TOTAL",
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};
26
10static pid_t event__synthesize_comm(pid_t pid, int full, 27static pid_t event__synthesize_comm(pid_t pid, int full,
11 int (*process)(event_t *event, 28 event__handler_t process,
12 struct perf_session *session),
13 struct perf_session *session) 29 struct perf_session *session)
14{ 30{
15 event_t ev; 31 event_t ev;
@@ -91,8 +107,7 @@ out_failure:
91} 107}
92 108
93static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 109static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
94 int (*process)(event_t *event, 110 event__handler_t process,
95 struct perf_session *session),
96 struct perf_session *session) 111 struct perf_session *session)
97{ 112{
98 char filename[PATH_MAX]; 113 char filename[PATH_MAX];
@@ -112,7 +127,14 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
112 while (1) { 127 while (1) {
113 char bf[BUFSIZ], *pbf = bf; 128 char bf[BUFSIZ], *pbf = bf;
114 event_t ev = { 129 event_t ev = {
115 .header = { .type = PERF_RECORD_MMAP }, 130 .header = {
131 .type = PERF_RECORD_MMAP,
132 /*
133 * Just like the kernel, see __perf_event_mmap
134 * in kernel/perf_event.c
135 */
136 .misc = PERF_RECORD_MISC_USER,
137 },
116 }; 138 };
117 int n; 139 int n;
118 size_t size; 140 size_t size;
@@ -138,6 +160,9 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
138 if (execname == NULL) 160 if (execname == NULL)
139 continue; 161 continue;
140 162
163 pbf += 3;
164 n = hex2u64(pbf, &ev.mmap.pgoff);
165
141 size = strlen(execname); 166 size = strlen(execname);
142 execname[size - 1] = '\0'; /* Remove \n */ 167 execname[size - 1] = '\0'; /* Remove \n */
143 memcpy(ev.mmap.filename, execname, size); 168 memcpy(ev.mmap.filename, execname, size);
@@ -156,9 +181,51 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
156 return 0; 181 return 0;
157} 182}
158 183
159int event__synthesize_thread(pid_t pid, 184int event__synthesize_modules(event__handler_t process,
160 int (*process)(event_t *event, 185 struct perf_session *session,
161 struct perf_session *session), 186 struct machine *machine)
187{
188 struct rb_node *nd;
189 struct map_groups *kmaps = &machine->kmaps;
190 u16 misc;
191
192 /*
193 * kernel uses 0 for user space maps, see kernel/perf_event.c
194 * __perf_event_mmap
195 */
196 if (machine__is_host(machine))
197 misc = PERF_RECORD_MISC_KERNEL;
198 else
199 misc = PERF_RECORD_MISC_GUEST_KERNEL;
200
201 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
202 nd; nd = rb_next(nd)) {
203 event_t ev;
204 size_t size;
205 struct map *pos = rb_entry(nd, struct map, rb_node);
206
207 if (pos->dso->kernel)
208 continue;
209
210 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
211 memset(&ev, 0, sizeof(ev));
212 ev.mmap.header.misc = misc;
213 ev.mmap.header.type = PERF_RECORD_MMAP;
214 ev.mmap.header.size = (sizeof(ev.mmap) -
215 (sizeof(ev.mmap.filename) - size));
216 ev.mmap.start = pos->start;
217 ev.mmap.len = pos->end - pos->start;
218 ev.mmap.pid = machine->pid;
219
220 memcpy(ev.mmap.filename, pos->dso->long_name,
221 pos->dso->long_name_len + 1);
222 process(&ev, session);
223 }
224
225 return 0;
226}
227
228int event__synthesize_thread(pid_t pid, event__handler_t process,
162 struct perf_session *session) 229 struct perf_session *session)
163{ 230{
164 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 231 pid_t tgid = event__synthesize_comm(pid, 1, process, session);
@@ -167,8 +234,7 @@ int event__synthesize_thread(pid_t pid,
167 return event__synthesize_mmap_events(pid, tgid, process, session); 234 return event__synthesize_mmap_events(pid, tgid, process, session);
168} 235}
169 236
170void event__synthesize_threads(int (*process)(event_t *event, 237void event__synthesize_threads(event__handler_t process,
171 struct perf_session *session),
172 struct perf_session *session) 238 struct perf_session *session)
173{ 239{
174 DIR *proc; 240 DIR *proc;
@@ -189,41 +255,120 @@ void event__synthesize_threads(int (*process)(event_t *event,
189 closedir(proc); 255 closedir(proc);
190} 256}
191 257
192static void thread__comm_adjust(struct thread *self) 258struct process_symbol_args {
259 const char *name;
260 u64 start;
261};
262
263static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
264{
265 struct process_symbol_args *args = arg;
266
267 /*
268 * Must be a function or at least an alias, as in PARISC64, where "_text" is
269 * an 'A' to the same address as "_stext".
270 */
271 if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
272 type == 'A') || strcmp(name, args->name))
273 return 0;
274
275 args->start = start;
276 return 1;
277}
278
279int event__synthesize_kernel_mmap(event__handler_t process,
280 struct perf_session *session,
281 struct machine *machine,
282 const char *symbol_name)
283{
284 size_t size;
285 const char *filename, *mmap_name;
286 char path[PATH_MAX];
287 char name_buff[PATH_MAX];
288 struct map *map;
289
290 event_t ev = {
291 .header = {
292 .type = PERF_RECORD_MMAP,
293 },
294 };
295 /*
296 * We should get this from /sys/kernel/sections/.text, but till that is
297 * available use this, and after it is use this as a fallback for older
298 * kernels.
299 */
300 struct process_symbol_args args = { .name = symbol_name, };
301
302 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
303 if (machine__is_host(machine)) {
304 /*
305 * kernel uses PERF_RECORD_MISC_USER for user space maps,
306 * see kernel/perf_event.c __perf_event_mmap
307 */
308 ev.header.misc = PERF_RECORD_MISC_KERNEL;
309 filename = "/proc/kallsyms";
310 } else {
311 ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
312 if (machine__is_default_guest(machine))
313 filename = (char *) symbol_conf.default_guest_kallsyms;
314 else {
315 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
316 filename = path;
317 }
318 }
319
320 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
321 return -ENOENT;
322
323 map = machine->vmlinux_maps[MAP__FUNCTION];
324 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
325 "%s%s", mmap_name, symbol_name) + 1;
326 size = ALIGN(size, sizeof(u64));
327 ev.mmap.header.size = (sizeof(ev.mmap) -
328 (sizeof(ev.mmap.filename) - size));
329 ev.mmap.pgoff = args.start;
330 ev.mmap.start = map->start;
331 ev.mmap.len = map->end - ev.mmap.start;
332 ev.mmap.pid = machine->pid;
333
334 return process(&ev, session);
335}
336
337static void thread__comm_adjust(struct thread *self, struct hists *hists)
193{ 338{
194 char *comm = self->comm; 339 char *comm = self->comm;
195 340
196 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 341 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
197 (!symbol_conf.comm_list || 342 (!symbol_conf.comm_list ||
198 strlist__has_entry(symbol_conf.comm_list, comm))) { 343 strlist__has_entry(symbol_conf.comm_list, comm))) {
199 unsigned int slen = strlen(comm); 344 u16 slen = strlen(comm);
200 345
201 if (slen > comms__col_width) { 346 if (hists__new_col_len(hists, HISTC_COMM, slen))
202 comms__col_width = slen; 347 hists__set_col_len(hists, HISTC_THREAD, slen + 6);
203 threads__col_width = slen + 6;
204 }
205 } 348 }
206} 349}
207 350
208static int thread__set_comm_adjust(struct thread *self, const char *comm) 351static int thread__set_comm_adjust(struct thread *self, const char *comm,
352 struct hists *hists)
209{ 353{
210 int ret = thread__set_comm(self, comm); 354 int ret = thread__set_comm(self, comm);
211 355
212 if (ret) 356 if (ret)
213 return ret; 357 return ret;
214 358
215 thread__comm_adjust(self); 359 thread__comm_adjust(self, hists);
216 360
217 return 0; 361 return 0;
218} 362}
219 363
220int event__process_comm(event_t *self, struct perf_session *session) 364int event__process_comm(event_t *self, struct perf_session *session)
221{ 365{
222 struct thread *thread = perf_session__findnew(session, self->comm.pid); 366 struct thread *thread = perf_session__findnew(session, self->comm.tid);
223 367
224 dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); 368 dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
225 369
226 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) { 370 if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm,
371 &session->hists)) {
227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 372 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
228 return -1; 373 return -1;
229 } 374 }
@@ -234,46 +379,165 @@ int event__process_comm(event_t *self, struct perf_session *session)
234int event__process_lost(event_t *self, struct perf_session *session) 379int event__process_lost(event_t *self, struct perf_session *session)
235{ 380{
236 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost); 381 dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
237 session->events_stats.lost += self->lost.lost; 382 session->hists.stats.total_lost += self->lost.lost;
238 return 0; 383 return 0;
239} 384}
240 385
241int event__process_mmap(event_t *self, struct perf_session *session) 386static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
242{ 387{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid); 388 maps[MAP__FUNCTION]->start = self->mmap.start;
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 389 maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
245 session->cwd, session->cwdlen); 390 /*
246 391 * Be a bit paranoid here, some perf.data file came with
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 392 * a zero sized synthesized MMAP event for the kernel.
248 self->mmap.pid, self->mmap.tid, 393 */
249 (void *)(long)self->mmap.start, 394 if (maps[MAP__FUNCTION]->end == 0)
250 (void *)(long)self->mmap.len, 395 maps[MAP__FUNCTION]->end = ~0UL;
251 (void *)(long)self->mmap.pgoff, 396}
252 self->mmap.filename); 397
253 398static int event__process_kernel_mmap(event_t *self,
254 if (thread == NULL || map == NULL) 399 struct perf_session *session)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 400{
401 struct map *map;
402 char kmmap_prefix[PATH_MAX];
403 struct machine *machine;
404 enum dso_kernel_type kernel_type;
405 bool is_kernel_mmap;
406
407 machine = perf_session__findnew_machine(session, self->mmap.pid);
408 if (!machine) {
409 pr_err("Can't find id %d's machine\n", self->mmap.pid);
410 goto out_problem;
411 }
412
413 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
414 if (machine__is_host(machine))
415 kernel_type = DSO_TYPE_KERNEL;
256 else 416 else
257 thread__insert_map(thread, map); 417 kernel_type = DSO_TYPE_GUEST_KERNEL;
418
419 is_kernel_mmap = memcmp(self->mmap.filename,
420 kmmap_prefix,
421 strlen(kmmap_prefix)) == 0;
422 if (self->mmap.filename[0] == '/' ||
423 (!is_kernel_mmap && self->mmap.filename[0] == '[')) {
424
425 char short_module_name[1024];
426 char *name, *dot;
427
428 if (self->mmap.filename[0] == '/') {
429 name = strrchr(self->mmap.filename, '/');
430 if (name == NULL)
431 goto out_problem;
432
433 ++name; /* skip / */
434 dot = strrchr(name, '.');
435 if (dot == NULL)
436 goto out_problem;
437 snprintf(short_module_name, sizeof(short_module_name),
438 "[%.*s]", (int)(dot - name), name);
439 strxfrchar(short_module_name, '-', '_');
440 } else
441 strcpy(short_module_name, self->mmap.filename);
442
443 map = machine__new_module(machine, self->mmap.start,
444 self->mmap.filename);
445 if (map == NULL)
446 goto out_problem;
447
448 name = strdup(short_module_name);
449 if (name == NULL)
450 goto out_problem;
451
452 map->dso->short_name = name;
453 map->dso->sname_alloc = 1;
454 map->end = map->start + self->mmap.len;
455 } else if (is_kernel_mmap) {
456 const char *symbol_name = (self->mmap.filename +
457 strlen(kmmap_prefix));
458 /*
459 * Should be there already, from the build-id table in
460 * the header.
461 */
462 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
463 kmmap_prefix);
464 if (kernel == NULL)
465 goto out_problem;
466
467 kernel->kernel = kernel_type;
468 if (__machine__create_kernel_maps(machine, kernel) < 0)
469 goto out_problem;
470
471 event_set_kernel_mmap_len(machine->vmlinux_maps, self);
472 perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
473 symbol_name,
474 self->mmap.pgoff);
475 if (machine__is_default_guest(machine)) {
476 /*
477 * preload dso of guest kernel and modules
478 */
479 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
480 NULL);
481 }
482 }
483 return 0;
484out_problem:
485 return -1;
486}
487
488int event__process_mmap(event_t *self, struct perf_session *session)
489{
490 struct machine *machine;
491 struct thread *thread;
492 struct map *map;
493 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
494 int ret = 0;
495
496 dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
497 self->mmap.pid, self->mmap.tid, self->mmap.start,
498 self->mmap.len, self->mmap.pgoff, self->mmap.filename);
258 499
500 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
501 cpumode == PERF_RECORD_MISC_KERNEL) {
502 ret = event__process_kernel_mmap(self, session);
503 if (ret < 0)
504 goto out_problem;
505 return 0;
506 }
507
508 machine = perf_session__find_host_machine(session);
509 if (machine == NULL)
510 goto out_problem;
511 thread = perf_session__findnew(session, self->mmap.pid);
512 if (thread == NULL)
513 goto out_problem;
514 map = map__new(&machine->user_dsos, self->mmap.start,
515 self->mmap.len, self->mmap.pgoff,
516 self->mmap.pid, self->mmap.filename,
517 MAP__FUNCTION);
518 if (map == NULL)
519 goto out_problem;
520
521 thread__insert_map(thread, map);
522 return 0;
523
524out_problem:
525 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
259 return 0; 526 return 0;
260} 527}
261 528
262int event__process_task(event_t *self, struct perf_session *session) 529int event__process_task(event_t *self, struct perf_session *session)
263{ 530{
264 struct thread *thread = perf_session__findnew(session, self->fork.pid); 531 struct thread *thread = perf_session__findnew(session, self->fork.tid);
265 struct thread *parent = perf_session__findnew(session, self->fork.ppid); 532 struct thread *parent = perf_session__findnew(session, self->fork.ptid);
266 533
267 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, 534 dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
268 self->fork.ppid, self->fork.ptid); 535 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 536
275 if (self->header.type == PERF_RECORD_EXIT) 537 if (self->header.type == PERF_RECORD_EXIT) {
538 perf_session__remove_thread(session, thread);
276 return 0; 539 return 0;
540 }
277 541
278 if (thread == NULL || parent == NULL || 542 if (thread == NULL || parent == NULL ||
279 thread__fork(thread, parent) < 0) { 543 thread__fork(thread, parent) < 0) {
@@ -284,26 +548,78 @@ int event__process_task(event_t *self, struct perf_session *session)
284 return 0; 548 return 0;
285} 549}
286 550
287void thread__find_addr_location(struct thread *self, 551int event__process(event_t *event, struct perf_session *session)
288 struct perf_session *session, u8 cpumode, 552{
289 enum map_type type, u64 addr, 553 switch (event->header.type) {
290 struct addr_location *al, 554 case PERF_RECORD_COMM:
291 symbol_filter_t filter) 555 event__process_comm(event, session);
556 break;
557 case PERF_RECORD_MMAP:
558 event__process_mmap(event, session);
559 break;
560 case PERF_RECORD_FORK:
561 case PERF_RECORD_EXIT:
562 event__process_task(event, session);
563 break;
564 default:
565 break;
566 }
567
568 return 0;
569}
570
571void thread__find_addr_map(struct thread *self,
572 struct perf_session *session, u8 cpumode,
573 enum map_type type, pid_t pid, u64 addr,
574 struct addr_location *al)
292{ 575{
293 struct map_groups *mg = &self->mg; 576 struct map_groups *mg = &self->mg;
577 struct machine *machine = NULL;
294 578
295 al->thread = self; 579 al->thread = self;
296 al->addr = addr; 580 al->addr = addr;
581 al->cpumode = cpumode;
582 al->filtered = false;
297 583
298 if (cpumode & PERF_RECORD_MISC_KERNEL) { 584 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
299 al->level = 'k'; 585 al->level = 'k';
300 mg = &session->kmaps; 586 machine = perf_session__find_host_machine(session);
301 } else if (cpumode & PERF_RECORD_MISC_USER) 587 if (machine == NULL) {
588 al->map = NULL;
589 return;
590 }
591 mg = &machine->kmaps;
592 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
302 al->level = '.'; 593 al->level = '.';
303 else { 594 machine = perf_session__find_host_machine(session);
304 al->level = 'H'; 595 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
596 al->level = 'g';
597 machine = perf_session__find_machine(session, pid);
598 if (machine == NULL) {
599 al->map = NULL;
600 return;
601 }
602 mg = &machine->kmaps;
603 } else {
604 /*
605 * 'u' means guest os user space.
606 * TODO: We don't support guest user space. Might support late.
607 */
608 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
609 al->level = 'u';
610 else
611 al->level = 'H';
305 al->map = NULL; 612 al->map = NULL;
306 al->sym = NULL; 613
614 if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
615 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
616 !perf_guest)
617 al->filtered = true;
618 if ((cpumode == PERF_RECORD_MISC_USER ||
619 cpumode == PERF_RECORD_MISC_KERNEL) &&
620 !perf_host)
621 al->filtered = true;
622
307 return; 623 return;
308 } 624 }
309try_again: 625try_again:
@@ -318,36 +634,72 @@ try_again:
318 * "[vdso]" dso, but for now lets use the old trick of looking 634 * "[vdso]" dso, but for now lets use the old trick of looking
319 * in the whole kernel symbol list. 635 * in the whole kernel symbol list.
320 */ 636 */
321 if ((long long)al->addr < 0 && mg != &session->kmaps) { 637 if ((long long)al->addr < 0 &&
322 mg = &session->kmaps; 638 cpumode == PERF_RECORD_MISC_KERNEL &&
639 machine && mg != &machine->kmaps) {
640 mg = &machine->kmaps;
323 goto try_again; 641 goto try_again;
324 } 642 }
325 al->sym = NULL; 643 } else
326 } else {
327 al->addr = al->map->map_ip(al->map, al->addr); 644 al->addr = al->map->map_ip(al->map, al->addr);
328 al->sym = map__find_symbol(al->map, session, al->addr, filter);
329 }
330} 645}
331 646
332static void dso__calc_col_width(struct dso *self) 647void thread__find_addr_location(struct thread *self,
648 struct perf_session *session, u8 cpumode,
649 enum map_type type, pid_t pid, u64 addr,
650 struct addr_location *al,
651 symbol_filter_t filter)
652{
653 thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
654 if (al->map != NULL)
655 al->sym = map__find_symbol(al->map, al->addr, filter);
656 else
657 al->sym = NULL;
658}
659
660static void dso__calc_col_width(struct dso *self, struct hists *hists)
333{ 661{
334 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep && 662 if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
335 (!symbol_conf.dso_list || 663 (!symbol_conf.dso_list ||
336 strlist__has_entry(symbol_conf.dso_list, self->name))) { 664 strlist__has_entry(symbol_conf.dso_list, self->name))) {
337 unsigned int slen = strlen(self->name); 665 u16 slen = dso__name_len(self);
338 if (slen > dsos__col_width) 666 hists__new_col_len(hists, HISTC_DSO, slen);
339 dsos__col_width = slen;
340 } 667 }
341 668
342 self->slen_calculated = 1; 669 self->slen_calculated = 1;
343} 670}
344 671
345int event__preprocess_sample(const event_t *self, struct perf_session *session, 672int event__preprocess_sample(const event_t *self, struct perf_session *session,
346 struct addr_location *al, symbol_filter_t filter) 673 struct addr_location *al, struct sample_data *data,
674 symbol_filter_t filter)
347{ 675{
348 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 676 u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
349 struct thread *thread = perf_session__findnew(session, self->ip.pid); 677 struct thread *thread;
678
679 event__parse_sample(self, session->sample_type, data);
680
681 dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n",
682 self->header.misc, data->pid, data->tid, data->ip,
683 data->period, data->cpu);
684
685 if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
686 unsigned int i;
687
688 dump_printf("... chain: nr:%Lu\n", data->callchain->nr);
689
690 if (!ip_callchain__valid(data->callchain, self)) {
691 pr_debug("call-chain problem with event, "
692 "skipping it.\n");
693 goto out_filtered;
694 }
350 695
696 if (dump_trace) {
697 for (i = 0; i < data->callchain->nr; i++)
698 dump_printf("..... %2d: %016Lx\n",
699 i, data->callchain->ips[i]);
700 }
701 }
702 thread = perf_session__findnew(session, self->ip.pid);
351 if (thread == NULL) 703 if (thread == NULL)
352 return -1; 704 return -1;
353 705
@@ -356,31 +708,57 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
356 goto out_filtered; 708 goto out_filtered;
357 709
358 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 710 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
711 /*
712 * Have we already created the kernel maps for the host machine?
713 *
714 * This should have happened earlier, when we processed the kernel MMAP
715 * events, but for older perf.data files there was no such thing, so do
716 * it now.
717 */
718 if (cpumode == PERF_RECORD_MISC_KERNEL &&
719 session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL)
720 machine__create_kernel_maps(&session->host_machine);
359 721
360 thread__find_addr_location(thread, session, cpumode, MAP__FUNCTION, 722 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
361 self->ip.ip, al, filter); 723 self->ip.pid, self->ip.ip, al);
362 dump_printf(" ...... dso: %s\n", 724 dump_printf(" ...... dso: %s\n",
363 al->map ? al->map->dso->long_name : 725 al->map ? al->map->dso->long_name :
364 al->level == 'H' ? "[hypervisor]" : "<not found>"); 726 al->level == 'H' ? "[hypervisor]" : "<not found>");
365 /* 727 al->sym = NULL;
366 * We have to do this here as we may have a dso with no symbol hit that 728 al->cpu = data->cpu;
367 * has a name longer than the ones with symbols sampled. 729
368 */ 730 if (al->map) {
369 if (al->map && !sort_dso.elide && !al->map->dso->slen_calculated) 731 if (symbol_conf.dso_list &&
370 dso__calc_col_width(al->map->dso); 732 (!al->map || !al->map->dso ||
371 733 !(strlist__has_entry(symbol_conf.dso_list,
372 if (symbol_conf.dso_list && 734 al->map->dso->short_name) ||
373 (!al->map || !al->map->dso || 735 (al->map->dso->short_name != al->map->dso->long_name &&
374 !(strlist__has_entry(symbol_conf.dso_list, al->map->dso->short_name) || 736 strlist__has_entry(symbol_conf.dso_list,
375 (al->map->dso->short_name != al->map->dso->long_name && 737 al->map->dso->long_name)))))
376 strlist__has_entry(symbol_conf.dso_list, al->map->dso->long_name))))) 738 goto out_filtered;
377 goto out_filtered; 739 /*
740 * We have to do this here as we may have a dso with no symbol
741 * hit that has a name longer than the ones with symbols
742 * sampled.
743 */
744 if (!sort_dso.elide && !al->map->dso->slen_calculated)
745 dso__calc_col_width(al->map->dso, &session->hists);
746
747 al->sym = map__find_symbol(al->map, al->addr, filter);
748 } else {
749 const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
750
751 if (hists__col_len(&session->hists, HISTC_DSO) < unresolved_col_width &&
752 !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
753 !symbol_conf.dso_list)
754 hists__set_col_len(&session->hists, HISTC_DSO,
755 unresolved_col_width);
756 }
378 757
379 if (symbol_conf.sym_list && al->sym && 758 if (symbol_conf.sym_list && al->sym &&
380 !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) 759 !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
381 goto out_filtered; 760 goto out_filtered;
382 761
383 al->filtered = false;
384 return 0; 762 return 0;
385 763
386out_filtered: 764out_filtered:
@@ -388,9 +766,9 @@ out_filtered:
388 return 0; 766 return 0;
389} 767}
390 768
391int event__parse_sample(event_t *event, u64 type, struct sample_data *data) 769int event__parse_sample(const event_t *event, u64 type, struct sample_data *data)
392{ 770{
393 u64 *array = event->sample.array; 771 const u64 *array = event->sample.array;
394 772
395 if (type & PERF_SAMPLE_IP) { 773 if (type & PERF_SAMPLE_IP) {
396 data->ip = event->ip.ip; 774 data->ip = event->ip.ip;
@@ -414,6 +792,7 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
414 array++; 792 array++;
415 } 793 }
416 794
795 data->id = -1ULL;
417 if (type & PERF_SAMPLE_ID) { 796 if (type & PERF_SAMPLE_ID) {
418 data->id = *array; 797 data->id = *array;
419 array++; 798 array++;
@@ -428,7 +807,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
428 u32 *p = (u32 *)array; 807 u32 *p = (u32 *)array;
429 data->cpu = *p; 808 data->cpu = *p;
430 array++; 809 array++;
431 } 810 } else
811 data->cpu = -1;
432 812
433 if (type & PERF_SAMPLE_PERIOD) { 813 if (type & PERF_SAMPLE_PERIOD) {
434 data->period = *array; 814 data->period = *array;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 690a96d0467c..8e790dae7026 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,54 @@ 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_HEADER_ATTR = 64,
89 PERF_RECORD_HEADER_EVENT_TYPE = 65,
90 PERF_RECORD_HEADER_TRACING_DATA = 66,
91 PERF_RECORD_HEADER_BUILD_ID = 67,
92 PERF_RECORD_FINISHED_ROUND = 68,
93 PERF_RECORD_HEADER_MAX
94};
95
96struct attr_event {
97 struct perf_event_header header;
98 struct perf_event_attr attr;
99 u64 id[];
100};
101
102#define MAX_EVENT_NAME 64
103
104struct perf_trace_event_type {
105 u64 event_id;
106 char name[MAX_EVENT_NAME];
107};
108
109struct event_type_event {
110 struct perf_event_header header;
111 struct perf_trace_event_type event_type;
112};
113
114struct tracing_data_event {
115 struct perf_event_header header;
116 u32 size;
117};
118
86typedef union event_union { 119typedef union event_union {
87 struct perf_event_header header; 120 struct perf_event_header header;
88 struct ip_event ip; 121 struct ip_event ip;
@@ -92,92 +125,43 @@ typedef union event_union {
92 struct lost_event lost; 125 struct lost_event lost;
93 struct read_event read; 126 struct read_event read;
94 struct sample_event sample; 127 struct sample_event sample;
128 struct attr_event attr;
129 struct event_type_event event_type;
130 struct tracing_data_event tracing_data;
131 struct build_id_event build_id;
95} event_t; 132} event_t;
96 133
97struct events_stats {
98 u64 total;
99 u64 lost;
100};
101
102void event__print_totals(void); 134void event__print_totals(void);
103 135
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; 136struct perf_session;
154 137
155int map__load(struct map *self, struct perf_session *session, 138typedef int (*event__handler_t)(event_t *event, struct perf_session *session);
156 symbol_filter_t filter); 139
157struct symbol *map__find_symbol(struct map *self, struct perf_session *session, 140int event__synthesize_thread(pid_t pid, event__handler_t process,
158 u64 addr, symbol_filter_t filter);
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); 141 struct perf_session *session);
169void event__synthesize_threads(int (*process)(event_t *event, 142void event__synthesize_threads(event__handler_t process,
170 struct perf_session *session),
171 struct perf_session *session); 143 struct perf_session *session);
144int event__synthesize_kernel_mmap(event__handler_t process,
145 struct perf_session *session,
146 struct machine *machine,
147 const char *symbol_name);
148
149int event__synthesize_modules(event__handler_t process,
150 struct perf_session *session,
151 struct machine *machine);
172 152
173int event__process_comm(event_t *self, struct perf_session *session); 153int event__process_comm(event_t *self, struct perf_session *session);
174int event__process_lost(event_t *self, struct perf_session *session); 154int event__process_lost(event_t *self, struct perf_session *session);
175int event__process_mmap(event_t *self, struct perf_session *session); 155int event__process_mmap(event_t *self, struct perf_session *session);
176int event__process_task(event_t *self, struct perf_session *session); 156int event__process_task(event_t *self, struct perf_session *session);
157int event__process(event_t *event, struct perf_session *session);
177 158
178struct addr_location; 159struct addr_location;
179int event__preprocess_sample(const event_t *self, struct perf_session *session, 160int event__preprocess_sample(const event_t *self, struct perf_session *session,
180 struct addr_location *al, symbol_filter_t filter); 161 struct addr_location *al, struct sample_data *data,
181int event__parse_sample(event_t *event, u64 type, struct sample_data *data); 162 symbol_filter_t filter);
163int event__parse_sample(const event_t *event, u64 type, struct sample_data *data);
164
165extern const char *event__name[];
182 166
183#endif /* __PERF_RECORD_H */ 167#endif /* __PERF_RECORD_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..d7e67b167ea3 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)
@@ -169,31 +172,50 @@ static int do_write(int fd, const void *buf, size_t size)
169 return 0; 172 return 0;
170} 173}
171 174
172static int __dsos__write_buildid_table(struct list_head *head, int fd) 175#define NAME_ALIGN 64
176
177static int write_padded(int fd, const void *bf, size_t count,
178 size_t count_aligned)
173{ 179{
174#define NAME_ALIGN 64
175 struct dso *pos;
176 static const char zero_buf[NAME_ALIGN]; 180 static const char zero_buf[NAME_ALIGN];
181 int err = do_write(fd, bf, count);
182
183 if (!err)
184 err = do_write(fd, zero_buf, count_aligned - count);
185
186 return err;
187}
188
189#define dsos__for_each_with_build_id(pos, head) \
190 list_for_each_entry(pos, head, node) \
191 if (!pos->has_build_id) \
192 continue; \
193 else
177 194
178 list_for_each_entry(pos, head, node) { 195static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
196 u16 misc, int fd)
197{
198 struct dso *pos;
199
200 dsos__for_each_with_build_id(pos, head) {
179 int err; 201 int err;
180 struct build_id_event b; 202 struct build_id_event b;
181 size_t len; 203 size_t len;
182 204
183 if (!pos->has_build_id) 205 if (!pos->hit)
184 continue; 206 continue;
185 len = pos->long_name_len + 1; 207 len = pos->long_name_len + 1;
186 len = ALIGN(len, NAME_ALIGN); 208 len = ALIGN(len, NAME_ALIGN);
187 memset(&b, 0, sizeof(b)); 209 memset(&b, 0, sizeof(b));
188 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); 210 memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
211 b.pid = pid;
212 b.header.misc = misc;
189 b.header.size = sizeof(b) + len; 213 b.header.size = sizeof(b) + len;
190 err = do_write(fd, &b, sizeof(b)); 214 err = do_write(fd, &b, sizeof(b));
191 if (err < 0) 215 if (err < 0)
192 return err; 216 return err;
193 err = do_write(fd, pos->long_name, pos->long_name_len + 1); 217 err = write_padded(fd, pos->long_name,
194 if (err < 0) 218 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) 219 if (err < 0)
198 return err; 220 return err;
199 } 221 }
@@ -201,23 +223,215 @@ static int __dsos__write_buildid_table(struct list_head *head, int fd)
201 return 0; 223 return 0;
202} 224}
203 225
204static int dsos__write_buildid_table(int fd) 226static int machine__write_buildid_table(struct machine *self, int fd)
205{ 227{
206 int err = __dsos__write_buildid_table(&dsos__kernel, fd); 228 int err;
229 u16 kmisc = PERF_RECORD_MISC_KERNEL,
230 umisc = PERF_RECORD_MISC_USER;
231
232 if (!machine__is_host(self)) {
233 kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
234 umisc = PERF_RECORD_MISC_GUEST_USER;
235 }
236
237 err = __dsos__write_buildid_table(&self->kernel_dsos, self->pid,
238 kmisc, fd);
207 if (err == 0) 239 if (err == 0)
208 err = __dsos__write_buildid_table(&dsos__user, fd); 240 err = __dsos__write_buildid_table(&self->user_dsos,
241 self->pid, umisc, fd);
242 return err;
243}
244
245static int dsos__write_buildid_table(struct perf_header *header, int fd)
246{
247 struct perf_session *session = container_of(header,
248 struct perf_session, header);
249 struct rb_node *nd;
250 int err = machine__write_buildid_table(&session->host_machine, fd);
251
252 if (err)
253 return err;
254
255 for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
256 struct machine *pos = rb_entry(nd, struct machine, rb_node);
257 err = machine__write_buildid_table(pos, fd);
258 if (err)
259 break;
260 }
261 return err;
262}
263
264int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
265 const char *name, bool is_kallsyms)
266{
267 const size_t size = PATH_MAX;
268 char *filename = malloc(size),
269 *linkname = malloc(size), *targetname;
270 int len, err = -1;
271
272 if (filename == NULL || linkname == NULL)
273 goto out_free;
274
275 len = snprintf(filename, size, "%s%s%s",
276 debugdir, is_kallsyms ? "/" : "", name);
277 if (mkdir_p(filename, 0755))
278 goto out_free;
279
280 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id);
281
282 if (access(filename, F_OK)) {
283 if (is_kallsyms) {
284 if (copyfile("/proc/kallsyms", filename))
285 goto out_free;
286 } else if (link(name, filename) && copyfile(name, filename))
287 goto out_free;
288 }
289
290 len = snprintf(linkname, size, "%s/.build-id/%.2s",
291 debugdir, sbuild_id);
292
293 if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
294 goto out_free;
295
296 snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
297 targetname = filename + strlen(debugdir) - 5;
298 memcpy(targetname, "../..", 5);
299
300 if (symlink(targetname, linkname) == 0)
301 err = 0;
302out_free:
303 free(filename);
304 free(linkname);
305 return err;
306}
307
308static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
309 const char *name, const char *debugdir,
310 bool is_kallsyms)
311{
312 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
313
314 build_id__sprintf(build_id, build_id_size, sbuild_id);
315
316 return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms);
317}
318
319int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
320{
321 const size_t size = PATH_MAX;
322 char *filename = malloc(size),
323 *linkname = malloc(size);
324 int err = -1;
325
326 if (filename == NULL || linkname == NULL)
327 goto out_free;
328
329 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
330 debugdir, sbuild_id, sbuild_id + 2);
331
332 if (access(linkname, F_OK))
333 goto out_free;
334
335 if (readlink(linkname, filename, size) < 0)
336 goto out_free;
337
338 if (unlink(linkname))
339 goto out_free;
340
341 /*
342 * Since the link is relative, we must make it absolute:
343 */
344 snprintf(linkname, size, "%s/.build-id/%.2s/%s",
345 debugdir, sbuild_id, filename);
346
347 if (unlink(linkname))
348 goto out_free;
349
350 err = 0;
351out_free:
352 free(filename);
353 free(linkname);
354 return err;
355}
356
357static int dso__cache_build_id(struct dso *self, const char *debugdir)
358{
359 bool is_kallsyms = self->kernel && self->long_name[0] != '/';
360
361 return build_id_cache__add_b(self->build_id, sizeof(self->build_id),
362 self->long_name, debugdir, is_kallsyms);
363}
364
365static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
366{
367 struct dso *pos;
368 int err = 0;
369
370 dsos__for_each_with_build_id(pos, head)
371 if (dso__cache_build_id(pos, debugdir))
372 err = -1;
373
209 return err; 374 return err;
210} 375}
211 376
377static int machine__cache_build_ids(struct machine *self, const char *debugdir)
378{
379 int ret = __dsos__cache_build_ids(&self->kernel_dsos, debugdir);
380 ret |= __dsos__cache_build_ids(&self->user_dsos, debugdir);
381 return ret;
382}
383
384static int perf_session__cache_build_ids(struct perf_session *self)
385{
386 struct rb_node *nd;
387 int ret;
388 char debugdir[PATH_MAX];
389
390 snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
391
392 if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
393 return -1;
394
395 ret = machine__cache_build_ids(&self->host_machine, debugdir);
396
397 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
398 struct machine *pos = rb_entry(nd, struct machine, rb_node);
399 ret |= machine__cache_build_ids(pos, debugdir);
400 }
401 return ret ? -1 : 0;
402}
403
404static bool machine__read_build_ids(struct machine *self, bool with_hits)
405{
406 bool ret = __dsos__read_build_ids(&self->kernel_dsos, with_hits);
407 ret |= __dsos__read_build_ids(&self->user_dsos, with_hits);
408 return ret;
409}
410
411static bool perf_session__read_build_ids(struct perf_session *self, bool with_hits)
412{
413 struct rb_node *nd;
414 bool ret = machine__read_build_ids(&self->host_machine, with_hits);
415
416 for (nd = rb_first(&self->machines); nd; nd = rb_next(nd)) {
417 struct machine *pos = rb_entry(nd, struct machine, rb_node);
418 ret |= machine__read_build_ids(pos, with_hits);
419 }
420
421 return ret;
422}
423
212static int perf_header__adds_write(struct perf_header *self, int fd) 424static int perf_header__adds_write(struct perf_header *self, int fd)
213{ 425{
214 int nr_sections; 426 int nr_sections;
427 struct perf_session *session;
215 struct perf_file_section *feat_sec; 428 struct perf_file_section *feat_sec;
216 int sec_size; 429 int sec_size;
217 u64 sec_start; 430 u64 sec_start;
218 int idx = 0, err; 431 int idx = 0, err;
219 432
220 if (dsos__read_build_ids()) 433 session = container_of(self, struct perf_session, header);
434 if (perf_session__read_build_ids(session, true))
221 perf_header__set_feat(self, HEADER_BUILD_ID); 435 perf_header__set_feat(self, HEADER_BUILD_ID);
222 436
223 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 437 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
@@ -244,7 +458,6 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
244 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; 458 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
245 } 459 }
246 460
247
248 if (perf_header__has_feat(self, HEADER_BUILD_ID)) { 461 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
249 struct perf_file_section *buildid_sec; 462 struct perf_file_section *buildid_sec;
250 463
@@ -252,12 +465,15 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
252 465
253 /* Write build-ids */ 466 /* Write build-ids */
254 buildid_sec->offset = lseek(fd, 0, SEEK_CUR); 467 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
255 err = dsos__write_buildid_table(fd); 468 err = dsos__write_buildid_table(self, fd);
256 if (err < 0) { 469 if (err < 0) {
257 pr_debug("failed to write buildid table\n"); 470 pr_debug("failed to write buildid table\n");
258 goto out_free; 471 goto out_free;
259 } 472 }
260 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; 473 buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
474 buildid_sec->offset;
475 if (!no_buildid_cache)
476 perf_session__cache_build_ids(session);
261 } 477 }
262 478
263 lseek(fd, sec_start, SEEK_SET); 479 lseek(fd, sec_start, SEEK_SET);
@@ -269,6 +485,25 @@ out_free:
269 return err; 485 return err;
270} 486}
271 487
488int perf_header__write_pipe(int fd)
489{
490 struct perf_pipe_file_header f_header;
491 int err;
492
493 f_header = (struct perf_pipe_file_header){
494 .magic = PERF_MAGIC,
495 .size = sizeof(f_header),
496 };
497
498 err = do_write(fd, &f_header, sizeof(f_header));
499 if (err < 0) {
500 pr_debug("failed to write perf pipe header\n");
501 return err;
502 }
503
504 return 0;
505}
506
272int perf_header__write(struct perf_header *self, int fd, bool at_exit) 507int perf_header__write(struct perf_header *self, int fd, bool at_exit)
273{ 508{
274 struct perf_file_header f_header; 509 struct perf_file_header f_header;
@@ -278,7 +513,6 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
278 513
279 lseek(fd, sizeof(f_header), SEEK_SET); 514 lseek(fd, sizeof(f_header), SEEK_SET);
280 515
281
282 for (i = 0; i < self->attrs; i++) { 516 for (i = 0; i < self->attrs; i++) {
283 attr = self->attr[i]; 517 attr = self->attr[i];
284 518
@@ -360,30 +594,28 @@ int perf_header__write(struct perf_header *self, int fd, bool at_exit)
360 return 0; 594 return 0;
361} 595}
362 596
363static void do_read(int fd, void *buf, size_t size) 597static int perf_header__getbuffer64(struct perf_header *self,
598 int fd, void *buf, size_t size)
364{ 599{
365 while (size) { 600 if (do_read(fd, buf, size) <= 0)
366 int ret = read(fd, buf, size); 601 return -1;
367 602
368 if (ret < 0) 603 if (self->needs_swap)
369 die("failed to read"); 604 mem_bswap_64(buf, size);
370 if (ret == 0)
371 die("failed to read: missing data");
372 605
373 size -= ret; 606 return 0;
374 buf += ret;
375 }
376} 607}
377 608
378int perf_header__process_sections(struct perf_header *self, int fd, 609int perf_header__process_sections(struct perf_header *self, int fd,
379 int (*process)(struct perf_file_section *self, 610 int (*process)(struct perf_file_section *self,
611 struct perf_header *ph,
380 int feat, int fd)) 612 int feat, int fd))
381{ 613{
382 struct perf_file_section *feat_sec; 614 struct perf_file_section *feat_sec;
383 int nr_sections; 615 int nr_sections;
384 int sec_size; 616 int sec_size;
385 int idx = 0; 617 int idx = 0;
386 int err = 0, feat = 1; 618 int err = -1, feat = 1;
387 619
388 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS); 620 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
389 if (!nr_sections) 621 if (!nr_sections)
@@ -397,33 +629,45 @@ int perf_header__process_sections(struct perf_header *self, int fd,
397 629
398 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 630 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
399 631
400 do_read(fd, feat_sec, sec_size); 632 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
633 goto out_free;
401 634
635 err = 0;
402 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { 636 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
403 if (perf_header__has_feat(self, feat)) { 637 if (perf_header__has_feat(self, feat)) {
404 struct perf_file_section *sec = &feat_sec[idx++]; 638 struct perf_file_section *sec = &feat_sec[idx++];
405 639
406 err = process(sec, feat, fd); 640 err = process(sec, self, feat, fd);
407 if (err < 0) 641 if (err < 0)
408 break; 642 break;
409 } 643 }
410 ++feat; 644 ++feat;
411 } 645 }
412 646out_free:
413 free(feat_sec); 647 free(feat_sec);
414 return err; 648 return err;
415}; 649}
416 650
417int perf_file_header__read(struct perf_file_header *self, 651int perf_file_header__read(struct perf_file_header *self,
418 struct perf_header *ph, int fd) 652 struct perf_header *ph, int fd)
419{ 653{
420 lseek(fd, 0, SEEK_SET); 654 lseek(fd, 0, SEEK_SET);
421 do_read(fd, self, sizeof(*self));
422 655
423 if (self->magic != PERF_MAGIC || 656 if (do_read(fd, self, sizeof(*self)) <= 0 ||
424 self->attr_size != sizeof(struct perf_file_attr)) 657 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
425 return -1; 658 return -1;
426 659
660 if (self->attr_size != sizeof(struct perf_file_attr)) {
661 u64 attr_size = bswap_64(self->attr_size);
662
663 if (attr_size != sizeof(struct perf_file_attr))
664 return -1;
665
666 mem_bswap_64(self, offsetof(struct perf_file_header,
667 adds_features));
668 ph->needs_swap = true;
669 }
670
427 if (self->size != sizeof(*self)) { 671 if (self->size != sizeof(*self)) {
428 /* Support the previous format */ 672 /* Support the previous format */
429 if (self->size == offsetof(typeof(*self), adds_features)) 673 if (self->size == offsetof(typeof(*self), adds_features))
@@ -433,19 +677,118 @@ int perf_file_header__read(struct perf_file_header *self,
433 } 677 }
434 678
435 memcpy(&ph->adds_features, &self->adds_features, 679 memcpy(&ph->adds_features, &self->adds_features,
436 sizeof(self->adds_features)); 680 sizeof(ph->adds_features));
681 /*
682 * FIXME: hack that assumes that if we need swap the perf.data file
683 * may be coming from an arch with a different word-size, ergo different
684 * DEFINE_BITMAP format, investigate more later, but for now its mostly
685 * safe to assume that we have a build-id section. Trace files probably
686 * have several other issues in this realm anyway...
687 */
688 if (ph->needs_swap) {
689 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
690 perf_header__set_feat(ph, HEADER_BUILD_ID);
691 }
437 692
438 ph->event_offset = self->event_types.offset; 693 ph->event_offset = self->event_types.offset;
439 ph->event_size = self->event_types.size; 694 ph->event_size = self->event_types.size;
440 ph->data_offset = self->data.offset; 695 ph->data_offset = self->data.offset;
441 ph->data_size = self->data.size; 696 ph->data_size = self->data.size;
442 return 0; 697 return 0;
443} 698}
444 699
700static int __event_process_build_id(struct build_id_event *bev,
701 char *filename,
702 struct perf_session *session)
703{
704 int err = -1;
705 struct list_head *head;
706 struct machine *machine;
707 u16 misc;
708 struct dso *dso;
709 enum dso_kernel_type dso_type;
710
711 machine = perf_session__findnew_machine(session, bev->pid);
712 if (!machine)
713 goto out;
714
715 misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
716
717 switch (misc) {
718 case PERF_RECORD_MISC_KERNEL:
719 dso_type = DSO_TYPE_KERNEL;
720 head = &machine->kernel_dsos;
721 break;
722 case PERF_RECORD_MISC_GUEST_KERNEL:
723 dso_type = DSO_TYPE_GUEST_KERNEL;
724 head = &machine->kernel_dsos;
725 break;
726 case PERF_RECORD_MISC_USER:
727 case PERF_RECORD_MISC_GUEST_USER:
728 dso_type = DSO_TYPE_USER;
729 head = &machine->user_dsos;
730 break;
731 default:
732 goto out;
733 }
734
735 dso = __dsos__findnew(head, filename);
736 if (dso != NULL) {
737 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
738
739 dso__set_build_id(dso, &bev->build_id);
740
741 if (filename[0] == '[')
742 dso->kernel = dso_type;
743
744 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
745 sbuild_id);
746 pr_debug("build id event received for %s: %s\n",
747 dso->long_name, sbuild_id);
748 }
749
750 err = 0;
751out:
752 return err;
753}
754
755static int perf_header__read_build_ids(struct perf_header *self,
756 int input, u64 offset, u64 size)
757{
758 struct perf_session *session = container_of(self,
759 struct perf_session, header);
760 struct build_id_event bev;
761 char filename[PATH_MAX];
762 u64 limit = offset + size;
763 int err = -1;
764
765 while (offset < limit) {
766 ssize_t len;
767
768 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
769 goto out;
770
771 if (self->needs_swap)
772 perf_event_header__bswap(&bev.header);
773
774 len = bev.header.size - sizeof(bev);
775 if (read(input, filename, len) != len)
776 goto out;
777
778 __event_process_build_id(&bev, filename, session);
779
780 offset += bev.header.size;
781 }
782 err = 0;
783out:
784 return err;
785}
786
445static int perf_file_section__process(struct perf_file_section *self, 787static int perf_file_section__process(struct perf_file_section *self,
788 struct perf_header *ph,
446 int feat, int fd) 789 int feat, int fd)
447{ 790{
448 if (lseek(fd, self->offset, SEEK_SET) < 0) { 791 if (lseek(fd, self->offset, SEEK_SET) == (off_t)-1) {
449 pr_debug("Failed to lseek to %Ld offset for feature %d, " 792 pr_debug("Failed to lseek to %Ld offset for feature %d, "
450 "continuing...\n", self->offset, feat); 793 "continuing...\n", self->offset, feat);
451 return 0; 794 return 0;
@@ -453,11 +796,11 @@ static int perf_file_section__process(struct perf_file_section *self,
453 796
454 switch (feat) { 797 switch (feat) {
455 case HEADER_TRACE_INFO: 798 case HEADER_TRACE_INFO:
456 trace_report(fd); 799 trace_report(fd, false);
457 break; 800 break;
458 801
459 case HEADER_BUILD_ID: 802 case HEADER_BUILD_ID:
460 if (perf_header__read_build_ids(fd, self->offset, self->size)) 803 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
461 pr_debug("Failed to read buildids, continuing...\n"); 804 pr_debug("Failed to read buildids, continuing...\n");
462 break; 805 break;
463 default: 806 default:
@@ -467,13 +810,56 @@ static int perf_file_section__process(struct perf_file_section *self,
467 return 0; 810 return 0;
468} 811}
469 812
470int perf_header__read(struct perf_header *self, int fd) 813static int perf_file_header__read_pipe(struct perf_pipe_file_header *self,
814 struct perf_header *ph, int fd,
815 bool repipe)
471{ 816{
472 struct perf_file_header f_header; 817 if (do_read(fd, self, sizeof(*self)) <= 0 ||
818 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
819 return -1;
820
821 if (repipe && do_write(STDOUT_FILENO, self, sizeof(*self)) < 0)
822 return -1;
823
824 if (self->size != sizeof(*self)) {
825 u64 size = bswap_64(self->size);
826
827 if (size != sizeof(*self))
828 return -1;
829
830 ph->needs_swap = true;
831 }
832
833 return 0;
834}
835
836static int perf_header__read_pipe(struct perf_session *session, int fd)
837{
838 struct perf_header *self = &session->header;
839 struct perf_pipe_file_header f_header;
840
841 if (perf_file_header__read_pipe(&f_header, self, fd,
842 session->repipe) < 0) {
843 pr_debug("incompatible file format\n");
844 return -EINVAL;
845 }
846
847 session->fd = fd;
848
849 return 0;
850}
851
852int perf_header__read(struct perf_session *session, int fd)
853{
854 struct perf_header *self = &session->header;
855 struct perf_file_header f_header;
473 struct perf_file_attr f_attr; 856 struct perf_file_attr f_attr;
474 u64 f_id; 857 u64 f_id;
475 int nr_attrs, nr_ids, i, j; 858 int nr_attrs, nr_ids, i, j;
476 859
860 if (session->fd_pipe)
861 return perf_header__read_pipe(session, fd);
862
477 if (perf_file_header__read(&f_header, self, fd) < 0) { 863 if (perf_file_header__read(&f_header, self, fd) < 0) {
478 pr_debug("incompatible file format\n"); 864 pr_debug("incompatible file format\n");
479 return -EINVAL; 865 return -EINVAL;
@@ -486,7 +872,9 @@ int perf_header__read(struct perf_header *self, int fd)
486 struct perf_header_attr *attr; 872 struct perf_header_attr *attr;
487 off_t tmp; 873 off_t tmp;
488 874
489 do_read(fd, &f_attr, sizeof(f_attr)); 875 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
876 goto out_errno;
877
490 tmp = lseek(fd, 0, SEEK_CUR); 878 tmp = lseek(fd, 0, SEEK_CUR);
491 879
492 attr = perf_header_attr__new(&f_attr.attr); 880 attr = perf_header_attr__new(&f_attr.attr);
@@ -497,7 +885,8 @@ int perf_header__read(struct perf_header *self, int fd)
497 lseek(fd, f_attr.ids.offset, SEEK_SET); 885 lseek(fd, f_attr.ids.offset, SEEK_SET);
498 886
499 for (j = 0; j < nr_ids; j++) { 887 for (j = 0; j < nr_ids; j++) {
500 do_read(fd, &f_id, sizeof(f_id)); 888 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
889 goto out_errno;
501 890
502 if (perf_header_attr__add_id(attr, f_id) < 0) { 891 if (perf_header_attr__add_id(attr, f_id) < 0) {
503 perf_header_attr__delete(attr); 892 perf_header_attr__delete(attr);
@@ -517,7 +906,9 @@ int perf_header__read(struct perf_header *self, int fd)
517 events = malloc(f_header.event_types.size); 906 events = malloc(f_header.event_types.size);
518 if (events == NULL) 907 if (events == NULL)
519 return -ENOMEM; 908 return -ENOMEM;
520 do_read(fd, events, f_header.event_types.size); 909 if (perf_header__getbuffer64(self, fd, events,
910 f_header.event_types.size))
911 goto out_errno;
521 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 912 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
522 } 913 }
523 914
@@ -527,6 +918,8 @@ int perf_header__read(struct perf_header *self, int fd)
527 918
528 self->frozen = 1; 919 self->frozen = 1;
529 return 0; 920 return 0;
921out_errno:
922 return -errno;
530} 923}
531 924
532u64 perf_header__sample_type(struct perf_header *header) 925u64 perf_header__sample_type(struct perf_header *header)
@@ -551,6 +944,14 @@ perf_header__find_attr(u64 id, struct perf_header *header)
551{ 944{
552 int i; 945 int i;
553 946
947 /*
948 * We set id to -1 if the data file doesn't contain sample
949 * ids. Check for this and avoid walking through the entire
950 * list of ids which may be large.
951 */
952 if (id == -1ULL)
953 return NULL;
954
554 for (i = 0; i < header->attrs; i++) { 955 for (i = 0; i < header->attrs; i++) {
555 struct perf_header_attr *attr = header->attr[i]; 956 struct perf_header_attr *attr = header->attr[i];
556 int j; 957 int j;
@@ -563,3 +964,236 @@ perf_header__find_attr(u64 id, struct perf_header *header)
563 964
564 return NULL; 965 return NULL;
565} 966}
967
968int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
969 event__handler_t process,
970 struct perf_session *session)
971{
972 event_t *ev;
973 size_t size;
974 int err;
975
976 size = sizeof(struct perf_event_attr);
977 size = ALIGN(size, sizeof(u64));
978 size += sizeof(struct perf_event_header);
979 size += ids * sizeof(u64);
980
981 ev = malloc(size);
982
983 ev->attr.attr = *attr;
984 memcpy(ev->attr.id, id, ids * sizeof(u64));
985
986 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
987 ev->attr.header.size = size;
988
989 err = process(ev, session);
990
991 free(ev);
992
993 return err;
994}
995
996int event__synthesize_attrs(struct perf_header *self,
997 event__handler_t process,
998 struct perf_session *session)
999{
1000 struct perf_header_attr *attr;
1001 int i, err = 0;
1002
1003 for (i = 0; i < self->attrs; i++) {
1004 attr = self->attr[i];
1005
1006 err = event__synthesize_attr(&attr->attr, attr->ids, attr->id,
1007 process, session);
1008 if (err) {
1009 pr_debug("failed to create perf header attribute\n");
1010 return err;
1011 }
1012 }
1013
1014 return err;
1015}
1016
1017int event__process_attr(event_t *self, struct perf_session *session)
1018{
1019 struct perf_header_attr *attr;
1020 unsigned int i, ids, n_ids;
1021
1022 attr = perf_header_attr__new(&self->attr.attr);
1023 if (attr == NULL)
1024 return -ENOMEM;
1025
1026 ids = self->header.size;
1027 ids -= (void *)&self->attr.id - (void *)self;
1028 n_ids = ids / sizeof(u64);
1029
1030 for (i = 0; i < n_ids; i++) {
1031 if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) {
1032 perf_header_attr__delete(attr);
1033 return -ENOMEM;
1034 }
1035 }
1036
1037 if (perf_header__add_attr(&session->header, attr) < 0) {
1038 perf_header_attr__delete(attr);
1039 return -ENOMEM;
1040 }
1041
1042 perf_session__update_sample_type(session);
1043
1044 return 0;
1045}
1046
1047int event__synthesize_event_type(u64 event_id, char *name,
1048 event__handler_t process,
1049 struct perf_session *session)
1050{
1051 event_t ev;
1052 size_t size = 0;
1053 int err = 0;
1054
1055 memset(&ev, 0, sizeof(ev));
1056
1057 ev.event_type.event_type.event_id = event_id;
1058 memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
1059 strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
1060
1061 ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
1062 size = strlen(name);
1063 size = ALIGN(size, sizeof(u64));
1064 ev.event_type.header.size = sizeof(ev.event_type) -
1065 (sizeof(ev.event_type.event_type.name) - size);
1066
1067 err = process(&ev, session);
1068
1069 return err;
1070}
1071
1072int event__synthesize_event_types(event__handler_t process,
1073 struct perf_session *session)
1074{
1075 struct perf_trace_event_type *type;
1076 int i, err = 0;
1077
1078 for (i = 0; i < event_count; i++) {
1079 type = &events[i];
1080
1081 err = event__synthesize_event_type(type->event_id, type->name,
1082 process, session);
1083 if (err) {
1084 pr_debug("failed to create perf header event type\n");
1085 return err;
1086 }
1087 }
1088
1089 return err;
1090}
1091
1092int event__process_event_type(event_t *self,
1093 struct perf_session *session __unused)
1094{
1095 if (perf_header__push_event(self->event_type.event_type.event_id,
1096 self->event_type.event_type.name) < 0)
1097 return -ENOMEM;
1098
1099 return 0;
1100}
1101
1102int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
1103 int nb_events,
1104 event__handler_t process,
1105 struct perf_session *session __unused)
1106{
1107 event_t ev;
1108 ssize_t size = 0, aligned_size = 0, padding;
1109 int err = 0;
1110
1111 memset(&ev, 0, sizeof(ev));
1112
1113 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
1114 size = read_tracing_data_size(fd, pattrs, nb_events);
1115 if (size <= 0)
1116 return size;
1117 aligned_size = ALIGN(size, sizeof(u64));
1118 padding = aligned_size - size;
1119 ev.tracing_data.header.size = sizeof(ev.tracing_data);
1120 ev.tracing_data.size = aligned_size;
1121
1122 process(&ev, session);
1123
1124 err = read_tracing_data(fd, pattrs, nb_events);
1125 write_padded(fd, NULL, 0, padding);
1126
1127 return aligned_size;
1128}
1129
1130int event__process_tracing_data(event_t *self,
1131 struct perf_session *session)
1132{
1133 ssize_t size_read, padding, size = self->tracing_data.size;
1134 off_t offset = lseek(session->fd, 0, SEEK_CUR);
1135 char buf[BUFSIZ];
1136
1137 /* setup for reading amidst mmap */
1138 lseek(session->fd, offset + sizeof(struct tracing_data_event),
1139 SEEK_SET);
1140
1141 size_read = trace_report(session->fd, session->repipe);
1142
1143 padding = ALIGN(size_read, sizeof(u64)) - size_read;
1144
1145 if (read(session->fd, buf, padding) < 0)
1146 die("reading input file");
1147 if (session->repipe) {
1148 int retw = write(STDOUT_FILENO, buf, padding);
1149 if (retw <= 0 || retw != padding)
1150 die("repiping tracing data padding");
1151 }
1152
1153 if (size_read + padding != size)
1154 die("tracing data size mismatch");
1155
1156 return size_read + padding;
1157}
1158
1159int event__synthesize_build_id(struct dso *pos, u16 misc,
1160 event__handler_t process,
1161 struct machine *machine,
1162 struct perf_session *session)
1163{
1164 event_t ev;
1165 size_t len;
1166 int err = 0;
1167
1168 if (!pos->hit)
1169 return err;
1170
1171 memset(&ev, 0, sizeof(ev));
1172
1173 len = pos->long_name_len + 1;
1174 len = ALIGN(len, NAME_ALIGN);
1175 memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
1176 ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
1177 ev.build_id.header.misc = misc;
1178 ev.build_id.pid = machine->pid;
1179 ev.build_id.header.size = sizeof(ev.build_id) + len;
1180 memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
1181
1182 err = process(&ev, session);
1183
1184 return err;
1185}
1186
1187int event__process_build_id(event_t *self,
1188 struct perf_session *session)
1189{
1190 __event_process_build_id(&self->build_id,
1191 self->build_id.filename,
1192 session);
1193 return 0;
1194}
1195
1196void disable_buildid_cache(void)
1197{
1198 no_buildid_cache = true;
1199}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d118d05d3abe..402ac2454cf8 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);
@@ -80,6 +88,40 @@ bool perf_header__has_feat(const struct perf_header *self, int feat);
80 88
81int perf_header__process_sections(struct perf_header *self, int fd, 89int perf_header__process_sections(struct perf_header *self, int fd,
82 int (*process)(struct perf_file_section *self, 90 int (*process)(struct perf_file_section *self,
91 struct perf_header *ph,
83 int feat, int fd)); 92 int feat, int fd));
84 93
94int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
95 const char *name, bool is_kallsyms);
96int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
97
98int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,
99 event__handler_t process,
100 struct perf_session *session);
101int event__synthesize_attrs(struct perf_header *self,
102 event__handler_t process,
103 struct perf_session *session);
104int event__process_attr(event_t *self, struct perf_session *session);
105
106int event__synthesize_event_type(u64 event_id, char *name,
107 event__handler_t process,
108 struct perf_session *session);
109int event__synthesize_event_types(event__handler_t process,
110 struct perf_session *session);
111int event__process_event_type(event_t *self,
112 struct perf_session *session);
113
114int event__synthesize_tracing_data(int fd, struct perf_event_attr *pattrs,
115 int nb_events,
116 event__handler_t process,
117 struct perf_session *session);
118int event__process_tracing_data(event_t *self,
119 struct perf_session *session);
120
121int event__synthesize_build_id(struct dso *pos, u16 misc,
122 event__handler_t process,
123 struct machine *machine,
124 struct perf_session *session);
125int event__process_build_id(event_t *self, struct perf_session *session);
126
85#endif /* __PERF_HEADER_H */ 127#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..be22ae6ef055 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_node) : 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)
19{ 106{
20 struct rb_node **p = &self->hists.rb_node; 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)
123{
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,9 @@ 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;
119 hist_entry__free(he); 229 hist_entry__free(he);
120 return; 230 return false;
121 } 231 }
122 232
123 if (cmp < 0) 233 if (cmp < 0)
@@ -128,9 +238,10 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
128 238
129 rb_link_node(&he->rb_node, parent, p); 239 rb_link_node(&he->rb_node, parent, p);
130 rb_insert_color(&he->rb_node, root); 240 rb_insert_color(&he->rb_node, root);
241 return true;
131} 242}
132 243
133void perf_session__collapse_resort(struct perf_session *self) 244void hists__collapse_resort(struct hists *self)
134{ 245{
135 struct rb_root tmp; 246 struct rb_root tmp;
136 struct rb_node *next; 247 struct rb_node *next;
@@ -140,72 +251,77 @@ void perf_session__collapse_resort(struct perf_session *self)
140 return; 251 return;
141 252
142 tmp = RB_ROOT; 253 tmp = RB_ROOT;
143 next = rb_first(&self->hists); 254 next = rb_first(&self->entries);
255 self->nr_entries = 0;
256 hists__reset_col_len(self);
144 257
145 while (next) { 258 while (next) {
146 n = rb_entry(next, struct hist_entry, rb_node); 259 n = rb_entry(next, struct hist_entry, rb_node);
147 next = rb_next(&n->rb_node); 260 next = rb_next(&n->rb_node);
148 261
149 rb_erase(&n->rb_node, &self->hists); 262 rb_erase(&n->rb_node, &self->entries);
150 collapse__insert_entry(&tmp, n); 263 if (collapse__insert_entry(&tmp, n))
264 hists__inc_nr_entries(self, n);
151 } 265 }
152 266
153 self->hists = tmp; 267 self->entries = tmp;
154} 268}
155 269
156/* 270/*
157 * reverse the map, sort on count. 271 * reverse the map, sort on period.
158 */ 272 */
159 273
160static void perf_session__insert_output_hist_entry(struct rb_root *root, 274static void __hists__insert_output_entry(struct rb_root *entries,
161 struct hist_entry *he, 275 struct hist_entry *he,
162 u64 min_callchain_hits) 276 u64 min_callchain_hits)
163{ 277{
164 struct rb_node **p = &root->rb_node; 278 struct rb_node **p = &entries->rb_node;
165 struct rb_node *parent = NULL; 279 struct rb_node *parent = NULL;
166 struct hist_entry *iter; 280 struct hist_entry *iter;
167 281
168 if (symbol_conf.use_callchain) 282 if (symbol_conf.use_callchain)
169 callchain_param.sort(&he->sorted_chain, &he->callchain, 283 callchain_param.sort(&he->sorted_chain, he->callchain,
170 min_callchain_hits, &callchain_param); 284 min_callchain_hits, &callchain_param);
171 285
172 while (*p != NULL) { 286 while (*p != NULL) {
173 parent = *p; 287 parent = *p;
174 iter = rb_entry(parent, struct hist_entry, rb_node); 288 iter = rb_entry(parent, struct hist_entry, rb_node);
175 289
176 if (he->count > iter->count) 290 if (he->period > iter->period)
177 p = &(*p)->rb_left; 291 p = &(*p)->rb_left;
178 else 292 else
179 p = &(*p)->rb_right; 293 p = &(*p)->rb_right;
180 } 294 }
181 295
182 rb_link_node(&he->rb_node, parent, p); 296 rb_link_node(&he->rb_node, parent, p);
183 rb_insert_color(&he->rb_node, root); 297 rb_insert_color(&he->rb_node, entries);
184} 298}
185 299
186void perf_session__output_resort(struct perf_session *self, u64 total_samples) 300void hists__output_resort(struct hists *self)
187{ 301{
188 struct rb_root tmp; 302 struct rb_root tmp;
189 struct rb_node *next; 303 struct rb_node *next;
190 struct hist_entry *n; 304 struct hist_entry *n;
191 u64 min_callchain_hits; 305 u64 min_callchain_hits;
192 306
193 min_callchain_hits = 307 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100);
194 total_samples * (callchain_param.min_percent / 100);
195 308
196 tmp = RB_ROOT; 309 tmp = RB_ROOT;
197 next = rb_first(&self->hists); 310 next = rb_first(&self->entries);
311
312 self->nr_entries = 0;
313 hists__reset_col_len(self);
198 314
199 while (next) { 315 while (next) {
200 n = rb_entry(next, struct hist_entry, rb_node); 316 n = rb_entry(next, struct hist_entry, rb_node);
201 next = rb_next(&n->rb_node); 317 next = rb_next(&n->rb_node);
202 318
203 rb_erase(&n->rb_node, &self->hists); 319 rb_erase(&n->rb_node, &self->entries);
204 perf_session__insert_output_hist_entry(&tmp, n, 320 __hists__insert_output_entry(&tmp, n, min_callchain_hits);
205 min_callchain_hits); 321 hists__inc_nr_entries(self, n);
206 } 322 }
207 323
208 self->hists = tmp; 324 self->entries = tmp;
209} 325}
210 326
211static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 327static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
@@ -237,7 +353,7 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
237} 353}
238 354
239static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 355static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
240 int depth, int depth_mask, int count, 356 int depth, int depth_mask, int period,
241 u64 total_samples, int hits, 357 u64 total_samples, int hits,
242 int left_margin) 358 int left_margin)
243{ 359{
@@ -250,7 +366,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
250 ret += fprintf(fp, "|"); 366 ret += fprintf(fp, "|");
251 else 367 else
252 ret += fprintf(fp, " "); 368 ret += fprintf(fp, " ");
253 if (!count && i == depth - 1) { 369 if (!period && i == depth - 1) {
254 double percent; 370 double percent;
255 371
256 percent = hits * 100.0 / total_samples; 372 percent = hits * 100.0 / total_samples;
@@ -258,8 +374,8 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
258 } else 374 } else
259 ret += fprintf(fp, "%s", " "); 375 ret += fprintf(fp, "%s", " ");
260 } 376 }
261 if (chain->sym) 377 if (chain->ms.sym)
262 ret += fprintf(fp, "%s\n", chain->sym->name); 378 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
263 else 379 else
264 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); 380 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
265 381
@@ -278,7 +394,7 @@ static void init_rem_hits(void)
278 } 394 }
279 395
280 strcpy(rem_sq_bracket->name, "[...]"); 396 strcpy(rem_sq_bracket->name, "[...]");
281 rem_hits.sym = rem_sq_bracket; 397 rem_hits.ms.sym = rem_sq_bracket;
282} 398}
283 399
284static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, 400static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
@@ -293,6 +409,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
293 u64 remaining; 409 u64 remaining;
294 size_t ret = 0; 410 size_t ret = 0;
295 int i; 411 int i;
412 uint entries_printed = 0;
296 413
297 if (callchain_param.mode == CHAIN_GRAPH_REL) 414 if (callchain_param.mode == CHAIN_GRAPH_REL)
298 new_total = self->children_hit; 415 new_total = self->children_hit;
@@ -321,15 +438,13 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
321 new_depth_mask &= ~(1 << (depth - 1)); 438 new_depth_mask &= ~(1 << (depth - 1));
322 439
323 /* 440 /*
324 * But we keep the older depth mask for the line seperator 441 * But we keep the older depth mask for the line separator
325 * to keep the level link until we reach the last child 442 * to keep the level link until we reach the last child
326 */ 443 */
327 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 444 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
328 left_margin); 445 left_margin);
329 i = 0; 446 i = 0;
330 list_for_each_entry(chain, &child->val, list) { 447 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, 448 ret += ipchain__fprintf_graph(fp, chain, depth,
334 new_depth_mask, i++, 449 new_depth_mask, i++,
335 new_total, 450 new_total,
@@ -341,6 +456,8 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
341 new_depth_mask | (1 << depth), 456 new_depth_mask | (1 << depth),
342 left_margin); 457 left_margin);
343 node = next; 458 node = next;
459 if (++entries_printed == callchain_param.print_limit)
460 break;
344 } 461 }
345 462
346 if (callchain_param.mode == CHAIN_GRAPH_REL && 463 if (callchain_param.mode == CHAIN_GRAPH_REL &&
@@ -366,11 +483,9 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
366 bool printed = false; 483 bool printed = false;
367 int i = 0; 484 int i = 0;
368 int ret = 0; 485 int ret = 0;
486 u32 entries_printed = 0;
369 487
370 list_for_each_entry(chain, &self->val, list) { 488 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) 489 if (!i++ && sort__first_dimension == SORT_SYM)
375 continue; 490 continue;
376 491
@@ -385,10 +500,13 @@ static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
385 } else 500 } else
386 ret += callchain__fprintf_left_margin(fp, left_margin); 501 ret += callchain__fprintf_left_margin(fp, left_margin);
387 502
388 if (chain->sym) 503 if (chain->ms.sym)
389 ret += fprintf(fp, " %s\n", chain->sym->name); 504 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
390 else 505 else
391 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 506 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
507
508 if (++entries_printed == callchain_param.print_limit)
509 break;
392 } 510 }
393 511
394 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin); 512 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
@@ -411,8 +529,8 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
411 list_for_each_entry(chain, &self->val, list) { 529 list_for_each_entry(chain, &self->val, list) {
412 if (chain->ip >= PERF_CONTEXT_MAX) 530 if (chain->ip >= PERF_CONTEXT_MAX)
413 continue; 531 continue;
414 if (chain->sym) 532 if (chain->ms.sym)
415 ret += fprintf(fp, " %s\n", chain->sym->name); 533 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
416 else 534 else
417 ret += fprintf(fp, " %p\n", 535 ret += fprintf(fp, " %p\n",
418 (void *)(long)chain->ip); 536 (void *)(long)chain->ip);
@@ -427,6 +545,7 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
427 struct rb_node *rb_node; 545 struct rb_node *rb_node;
428 struct callchain_node *chain; 546 struct callchain_node *chain;
429 size_t ret = 0; 547 size_t ret = 0;
548 u32 entries_printed = 0;
430 549
431 rb_node = rb_first(&self->sorted_chain); 550 rb_node = rb_first(&self->sorted_chain);
432 while (rb_node) { 551 while (rb_node) {
@@ -449,55 +568,89 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
449 break; 568 break;
450 } 569 }
451 ret += fprintf(fp, "\n"); 570 ret += fprintf(fp, "\n");
571 if (++entries_printed == callchain_param.print_limit)
572 break;
452 rb_node = rb_next(rb_node); 573 rb_node = rb_next(rb_node);
453 } 574 }
454 575
455 return ret; 576 return ret;
456} 577}
457 578
458static size_t hist_entry__fprintf(struct hist_entry *self, 579int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
459 struct perf_session *session, 580 struct hists *hists, struct hists *pair_hists,
460 struct perf_session *pair_session, 581 bool show_displacement, long displacement,
461 bool show_displacement, 582 bool color, u64 session_total)
462 long displacement, FILE *fp)
463{ 583{
464 struct sort_entry *se; 584 struct sort_entry *se;
465 u64 count, total; 585 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
466 const char *sep = symbol_conf.field_sep; 586 const char *sep = symbol_conf.field_sep;
467 size_t ret; 587 int ret;
468 588
469 if (symbol_conf.exclude_other && !self->parent) 589 if (symbol_conf.exclude_other && !self->parent)
470 return 0; 590 return 0;
471 591
472 if (pair_session) { 592 if (pair_hists) {
473 count = self->pair ? self->pair->count : 0; 593 period = self->pair ? self->pair->period : 0;
474 total = pair_session->events_stats.total; 594 total = pair_hists->stats.total_period;
595 period_sys = self->pair ? self->pair->period_sys : 0;
596 period_us = self->pair ? self->pair->period_us : 0;
597 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
598 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
475 } else { 599 } else {
476 count = self->count; 600 period = self->period;
477 total = session->events_stats.total; 601 total = session_total;
602 period_sys = self->period_sys;
603 period_us = self->period_us;
604 period_guest_sys = self->period_guest_sys;
605 period_guest_us = self->period_guest_us;
478 } 606 }
479 607
480 if (total) 608 if (total) {
481 ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%", 609 if (color)
482 (count * 100.0) / total); 610 ret = percent_color_snprintf(s, size,
483 else 611 sep ? "%.2f" : " %6.2f%%",
484 ret = fprintf(fp, sep ? "%lld" : "%12lld ", count); 612 (period * 100.0) / total);
613 else
614 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
615 (period * 100.0) / total);
616 if (symbol_conf.show_cpu_utilization) {
617 ret += percent_color_snprintf(s + ret, size - ret,
618 sep ? "%.2f" : " %6.2f%%",
619 (period_sys * 100.0) / total);
620 ret += percent_color_snprintf(s + ret, size - ret,
621 sep ? "%.2f" : " %6.2f%%",
622 (period_us * 100.0) / total);
623 if (perf_guest) {
624 ret += percent_color_snprintf(s + ret,
625 size - ret,
626 sep ? "%.2f" : " %6.2f%%",
627 (period_guest_sys * 100.0) /
628 total);
629 ret += percent_color_snprintf(s + ret,
630 size - ret,
631 sep ? "%.2f" : " %6.2f%%",
632 (period_guest_us * 100.0) /
633 total);
634 }
635 }
636 } else
637 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period);
485 638
486 if (symbol_conf.show_nr_samples) { 639 if (symbol_conf.show_nr_samples) {
487 if (sep) 640 if (sep)
488 fprintf(fp, "%c%lld", *sep, count); 641 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period);
489 else 642 else
490 fprintf(fp, "%11lld", count); 643 ret += snprintf(s + ret, size - ret, "%11lld", period);
491 } 644 }
492 645
493 if (pair_session) { 646 if (pair_hists) {
494 char bf[32]; 647 char bf[32];
495 double old_percent = 0, new_percent = 0, diff; 648 double old_percent = 0, new_percent = 0, diff;
496 649
497 if (total > 0) 650 if (total > 0)
498 old_percent = (count * 100.0) / total; 651 old_percent = (period * 100.0) / total;
499 if (session->events_stats.total > 0) 652 if (session_total > 0)
500 new_percent = (self->count * 100.0) / session->events_stats.total; 653 new_percent = (self->period * 100.0) / session_total;
501 654
502 diff = new_percent - old_percent; 655 diff = new_percent - old_percent;
503 656
@@ -507,9 +660,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
507 snprintf(bf, sizeof(bf), " "); 660 snprintf(bf, sizeof(bf), " ");
508 661
509 if (sep) 662 if (sep)
510 ret += fprintf(fp, "%c%s", *sep, bf); 663 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
511 else 664 else
512 ret += fprintf(fp, "%11.11s", bf); 665 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
513 666
514 if (show_displacement) { 667 if (show_displacement) {
515 if (displacement) 668 if (displacement)
@@ -518,9 +671,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
518 snprintf(bf, sizeof(bf), " "); 671 snprintf(bf, sizeof(bf), " ");
519 672
520 if (sep) 673 if (sep)
521 fprintf(fp, "%c%s", *sep, bf); 674 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
522 else 675 else
523 fprintf(fp, "%6.6s", bf); 676 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
524 } 677 }
525 } 678 }
526 679
@@ -528,32 +681,44 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
528 if (se->elide) 681 if (se->elide)
529 continue; 682 continue;
530 683
531 fprintf(fp, "%s", sep ?: " "); 684 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0); 685 ret += se->se_snprintf(self, s + ret, size - ret,
686 hists__col_len(hists, se->se_width_idx));
533 } 687 }
534 688
535 ret += fprintf(fp, "\n"); 689 return ret;
690}
536 691
537 if (symbol_conf.use_callchain) { 692int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
538 int left_margin = 0; 693 struct hists *pair_hists, bool show_displacement,
694 long displacement, FILE *fp, u64 session_total)
695{
696 char bf[512];
697 hist_entry__snprintf(self, bf, sizeof(bf), hists, pair_hists,
698 show_displacement, displacement,
699 true, session_total);
700 return fprintf(fp, "%s\n", bf);
701}
539 702
540 if (sort__first_dimension == SORT_COMM) { 703static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se), 704 struct hists *hists, FILE *fp,
542 list); 705 u64 session_total)
543 left_margin = se->width ? *se->width : 0; 706{
544 left_margin -= thread__comm_len(self->thread); 707 int left_margin = 0;
545 }
546 708
547 hist_entry_callchain__fprintf(fp, self, session->events_stats.total, 709 if (sort__first_dimension == SORT_COMM) {
548 left_margin); 710 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
711 typeof(*se), list);
712 left_margin = hists__col_len(hists, se->se_width_idx);
713 left_margin -= thread__comm_len(self->thread);
549 } 714 }
550 715
551 return ret; 716 return hist_entry_callchain__fprintf(fp, self, session_total,
717 left_margin);
552} 718}
553 719
554size_t perf_session__fprintf_hists(struct perf_session *self, 720size_t hists__fprintf(struct hists *self, struct hists *pair,
555 struct perf_session *pair, 721 bool show_displacement, FILE *fp)
556 bool show_displacement, FILE *fp)
557{ 722{
558 struct sort_entry *se; 723 struct sort_entry *se;
559 struct rb_node *nd; 724 struct rb_node *nd;
@@ -562,7 +727,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
562 long displacement = 0; 727 long displacement = 0;
563 unsigned int width; 728 unsigned int width;
564 const char *sep = symbol_conf.field_sep; 729 const char *sep = symbol_conf.field_sep;
565 char *col_width = symbol_conf.col_width_list_str; 730 const char *col_width = symbol_conf.col_width_list_str;
566 731
567 init_rem_hits(); 732 init_rem_hits();
568 733
@@ -575,6 +740,24 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
575 fputs(" Samples ", fp); 740 fputs(" Samples ", fp);
576 } 741 }
577 742
743 if (symbol_conf.show_cpu_utilization) {
744 if (sep) {
745 ret += fprintf(fp, "%csys", *sep);
746 ret += fprintf(fp, "%cus", *sep);
747 if (perf_guest) {
748 ret += fprintf(fp, "%cguest sys", *sep);
749 ret += fprintf(fp, "%cguest us", *sep);
750 }
751 } else {
752 ret += fprintf(fp, " sys ");
753 ret += fprintf(fp, " us ");
754 if (perf_guest) {
755 ret += fprintf(fp, " guest sys ");
756 ret += fprintf(fp, " guest us ");
757 }
758 }
759 }
760
578 if (pair) { 761 if (pair) {
579 if (sep) 762 if (sep)
580 ret += fprintf(fp, "%cDelta", *sep); 763 ret += fprintf(fp, "%cDelta", *sep);
@@ -593,22 +776,22 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
593 if (se->elide) 776 if (se->elide)
594 continue; 777 continue;
595 if (sep) { 778 if (sep) {
596 fprintf(fp, "%c%s", *sep, se->header); 779 fprintf(fp, "%c%s", *sep, se->se_header);
597 continue; 780 continue;
598 } 781 }
599 width = strlen(se->header); 782 width = strlen(se->se_header);
600 if (se->width) { 783 if (symbol_conf.col_width_list_str) {
601 if (symbol_conf.col_width_list_str) { 784 if (col_width) {
602 if (col_width) { 785 hists__set_col_len(self, se->se_width_idx,
603 *se->width = atoi(col_width); 786 atoi(col_width));
604 col_width = strchr(col_width, ','); 787 col_width = strchr(col_width, ',');
605 if (col_width) 788 if (col_width)
606 ++col_width; 789 ++col_width;
607 }
608 } 790 }
609 width = *se->width = max(*se->width, width);
610 } 791 }
611 fprintf(fp, " %*s", width, se->header); 792 if (!hists__new_col_len(self, se->se_width_idx, width))
793 width = hists__col_len(self, se->se_width_idx);
794 fprintf(fp, " %*s", width, se->se_header);
612 } 795 }
613 fprintf(fp, "\n"); 796 fprintf(fp, "\n");
614 797
@@ -630,10 +813,9 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
630 continue; 813 continue;
631 814
632 fprintf(fp, " "); 815 fprintf(fp, " ");
633 if (se->width) 816 width = hists__col_len(self, se->se_width_idx);
634 width = *se->width; 817 if (width == 0)
635 else 818 width = strlen(se->se_header);
636 width = strlen(se->header);
637 for (i = 0; i < width; i++) 819 for (i = 0; i < width; i++)
638 fprintf(fp, "."); 820 fprintf(fp, ".");
639 } 821 }
@@ -641,7 +823,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self,
641 fprintf(fp, "\n#\n"); 823 fprintf(fp, "\n#\n");
642 824
643print_entries: 825print_entries:
644 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { 826 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
645 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 827 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
646 828
647 if (show_displacement) { 829 if (show_displacement) {
@@ -653,10 +835,342 @@ print_entries:
653 ++position; 835 ++position;
654 } 836 }
655 ret += hist_entry__fprintf(h, self, pair, show_displacement, 837 ret += hist_entry__fprintf(h, self, pair, show_displacement,
656 displacement, fp); 838 displacement, fp, self->stats.total_period);
839
840 if (symbol_conf.use_callchain)
841 ret += hist_entry__fprintf_callchain(h, self, fp,
842 self->stats.total_period);
843 if (h->ms.map == NULL && verbose > 1) {
844 __map_groups__fprintf_maps(&h->thread->mg,
845 MAP__FUNCTION, verbose, fp);
846 fprintf(fp, "%.10s end\n", graph_dotted_line);
847 }
657 } 848 }
658 849
659 free(rem_sq_bracket); 850 free(rem_sq_bracket);
660 851
661 return ret; 852 return ret;
662} 853}
854
855/*
856 * See hists__fprintf to match the column widths
857 */
858unsigned int hists__sort_list_width(struct hists *self)
859{
860 struct sort_entry *se;
861 int ret = 9; /* total % */
862
863 if (symbol_conf.show_cpu_utilization) {
864 ret += 7; /* count_sys % */
865 ret += 6; /* count_us % */
866 if (perf_guest) {
867 ret += 13; /* count_guest_sys % */
868 ret += 12; /* count_guest_us % */
869 }
870 }
871
872 if (symbol_conf.show_nr_samples)
873 ret += 11;
874
875 list_for_each_entry(se, &hist_entry__sort_list, list)
876 if (!se->elide)
877 ret += 2 + hists__col_len(self, se->se_width_idx);
878
879 if (verbose) /* Addr + origin */
880 ret += 3 + BITS_PER_LONG / 4;
881
882 return ret;
883}
884
885static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
886 enum hist_filter filter)
887{
888 h->filtered &= ~(1 << filter);
889 if (h->filtered)
890 return;
891
892 ++self->nr_entries;
893 if (h->ms.unfolded)
894 self->nr_entries += h->nr_rows;
895 h->row_offset = 0;
896 self->stats.total_period += h->period;
897 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
898
899 hists__calc_col_len(self, h);
900}
901
902void hists__filter_by_dso(struct hists *self, const struct dso *dso)
903{
904 struct rb_node *nd;
905
906 self->nr_entries = self->stats.total_period = 0;
907 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
908 hists__reset_col_len(self);
909
910 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
911 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
912
913 if (symbol_conf.exclude_other && !h->parent)
914 continue;
915
916 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
917 h->filtered |= (1 << HIST_FILTER__DSO);
918 continue;
919 }
920
921 hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
922 }
923}
924
925void hists__filter_by_thread(struct hists *self, const struct thread *thread)
926{
927 struct rb_node *nd;
928
929 self->nr_entries = self->stats.total_period = 0;
930 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
931 hists__reset_col_len(self);
932
933 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
934 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
935
936 if (thread != NULL && h->thread != thread) {
937 h->filtered |= (1 << HIST_FILTER__THREAD);
938 continue;
939 }
940
941 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
942 }
943}
944
945static int symbol__alloc_hist(struct symbol *self)
946{
947 struct sym_priv *priv = symbol__priv(self);
948 const int size = (sizeof(*priv->hist) +
949 (self->end - self->start) * sizeof(u64));
950
951 priv->hist = zalloc(size);
952 return priv->hist == NULL ? -1 : 0;
953}
954
955int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
956{
957 unsigned int sym_size, offset;
958 struct symbol *sym = self->ms.sym;
959 struct sym_priv *priv;
960 struct sym_hist *h;
961
962 if (!sym || !self->ms.map)
963 return 0;
964
965 priv = symbol__priv(sym);
966 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
967 return -ENOMEM;
968
969 sym_size = sym->end - sym->start;
970 offset = ip - sym->start;
971
972 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
973
974 if (offset >= sym_size)
975 return 0;
976
977 h = priv->hist;
978 h->sum++;
979 h->ip[offset]++;
980
981 pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
982 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
983 return 0;
984}
985
986static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
987{
988 struct objdump_line *self = malloc(sizeof(*self) + privsize);
989
990 if (self != NULL) {
991 self->offset = offset;
992 self->line = line;
993 }
994
995 return self;
996}
997
998void objdump_line__free(struct objdump_line *self)
999{
1000 free(self->line);
1001 free(self);
1002}
1003
1004static void objdump__add_line(struct list_head *head, struct objdump_line *line)
1005{
1006 list_add_tail(&line->node, head);
1007}
1008
1009struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
1010 struct objdump_line *pos)
1011{
1012 list_for_each_entry_continue(pos, head, node)
1013 if (pos->offset >= 0)
1014 return pos;
1015
1016 return NULL;
1017}
1018
1019static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
1020 struct list_head *head, size_t privsize)
1021{
1022 struct symbol *sym = self->ms.sym;
1023 struct objdump_line *objdump_line;
1024 char *line = NULL, *tmp, *tmp2, *c;
1025 size_t line_len;
1026 s64 line_ip, offset = -1;
1027
1028 if (getline(&line, &line_len, file) < 0)
1029 return -1;
1030
1031 if (!line)
1032 return -1;
1033
1034 while (line_len != 0 && isspace(line[line_len - 1]))
1035 line[--line_len] = '\0';
1036
1037 c = strchr(line, '\n');
1038 if (c)
1039 *c = 0;
1040
1041 line_ip = -1;
1042
1043 /*
1044 * Strip leading spaces:
1045 */
1046 tmp = line;
1047 while (*tmp) {
1048 if (*tmp != ' ')
1049 break;
1050 tmp++;
1051 }
1052
1053 if (*tmp) {
1054 /*
1055 * Parse hexa addresses followed by ':'
1056 */
1057 line_ip = strtoull(tmp, &tmp2, 16);
1058 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1059 line_ip = -1;
1060 }
1061
1062 if (line_ip != -1) {
1063 u64 start = map__rip_2objdump(self->ms.map, sym->start),
1064 end = map__rip_2objdump(self->ms.map, sym->end);
1065
1066 offset = line_ip - start;
1067 if (offset < 0 || (u64)line_ip > end)
1068 offset = -1;
1069 }
1070
1071 objdump_line = objdump_line__new(offset, line, privsize);
1072 if (objdump_line == NULL) {
1073 free(line);
1074 return -1;
1075 }
1076 objdump__add_line(head, objdump_line);
1077
1078 return 0;
1079}
1080
1081int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
1082 size_t privsize)
1083{
1084 struct symbol *sym = self->ms.sym;
1085 struct map *map = self->ms.map;
1086 struct dso *dso = map->dso;
1087 char *filename = dso__build_id_filename(dso, NULL, 0);
1088 bool free_filename = true;
1089 char command[PATH_MAX * 2];
1090 FILE *file;
1091 int err = 0;
1092 u64 len;
1093
1094 if (filename == NULL) {
1095 if (dso->has_build_id) {
1096 pr_err("Can't annotate %s: not enough memory\n",
1097 sym->name);
1098 return -ENOMEM;
1099 }
1100 goto fallback;
1101 } else if (readlink(filename, command, sizeof(command)) < 0 ||
1102 strstr(command, "[kernel.kallsyms]") ||
1103 access(filename, R_OK)) {
1104 free(filename);
1105fallback:
1106 /*
1107 * If we don't have build-ids or the build-id file isn't in the
1108 * cache, or is just a kallsyms file, well, lets hope that this
1109 * DSO is the same as when 'perf record' ran.
1110 */
1111 filename = dso->long_name;
1112 free_filename = false;
1113 }
1114
1115 if (dso->origin == DSO__ORIG_KERNEL) {
1116 if (dso->annotate_warned)
1117 goto out_free_filename;
1118 err = -ENOENT;
1119 dso->annotate_warned = 1;
1120 pr_err("Can't annotate %s: No vmlinux file was found in the "
1121 "path\n", sym->name);
1122 goto out_free_filename;
1123 }
1124
1125 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1126 filename, sym->name, map->unmap_ip(map, sym->start),
1127 map->unmap_ip(map, sym->end));
1128
1129 len = sym->end - sym->start;
1130
1131 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1132 dso, dso->long_name, sym, sym->name);
1133
1134 snprintf(command, sizeof(command),
1135 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1136 map__rip_2objdump(map, sym->start),
1137 map__rip_2objdump(map, sym->end),
1138 filename, filename);
1139
1140 pr_debug("Executing: %s\n", command);
1141
1142 file = popen(command, "r");
1143 if (!file)
1144 goto out_free_filename;
1145
1146 while (!feof(file))
1147 if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0)
1148 break;
1149
1150 pclose(file);
1151out_free_filename:
1152 if (free_filename)
1153 free(filename);
1154 return err;
1155}
1156
1157void hists__inc_nr_events(struct hists *self, u32 type)
1158{
1159 ++self->stats.nr_events[0];
1160 ++self->stats.nr_events[type];
1161}
1162
1163size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1164{
1165 int i;
1166 size_t ret = 0;
1167
1168 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1169 if (!event__name[i])
1170 continue;
1171 ret += fprintf(fp, "%10s events: %10d\n",
1172 event__name[i], self->stats.nr_events[i]);
1173 }
1174
1175 return ret;
1176}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index e5f99b24048b..587d375d3430 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -6,22 +6,143 @@
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 u32 nr_events[PERF_RECORD_HEADER_MAX];
56 u32 nr_unknown_events;
57};
58
59enum hist_column {
60 HISTC_SYMBOL,
61 HISTC_DSO,
62 HISTC_THREAD,
63 HISTC_COMM,
64 HISTC_PARENT,
65 HISTC_CPU,
66 HISTC_NR_COLS, /* Last entry */
67};
68
69struct hists {
70 struct rb_node rb_node;
71 struct rb_root entries;
72 u64 nr_entries;
73 struct events_stats stats;
74 u64 config;
75 u64 event_stream;
76 u32 type;
77 u16 col_len[HISTC_NR_COLS];
78};
79
80struct hist_entry *__hists__add_entry(struct hists *self,
81 struct addr_location *al,
82 struct symbol *parent, u64 period);
18extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 83extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
19extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 84extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
85int hist_entry__fprintf(struct hist_entry *self, struct hists *hists,
86 struct hists *pair_hists, bool show_displacement,
87 long displacement, FILE *fp, u64 total);
88int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
89 struct hists *hists, struct hists *pair_hists,
90 bool show_displacement, long displacement,
91 bool color, u64 total);
20void hist_entry__free(struct hist_entry *); 92void hist_entry__free(struct hist_entry *);
21 93
22void perf_session__output_resort(struct perf_session *self, u64 total_samples); 94void hists__output_resort(struct hists *self);
23void perf_session__collapse_resort(struct perf_session *self); 95void hists__collapse_resort(struct hists *self);
24size_t perf_session__fprintf_hists(struct perf_session *self, 96
25 struct perf_session *pair, 97void hists__inc_nr_events(struct hists *self, u32 type);
26 bool show_displacement, FILE *fp); 98size_t hists__fprintf_nr_events(struct hists *self, FILE *fp);
99
100size_t hists__fprintf(struct hists *self, struct hists *pair,
101 bool show_displacement, FILE *fp);
102
103int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip);
104int hist_entry__annotate(struct hist_entry *self, struct list_head *head,
105 size_t privsize);
106
107void hists__filter_by_dso(struct hists *self, const struct dso *dso);
108void hists__filter_by_thread(struct hists *self, const struct thread *thread);
109
110u16 hists__col_len(struct hists *self, enum hist_column col);
111void hists__set_col_len(struct hists *self, enum hist_column col, u16 len);
112bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len);
113
114#ifdef NO_NEWT_SUPPORT
115static inline int hists__browse(struct hists *self __used,
116 const char *helpline __used,
117 const char *ev_name __used)
118{
119 return 0;
120}
121
122static inline int hists__tui_browse_tree(struct rb_root *self __used,
123 const char *help __used)
124{
125 return 0;
126}
127
128static inline int hist_entry__tui_annotate(struct hist_entry *self __used)
129{
130 return 0;
131}
132#define KEY_LEFT -1
133#define KEY_RIGHT -2
134#else
135#include <newt.h>
136int hists__browse(struct hists *self, const char *helpline,
137 const char *ev_name);
138int hist_entry__tui_annotate(struct hist_entry *self);
139
140#define KEY_LEFT NEWT_KEY_LEFT
141#define KEY_RIGHT NEWT_KEY_RIGHT
142
143int hists__tui_browse_tree(struct rb_root *self, const char *help);
144#endif
145
146unsigned int hists__sort_list_width(struct hists *self);
147
27#endif /* __PERF_HIST_H */ 148#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/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..bb4ac2e05385 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -1,13 +1,12 @@
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{
@@ -20,10 +19,9 @@ static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
20 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0; 19 (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
21} 20}
22 21
23unsigned long generic_find_next_zero_le_bit(const unsigned long *addr, unsigned 22static inline unsigned long hweight_long(unsigned long w)
24 long size, unsigned long offset); 23{
25 24 return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
26unsigned long generic_find_next_le_bit(const unsigned long *addr, unsigned 25}
27 long size, unsigned long offset);
28 26
29#endif 27#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/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..78575796d5f3
--- /dev/null
+++ b/tools/perf/util/map.h
@@ -0,0 +1,227 @@
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
218int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
219 int verbose, FILE *fp);
220
221struct map *map_groups__find_by_name(struct map_groups *self,
222 enum map_type type, const char *name);
223struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
224
225void map_groups__flush(struct map_groups *self);
226
227#endif /* __PERF_MAP_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index e5bc0fb016b2..4af5bd59cfd1 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -5,6 +5,7 @@
5#include "parse-events.h" 5#include "parse-events.h"
6#include "exec_cmd.h" 6#include "exec_cmd.h"
7#include "string.h" 7#include "string.h"
8#include "symbol.h"
8#include "cache.h" 9#include "cache.h"
9#include "header.h" 10#include "header.h"
10#include "debugfs.h" 11#include "debugfs.h"
@@ -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
@@ -444,13 +436,21 @@ parse_single_tracepoint_event(char *sys_name,
444 attr->type = PERF_TYPE_TRACEPOINT; 436 attr->type = PERF_TYPE_TRACEPOINT;
445 *strp = evt_name + evt_length; 437 *strp = evt_name + evt_length;
446 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
445
447 return EVT_HANDLED; 446 return EVT_HANDLED;
448} 447}
449 448
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 ?: "");
@@ -522,13 +525,13 @@ static enum event_result parse_tracepoint_event(const char **strp,
522 if (evt_length >= MAX_EVENT_LENGTH) 525 if (evt_length >= MAX_EVENT_LENGTH)
523 return EVT_FAILED; 526 return EVT_FAILED;
524 527
525 if (!strcmp(evt_name, "*")) { 528 if (strpbrk(evt_name, "*?")) {
526 *strp = evt_name + evt_length; 529 *strp = evt_name + evt_length;
527 return parse_subsystem_tracepoint_event(sys_name, flags); 530 return parse_multiple_tracepoint_event(sys_name, evt_name,
531 flags);
528 } else 532 } else
529 return parse_single_tracepoint_event(sys_name, evt_name, 533 return parse_single_tracepoint_event(sys_name, evt_name,
530 evt_length, flags, 534 evt_length, attr, strp);
531 attr, strp);
532} 535}
533 536
534static enum event_result 537static enum event_result
@@ -599,8 +602,15 @@ parse_breakpoint_event(const char **strp, struct perf_event_attr *attr)
599 return EVT_FAILED; 602 return EVT_FAILED;
600 } 603 }
601 604
602 /* We should find a nice way to override the access type */ 605 /*
603 attr->bp_len = HW_BREAKPOINT_LEN_4; 606 * We should find a nice way to override the access length
607 * Provide some defaults for now
608 */
609 if (attr->bp_type == HW_BREAKPOINT_X)
610 attr->bp_len = sizeof(long);
611 else
612 attr->bp_len = HW_BREAKPOINT_LEN_4;
613
604 attr->type = PERF_TYPE_BREAKPOINT; 614 attr->type = PERF_TYPE_BREAKPOINT;
605 615
606 return EVT_HANDLED; 616 return EVT_HANDLED;
@@ -685,19 +695,29 @@ static enum event_result
685parse_event_modifier(const char **strp, struct perf_event_attr *attr) 695parse_event_modifier(const char **strp, struct perf_event_attr *attr)
686{ 696{
687 const char *str = *strp; 697 const char *str = *strp;
688 int eu = 1, ek = 1, eh = 1; 698 int exclude = 0;
699 int eu = 0, ek = 0, eh = 0, precise = 0;
689 700
690 if (*str++ != ':') 701 if (*str++ != ':')
691 return 0; 702 return 0;
692 while (*str) { 703 while (*str) {
693 if (*str == 'u') 704 if (*str == 'u') {
705 if (!exclude)
706 exclude = eu = ek = eh = 1;
694 eu = 0; 707 eu = 0;
695 else if (*str == 'k') 708 } else if (*str == 'k') {
709 if (!exclude)
710 exclude = eu = ek = eh = 1;
696 ek = 0; 711 ek = 0;
697 else if (*str == 'h') 712 } else if (*str == 'h') {
713 if (!exclude)
714 exclude = eu = ek = eh = 1;
698 eh = 0; 715 eh = 0;
699 else 716 } else if (*str == 'p') {
717 precise++;
718 } else
700 break; 719 break;
720
701 ++str; 721 ++str;
702 } 722 }
703 if (str >= *strp + 2) { 723 if (str >= *strp + 2) {
@@ -705,6 +725,7 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
705 attr->exclude_user = eu; 725 attr->exclude_user = eu;
706 attr->exclude_kernel = ek; 726 attr->exclude_kernel = ek;
707 attr->exclude_hv = eh; 727 attr->exclude_hv = eh;
728 attr->precise_ip = precise;
708 return 1; 729 return 1;
709 } 730 }
710 return 0; 731 return 0;
@@ -753,11 +774,11 @@ modifier:
753 return ret; 774 return ret;
754} 775}
755 776
756static void store_event_type(const char *orgname) 777static int store_event_type(const char *orgname)
757{ 778{
758 char filename[PATH_MAX], *c; 779 char filename[PATH_MAX], *c;
759 FILE *file; 780 FILE *file;
760 int id; 781 int id, n;
761 782
762 sprintf(filename, "%s/", debugfs_path); 783 sprintf(filename, "%s/", debugfs_path);
763 strncat(filename, orgname, strlen(orgname)); 784 strncat(filename, orgname, strlen(orgname));
@@ -769,11 +790,14 @@ static void store_event_type(const char *orgname)
769 790
770 file = fopen(filename, "r"); 791 file = fopen(filename, "r");
771 if (!file) 792 if (!file)
772 return; 793 return 0;
773 if (fscanf(file, "%i", &id) < 1) 794 n = fscanf(file, "%i", &id);
774 die("cannot store event ID");
775 fclose(file); 795 fclose(file);
776 perf_header__push_event(id, orgname); 796 if (n < 1) {
797 pr_err("cannot store event ID\n");
798 return -EINVAL;
799 }
800 return perf_header__push_event(id, orgname);
777} 801}
778 802
779int parse_events(const struct option *opt __used, const char *str, int unset __used) 803int parse_events(const struct option *opt __used, const char *str, int unset __used)
@@ -782,7 +806,8 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u
782 enum event_result ret; 806 enum event_result ret;
783 807
784 if (strchr(str, ':')) 808 if (strchr(str, ':'))
785 store_event_type(str); 809 if (store_event_type(str) < 0)
810 return -1;
786 811
787 for (;;) { 812 for (;;) {
788 if (nr_counters == MAX_COUNTERS) 813 if (nr_counters == MAX_COUNTERS)
@@ -835,11 +860,12 @@ int parse_filter(const struct option *opt __used, const char *str,
835} 860}
836 861
837static const char * const event_type_descriptors[] = { 862static const char * const event_type_descriptors[] = {
838 "",
839 "Hardware event", 863 "Hardware event",
840 "Software event", 864 "Software event",
841 "Tracepoint event", 865 "Tracepoint event",
842 "Hardware cache event", 866 "Hardware cache event",
867 "Raw hardware event descriptor",
868 "Hardware breakpoint",
843}; 869};
844 870
845/* 871/*
@@ -872,7 +898,7 @@ static void print_tracepoint_events(void)
872 snprintf(evt_path, MAXPATHLEN, "%s:%s", 898 snprintf(evt_path, MAXPATHLEN, "%s:%s",
873 sys_dirent.d_name, evt_dirent.d_name); 899 sys_dirent.d_name, evt_dirent.d_name);
874 printf(" %-42s [%s]\n", evt_path, 900 printf(" %-42s [%s]\n", evt_path,
875 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 901 event_type_descriptors[PERF_TYPE_TRACEPOINT]);
876 } 902 }
877 closedir(evt_dir); 903 closedir(evt_dir);
878 } 904 }
@@ -892,9 +918,7 @@ void print_events(void)
892 printf("List of pre-defined events (to be used in -e):\n"); 918 printf("List of pre-defined events (to be used in -e):\n");
893 919
894 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 920 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
895 type = syms->type + 1; 921 type = syms->type;
896 if (type >= ARRAY_SIZE(event_type_descriptors))
897 type = 0;
898 922
899 if (type != prev_type) 923 if (type != prev_type)
900 printf("\n"); 924 printf("\n");
@@ -919,17 +943,20 @@ void print_events(void)
919 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 943 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
920 printf(" %-42s [%s]\n", 944 printf(" %-42s [%s]\n",
921 event_cache_name(type, op, i), 945 event_cache_name(type, op, i),
922 event_type_descriptors[4]); 946 event_type_descriptors[PERF_TYPE_HW_CACHE]);
923 } 947 }
924 } 948 }
925 } 949 }
926 950
927 printf("\n"); 951 printf("\n");
928 printf(" %-42s [raw hardware event descriptor]\n", 952 printf(" %-42s [%s]\n",
929 "rNNN"); 953 "rNNN (see 'perf list --help' on how to encode it)",
954 event_type_descriptors[PERF_TYPE_RAW]);
930 printf("\n"); 955 printf("\n");
931 956
932 printf(" %-42s [hardware breakpoint]\n", "mem:<addr>[:access]"); 957 printf(" %-42s [%s]\n",
958 "mem:<addr>[:access]",
959 event_type_descriptors[PERF_TYPE_BREAKPOINT]);
933 printf("\n"); 960 printf("\n");
934 961
935 print_tracepoint_events(); 962 print_tracepoint_events();
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index b8c1f64bc935..fc4ab3fe877a 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -13,6 +13,7 @@ struct tracepoint_path {
13}; 13};
14 14
15extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 15extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
16extern bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events);
16 17
17extern int nr_counters; 18extern int nr_counters;
18 19
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..c7d72dce54b2 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) \
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index fd1f2faaade4..58a470d036dd 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -54,21 +54,6 @@ static char *cleanup_path(char *path)
54 return path; 54 return path;
55} 55}
56 56
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) 57static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
73{ 58{
74 const char *perf_dir = get_perf_dir(); 59 const char *perf_dir = get_perf_dir();
@@ -89,15 +74,6 @@ bad:
89 return buf; 74 return buf;
90} 75}
91 76
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, ...) 77char *perf_pathdup(const char *fmt, ...)
102{ 78{
103 char path[PATH_MAX]; 79 char path[PATH_MAX];
@@ -143,184 +119,6 @@ char *perf_path(const char *fmt, ...)
143 return cleanup_path(pathname); 119 return cleanup_path(pathname);
144} 120}
145 121
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 */ 122/* strip arbitrary amount of directory separators at end of path */
325static inline int chomp_trailing_dir_sep(const char *path, int len) 123static inline int chomp_trailing_dir_sep(const char *path, int len)
326{ 124{
@@ -354,5 +152,5 @@ char *strip_path_suffix(const char *path, const char *suffix)
354 152
355 if (path_len && !is_dir_sep(path[path_len - 1])) 153 if (path_len && !is_dir_sep(path[path_len - 1]))
356 return NULL; 154 return NULL;
357 return xstrndup(path, chomp_trailing_dir_sep(path, path_len)); 155 return strndup(path, chomp_trailing_dir_sep(path, path_len));
358} 156}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 29465d440043..fcc16e4349df 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,398 @@ 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 */
78static int init_vmlinux(void)
79{
80 struct dso *kernel;
81 int ret;
82
83 symbol_conf.sort_by_name = true;
84 if (symbol_conf.vmlinux_name == NULL)
85 symbol_conf.try_vmlinux_path = true;
86 else
87 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
88 ret = symbol__init();
89 if (ret < 0) {
90 pr_debug("Failed to init symbol map.\n");
91 goto out;
92 }
93
94 ret = machine__init(&machine, "/", 0);
95 if (ret < 0)
96 goto out;
97
98 kernel = dso__new_kernel(symbol_conf.vmlinux_name);
99 if (kernel == NULL)
100 die("Failed to create kernel dso.");
101
102 ret = __machine__create_kernel_maps(&machine, kernel);
103 if (ret < 0)
104 pr_debug("Failed to create kernel maps.\n");
105
106out:
107 if (ret < 0)
108 pr_warning("Failed to init vmlinux path.\n");
109 return ret;
110}
111
112#ifdef DWARF_SUPPORT
113static int open_vmlinux(void)
114{
115 if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
116 pr_debug("Failed to load kernel map.\n");
117 return -EINVAL;
118 }
119 pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);
120 return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
121}
122
123/*
124 * Convert trace point to probe point with debuginfo
125 * Currently only handles kprobes.
126 */
127static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
128 struct perf_probe_point *pp)
129{
130 struct symbol *sym;
131 int fd, ret = -ENOENT;
132
133 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
134 tp->symbol, NULL);
135 if (sym) {
136 fd = open_vmlinux();
137 if (fd >= 0) {
138 ret = find_perf_probe_point(fd,
139 sym->start + tp->offset, pp);
140 close(fd);
141 }
142 }
143 if (ret <= 0) {
144 pr_debug("Failed to find corresponding probes from "
145 "debuginfo. Use kprobe event information.\n");
146 pp->function = strdup(tp->symbol);
147 if (pp->function == NULL)
148 return -ENOMEM;
149 pp->offset = tp->offset;
150 }
151 pp->retprobe = tp->retprobe;
152
153 return 0;
154}
155
156/* Try to find perf_probe_event with debuginfo */
157static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
158 struct probe_trace_event **tevs,
159 int max_tevs)
160{
161 bool need_dwarf = perf_probe_event_need_dwarf(pev);
162 int fd, ntevs;
163
164 fd = open_vmlinux();
165 if (fd < 0) {
166 if (need_dwarf) {
167 pr_warning("Failed to open debuginfo file.\n");
168 return fd;
169 }
170 pr_debug("Could not open vmlinux. Try to use symbols.\n");
171 return 0;
172 }
173
174 /* Searching trace events corresponding to probe event */
175 ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
176 close(fd);
177
178 if (ntevs > 0) { /* Succeeded to find trace events */
179 pr_debug("find %d probe_trace_events.\n", ntevs);
180 return ntevs;
181 }
182
183 if (ntevs == 0) { /* No error but failed to find probe point. */
184 pr_warning("Probe point '%s' not found.\n",
185 synthesize_perf_probe_point(&pev->point));
186 return -ENOENT;
187 }
188 /* Error path : ntevs < 0 */
189 pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
190 if (ntevs == -EBADF) {
191 pr_warning("Warning: No dwarf info found in the vmlinux - "
192 "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
193 if (!need_dwarf) {
194 pr_debug("Trying to use symbols.\nn");
195 return 0;
196 }
197 }
198 return ntevs;
199}
200
201/*
202 * Find a src file from a DWARF tag path. Prepend optional source path prefix
203 * and chop off leading directories that do not exist. Result is passed back as
204 * a newly allocated path on success.
205 * Return 0 if file was found and readable, -errno otherwise.
206 */
207static int get_real_path(const char *raw_path, const char *comp_dir,
208 char **new_path)
209{
210 const char *prefix = symbol_conf.source_prefix;
211
212 if (!prefix) {
213 if (raw_path[0] != '/' && comp_dir)
214 /* If not an absolute path, try to use comp_dir */
215 prefix = comp_dir;
216 else {
217 if (access(raw_path, R_OK) == 0) {
218 *new_path = strdup(raw_path);
219 return 0;
220 } else
221 return -errno;
222 }
223 }
224
225 *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
226 if (!*new_path)
227 return -ENOMEM;
228
229 for (;;) {
230 sprintf(*new_path, "%s/%s", prefix, raw_path);
231
232 if (access(*new_path, R_OK) == 0)
233 return 0;
234
235 if (!symbol_conf.source_prefix)
236 /* In case of searching comp_dir, don't retry */
237 return -errno;
238
239 switch (errno) {
240 case ENAMETOOLONG:
241 case ENOENT:
242 case EROFS:
243 case EFAULT:
244 raw_path = strchr(++raw_path, '/');
245 if (!raw_path) {
246 free(*new_path);
247 *new_path = NULL;
248 return -ENOENT;
249 }
250 continue;
251
252 default:
253 free(*new_path);
254 *new_path = NULL;
255 return -errno;
256 }
257 }
258}
259
260#define LINEBUF_SIZE 256
261#define NR_ADDITIONAL_LINES 2
262
263static int show_one_line(FILE *fp, int l, bool skip, bool show_num)
264{
265 char buf[LINEBUF_SIZE];
266 const char *color = PERF_COLOR_BLUE;
267
268 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
269 goto error;
270 if (!skip) {
271 if (show_num)
272 fprintf(stdout, "%7d %s", l, buf);
273 else
274 color_fprintf(stdout, color, " %s", buf);
275 }
276
277 while (strlen(buf) == LINEBUF_SIZE - 1 &&
278 buf[LINEBUF_SIZE - 2] != '\n') {
279 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
280 goto error;
281 if (!skip) {
282 if (show_num)
283 fprintf(stdout, "%s", buf);
284 else
285 color_fprintf(stdout, color, "%s", buf);
286 }
287 }
288
289 return 0;
290error:
291 if (feof(fp))
292 pr_warning("Source file is shorter than expected.\n");
293 else
294 pr_warning("File read error: %s\n", strerror(errno));
295
296 return -1;
297}
298
299/*
300 * Show line-range always requires debuginfo to find source file and
301 * line number.
302 */
303int show_line_range(struct line_range *lr)
304{
305 int l = 1;
306 struct line_node *ln;
307 FILE *fp;
308 int fd, ret;
309 char *tmp;
310
311 /* Search a line range */
312 ret = init_vmlinux();
313 if (ret < 0)
314 return ret;
315
316 fd = open_vmlinux();
317 if (fd < 0) {
318 pr_warning("Failed to open debuginfo file.\n");
319 return fd;
320 }
321
322 ret = find_line_range(fd, lr);
323 close(fd);
324 if (ret == 0) {
325 pr_warning("Specified source line is not found.\n");
326 return -ENOENT;
327 } else if (ret < 0) {
328 pr_warning("Debuginfo analysis failed. (%d)\n", ret);
329 return ret;
330 }
331
332 /* Convert source file path */
333 tmp = lr->path;
334 ret = get_real_path(tmp, lr->comp_dir, &lr->path);
335 free(tmp); /* Free old path */
336 if (ret < 0) {
337 pr_warning("Failed to find source file. (%d)\n", ret);
338 return ret;
339 }
340
341 setup_pager();
342
343 if (lr->function)
344 fprintf(stdout, "<%s:%d>\n", lr->function,
345 lr->start - lr->offset);
346 else
347 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
348
349 fp = fopen(lr->path, "r");
350 if (fp == NULL) {
351 pr_warning("Failed to open %s: %s\n", lr->path,
352 strerror(errno));
353 return -errno;
354 }
355 /* Skip to starting line number */
356 while (l < lr->start && ret >= 0)
357 ret = show_one_line(fp, l++, true, false);
358 if (ret < 0)
359 goto end;
360
361 list_for_each_entry(ln, &lr->line_list, list) {
362 while (ln->line > l && ret >= 0)
363 ret = show_one_line(fp, (l++) - lr->offset,
364 false, false);
365 if (ret >= 0)
366 ret = show_one_line(fp, (l++) - lr->offset,
367 false, true);
368 if (ret < 0)
369 goto end;
370 }
371
372 if (lr->end == INT_MAX)
373 lr->end = l + NR_ADDITIONAL_LINES;
374 while (l <= lr->end && !feof(fp) && ret >= 0)
375 ret = show_one_line(fp, (l++) - lr->offset, false, false);
376end:
377 fclose(fp);
378 return ret;
379}
380
381#else /* !DWARF_SUPPORT */
382
383static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
384 struct perf_probe_point *pp)
385{
386 pp->function = strdup(tp->symbol);
387 if (pp->function == NULL)
388 return -ENOMEM;
389 pp->offset = tp->offset;
390 pp->retprobe = tp->retprobe;
391
392 return 0;
393}
394
395static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
396 struct probe_trace_event **tevs __unused,
397 int max_tevs __unused)
398{
399 if (perf_probe_event_need_dwarf(pev)) {
400 pr_warning("Debuginfo-analysis is not supported.\n");
401 return -ENOSYS;
402 }
403 return 0;
404}
405
406int show_line_range(struct line_range *lr __unused)
407{
408 pr_warning("Debuginfo-analysis is not supported.\n");
409 return -ENOSYS;
410}
411
412#endif
413
414int parse_line_range_desc(const char *arg, struct line_range *lr)
415{
416 const char *ptr;
417 char *tmp;
418 /*
419 * <Syntax>
420 * SRC:SLN[+NUM|-ELN]
421 * FUNC[:SLN[+NUM|-ELN]]
422 */
423 ptr = strchr(arg, ':');
424 if (ptr) {
425 lr->start = (int)strtoul(ptr + 1, &tmp, 0);
426 if (*tmp == '+') {
427 lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
428 lr->end--; /*
429 * Adjust the number of lines here.
430 * If the number of lines == 1, the
431 * the end of line should be equal to
432 * the start of line.
433 */
434 } else if (*tmp == '-')
435 lr->end = (int)strtoul(tmp + 1, &tmp, 0);
436 else
437 lr->end = INT_MAX;
438 pr_debug("Line range is %d to %d\n", lr->start, lr->end);
439 if (lr->start > lr->end) {
440 semantic_error("Start line must be smaller"
441 " than end line.\n");
442 return -EINVAL;
443 }
444 if (*tmp != '\0') {
445 semantic_error("Tailing with invalid character '%d'.\n",
446 *tmp);
447 return -EINVAL;
448 }
449 tmp = strndup(arg, (ptr - arg));
450 } else {
451 tmp = strdup(arg);
452 lr->end = INT_MAX;
453 }
454
455 if (tmp == NULL)
456 return -ENOMEM;
457
458 if (strchr(tmp, '.'))
459 lr->file = tmp;
460 else
461 lr->function = tmp;
462
463 return 0;
464}
465
65/* Check the name is good for event/group */ 466/* Check the name is good for event/group */
66static bool check_event_name(const char *name) 467static bool check_event_name(const char *name)
67{ 468{
@@ -75,50 +476,66 @@ static bool check_event_name(const char *name)
75} 476}
76 477
77/* Parse probepoint definition. */ 478/* Parse probepoint definition. */
78static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 479static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
79{ 480{
481 struct perf_probe_point *pp = &pev->point;
80 char *ptr, *tmp; 482 char *ptr, *tmp;
81 char c, nc = 0; 483 char c, nc = 0;
82 /* 484 /*
83 * <Syntax> 485 * <Syntax>
84 * perf probe [EVENT=]SRC:LN 486 * perf probe [EVENT=]SRC[:LN|;PTN]
85 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC] 487 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
86 * 488 *
87 * TODO:Group name support 489 * TODO:Group name support
88 */ 490 */
89 491
90 ptr = strchr(arg, '='); 492 ptr = strpbrk(arg, ";=@+%");
91 if (ptr) { /* Event name */ 493 if (ptr && *ptr == '=') { /* Event name */
92 *ptr = '\0'; 494 *ptr = '\0';
93 tmp = ptr + 1; 495 tmp = ptr + 1;
94 ptr = strchr(arg, ':'); 496 if (strchr(arg, ':')) {
95 if (ptr) /* Group name is not supported yet. */ 497 semantic_error("Group name is not supported yet.\n");
96 semantic_error("Group name is not supported yet."); 498 return -ENOTSUP;
97 if (!check_event_name(arg)) 499 }
500 if (!check_event_name(arg)) {
98 semantic_error("%s is bad for event name -it must " 501 semantic_error("%s is bad for event name -it must "
99 "follow C symbol-naming rule.", arg); 502 "follow C symbol-naming rule.\n", arg);
100 pp->event = strdup(arg); 503 return -EINVAL;
504 }
505 pev->event = strdup(arg);
506 if (pev->event == NULL)
507 return -ENOMEM;
508 pev->group = NULL;
101 arg = tmp; 509 arg = tmp;
102 } 510 }
103 511
104 ptr = strpbrk(arg, ":+@%"); 512 ptr = strpbrk(arg, ";:+@%");
105 if (ptr) { 513 if (ptr) {
106 nc = *ptr; 514 nc = *ptr;
107 *ptr++ = '\0'; 515 *ptr++ = '\0';
108 } 516 }
109 517
518 tmp = strdup(arg);
519 if (tmp == NULL)
520 return -ENOMEM;
521
110 /* Check arg is function or file and copy it */ 522 /* Check arg is function or file and copy it */
111 if (strchr(arg, '.')) /* File */ 523 if (strchr(tmp, '.')) /* File */
112 pp->file = strdup(arg); 524 pp->file = tmp;
113 else /* Function */ 525 else /* Function */
114 pp->function = strdup(arg); 526 pp->function = tmp;
115 DIE_IF(pp->file == NULL && pp->function == NULL);
116 527
117 /* Parse other options */ 528 /* Parse other options */
118 while (ptr) { 529 while (ptr) {
119 arg = ptr; 530 arg = ptr;
120 c = nc; 531 c = nc;
121 ptr = strpbrk(arg, ":+@%"); 532 if (c == ';') { /* Lazy pattern must be the last part */
533 pp->lazy_line = strdup(arg);
534 if (pp->lazy_line == NULL)
535 return -ENOMEM;
536 break;
537 }
538 ptr = strpbrk(arg, ";:+@%");
122 if (ptr) { 539 if (ptr) {
123 nc = *ptr; 540 nc = *ptr;
124 *ptr++ = '\0'; 541 *ptr++ = '\0';
@@ -126,258 +543,690 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
126 switch (c) { 543 switch (c) {
127 case ':': /* Line number */ 544 case ':': /* Line number */
128 pp->line = strtoul(arg, &tmp, 0); 545 pp->line = strtoul(arg, &tmp, 0);
129 if (*tmp != '\0') 546 if (*tmp != '\0') {
130 semantic_error("There is non-digit charactor" 547 semantic_error("There is non-digit char"
131 " in line number."); 548 " in line number.\n");
549 return -EINVAL;
550 }
132 break; 551 break;
133 case '+': /* Byte offset from a symbol */ 552 case '+': /* Byte offset from a symbol */
134 pp->offset = strtoul(arg, &tmp, 0); 553 pp->offset = strtoul(arg, &tmp, 0);
135 if (*tmp != '\0') 554 if (*tmp != '\0') {
136 semantic_error("There is non-digit charactor" 555 semantic_error("There is non-digit character"
137 " in offset."); 556 " in offset.\n");
557 return -EINVAL;
558 }
138 break; 559 break;
139 case '@': /* File name */ 560 case '@': /* File name */
140 if (pp->file) 561 if (pp->file) {
141 semantic_error("SRC@SRC is not allowed."); 562 semantic_error("SRC@SRC is not allowed.\n");
563 return -EINVAL;
564 }
142 pp->file = strdup(arg); 565 pp->file = strdup(arg);
143 DIE_IF(pp->file == NULL); 566 if (pp->file == NULL)
144 if (ptr) 567 return -ENOMEM;
145 semantic_error("@SRC must be the last "
146 "option.");
147 break; 568 break;
148 case '%': /* Probe places */ 569 case '%': /* Probe places */
149 if (strcmp(arg, "return") == 0) { 570 if (strcmp(arg, "return") == 0) {
150 pp->retprobe = 1; 571 pp->retprobe = 1;
151 } else /* Others not supported yet */ 572 } else { /* Others not supported yet */
152 semantic_error("%%%s is not supported.", arg); 573 semantic_error("%%%s is not supported.\n", arg);
574 return -ENOTSUP;
575 }
153 break; 576 break;
154 default: 577 default: /* Buggy case */
155 DIE_IF("Program has a bug."); 578 pr_err("This program has a bug at %s:%d.\n",
579 __FILE__, __LINE__);
580 return -ENOTSUP;
156 break; 581 break;
157 } 582 }
158 } 583 }
159 584
160 /* Exclusion check */ 585 /* Exclusion check */
161 if (pp->line && pp->offset) 586 if (pp->lazy_line && pp->line) {
587 semantic_error("Lazy pattern can't be used with line number.");
588 return -EINVAL;
589 }
590
591 if (pp->lazy_line && pp->offset) {
592 semantic_error("Lazy pattern can't be used with offset.");
593 return -EINVAL;
594 }
595
596 if (pp->line && pp->offset) {
162 semantic_error("Offset can't be used with line number."); 597 semantic_error("Offset can't be used with line number.");
598 return -EINVAL;
599 }
163 600
164 if (!pp->line && pp->file && !pp->function) 601 if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
165 semantic_error("File always requires line number."); 602 semantic_error("File always requires line number or "
603 "lazy pattern.");
604 return -EINVAL;
605 }
166 606
167 if (pp->offset && !pp->function) 607 if (pp->offset && !pp->function) {
168 semantic_error("Offset requires an entry function."); 608 semantic_error("Offset requires an entry function.");
609 return -EINVAL;
610 }
169 611
170 if (pp->retprobe && !pp->function) 612 if (pp->retprobe && !pp->function) {
171 semantic_error("Return probe requires an entry function."); 613 semantic_error("Return probe requires an entry function.");
614 return -EINVAL;
615 }
172 616
173 if ((pp->offset || pp->line) && pp->retprobe) 617 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
174 semantic_error("Offset/Line can't be used with return probe."); 618 semantic_error("Offset/Line/Lazy pattern can't be used with "
619 "return probe.");
620 return -EINVAL;
621 }
175 622
176 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", 623 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); 624 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
625 pp->lazy_line);
626 return 0;
178} 627}
179 628
180/* Parse perf-probe event definition */ 629/* Parse perf-probe event argument */
181void parse_perf_probe_event(const char *str, struct probe_point *pp, 630static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
182 bool *need_dwarf)
183{ 631{
184 char **argv; 632 char *tmp, *goodname;
185 int argc, i; 633 struct perf_probe_arg_field **fieldp;
634
635 pr_debug("parsing arg: %s into ", str);
636
637 tmp = strchr(str, '=');
638 if (tmp) {
639 arg->name = strndup(str, tmp - str);
640 if (arg->name == NULL)
641 return -ENOMEM;
642 pr_debug("name:%s ", arg->name);
643 str = tmp + 1;
644 }
186 645
187 *need_dwarf = false; 646 tmp = strchr(str, ':');
647 if (tmp) { /* Type setting */
648 *tmp = '\0';
649 arg->type = strdup(tmp + 1);
650 if (arg->type == NULL)
651 return -ENOMEM;
652 pr_debug("type:%s ", arg->type);
653 }
188 654
189 argv = argv_split(str, &argc); 655 tmp = strpbrk(str, "-.[");
190 if (!argv) 656 if (!is_c_varname(str) || !tmp) {
191 die("argv_split failed."); 657 /* A variable, register, symbol or special value */
192 if (argc > MAX_PROBE_ARGS + 1) 658 arg->var = strdup(str);
193 semantic_error("Too many arguments"); 659 if (arg->var == NULL)
660 return -ENOMEM;
661 pr_debug("%s\n", arg->var);
662 return 0;
663 }
194 664
665 /* Structure fields or array element */
666 arg->var = strndup(str, tmp - str);
667 if (arg->var == NULL)
668 return -ENOMEM;
669 goodname = arg->var;
670 pr_debug("%s, ", arg->var);
671 fieldp = &arg->field;
672
673 do {
674 *fieldp = zalloc(sizeof(struct perf_probe_arg_field));
675 if (*fieldp == NULL)
676 return -ENOMEM;
677 if (*tmp == '[') { /* Array */
678 str = tmp;
679 (*fieldp)->index = strtol(str + 1, &tmp, 0);
680 (*fieldp)->ref = true;
681 if (*tmp != ']' || tmp == str + 1) {
682 semantic_error("Array index must be a"
683 " number.\n");
684 return -EINVAL;
685 }
686 tmp++;
687 if (*tmp == '\0')
688 tmp = NULL;
689 } else { /* Structure */
690 if (*tmp == '.') {
691 str = tmp + 1;
692 (*fieldp)->ref = false;
693 } else if (tmp[1] == '>') {
694 str = tmp + 2;
695 (*fieldp)->ref = true;
696 } else {
697 semantic_error("Argument parse error: %s\n",
698 str);
699 return -EINVAL;
700 }
701 tmp = strpbrk(str, "-.[");
702 }
703 if (tmp) {
704 (*fieldp)->name = strndup(str, tmp - str);
705 if ((*fieldp)->name == NULL)
706 return -ENOMEM;
707 if (*str != '[')
708 goodname = (*fieldp)->name;
709 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
710 fieldp = &(*fieldp)->next;
711 }
712 } while (tmp);
713 (*fieldp)->name = strdup(str);
714 if ((*fieldp)->name == NULL)
715 return -ENOMEM;
716 if (*str != '[')
717 goodname = (*fieldp)->name;
718 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
719
720 /* If no name is specified, set the last field name (not array index)*/
721 if (!arg->name) {
722 arg->name = strdup(goodname);
723 if (arg->name == NULL)
724 return -ENOMEM;
725 }
726 return 0;
727}
728
729/* Parse perf-probe event command */
730int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
731{
732 char **argv;
733 int argc, i, ret = 0;
734
735 argv = argv_split(cmd, &argc);
736 if (!argv) {
737 pr_debug("Failed to split arguments.\n");
738 return -ENOMEM;
739 }
740 if (argc - 1 > MAX_PROBE_ARGS) {
741 semantic_error("Too many probe arguments (%d).\n", argc - 1);
742 ret = -ERANGE;
743 goto out;
744 }
195 /* Parse probe point */ 745 /* Parse probe point */
196 parse_perf_probe_probepoint(argv[0], pp); 746 ret = parse_perf_probe_point(argv[0], pev);
197 if (pp->file || pp->line) 747 if (ret < 0)
198 *need_dwarf = true; 748 goto out;
199 749
200 /* Copy arguments and ensure return probe has no C argument */ 750 /* Copy arguments and ensure return probe has no C argument */
201 pp->nr_args = argc - 1; 751 pev->nargs = argc - 1;
202 pp->args = zalloc(sizeof(char *) * pp->nr_args); 752 pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
203 for (i = 0; i < pp->nr_args; i++) { 753 if (pev->args == NULL) {
204 pp->args[i] = strdup(argv[i + 1]); 754 ret = -ENOMEM;
205 if (!pp->args[i]) 755 goto out;
206 die("Failed to copy argument."); 756 }
207 if (is_c_varname(pp->args[i])) { 757 for (i = 0; i < pev->nargs && ret >= 0; i++) {
208 if (pp->retprobe) 758 ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
209 semantic_error("You can't specify local" 759 if (ret >= 0 &&
210 " variable for kretprobe"); 760 is_c_varname(pev->args[i].var) && pev->point.retprobe) {
211 *need_dwarf = true; 761 semantic_error("You can't specify local variable for"
762 " kretprobe.\n");
763 ret = -EINVAL;
212 } 764 }
213 } 765 }
214 766out:
215 argv_free(argv); 767 argv_free(argv);
768
769 return ret;
216} 770}
217 771
218/* Parse kprobe_events event into struct probe_point */ 772/* Return true if this perf_probe_event requires debuginfo */
219void parse_trace_kprobe_event(const char *str, struct probe_point *pp) 773bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
220{ 774{
775 int i;
776
777 if (pev->point.file || pev->point.line || pev->point.lazy_line)
778 return true;
779
780 for (i = 0; i < pev->nargs; i++)
781 if (is_c_varname(pev->args[i].var))
782 return true;
783
784 return false;
785}
786
787/* Parse probe_events event into struct probe_point */
788static int parse_probe_trace_command(const char *cmd,
789 struct probe_trace_event *tev)
790{
791 struct probe_trace_point *tp = &tev->point;
221 char pr; 792 char pr;
222 char *p; 793 char *p;
223 int ret, i, argc; 794 int ret, i, argc;
224 char **argv; 795 char **argv;
225 796
226 pr_debug("Parsing kprobe_events: %s\n", str); 797 pr_debug("Parsing probe_events: %s\n", cmd);
227 argv = argv_split(str, &argc); 798 argv = argv_split(cmd, &argc);
228 if (!argv) 799 if (!argv) {
229 die("argv_split failed."); 800 pr_debug("Failed to split arguments.\n");
230 if (argc < 2) 801 return -ENOMEM;
231 semantic_error("Too less arguments."); 802 }
803 if (argc < 2) {
804 semantic_error("Too few probe arguments.\n");
805 ret = -ERANGE;
806 goto out;
807 }
232 808
233 /* Scan event and group name. */ 809 /* Scan event and group name. */
234 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 810 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
235 &pr, (float *)(void *)&pp->group, 811 &pr, (float *)(void *)&tev->group,
236 (float *)(void *)&pp->event); 812 (float *)(void *)&tev->event);
237 if (ret != 3) 813 if (ret != 3) {
238 semantic_error("Failed to parse event name: %s", argv[0]); 814 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); 815 ret = -EINVAL;
816 goto out;
817 }
818 pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
240 819
241 pp->retprobe = (pr == 'r'); 820 tp->retprobe = (pr == 'r');
242 821
243 /* Scan function name and offset */ 822 /* Scan function name and offset */
244 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, 823 ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
245 &pp->offset); 824 &tp->offset);
246 if (ret == 1) 825 if (ret == 1)
247 pp->offset = 0; 826 tp->offset = 0;
248 827
249 /* kprobe_events doesn't have this information */ 828 tev->nargs = argc - 2;
250 pp->line = 0; 829 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
251 pp->file = NULL; 830 if (tev->args == NULL) {
252 831 ret = -ENOMEM;
253 pp->nr_args = argc - 2; 832 goto out;
254 pp->args = zalloc(sizeof(char *) * pp->nr_args); 833 }
255 for (i = 0; i < pp->nr_args; i++) { 834 for (i = 0; i < tev->nargs; i++) {
256 p = strchr(argv[i + 2], '='); 835 p = strchr(argv[i + 2], '=');
257 if (p) /* We don't need which register is assigned. */ 836 if (p) /* We don't need which register is assigned. */
258 *p = '\0'; 837 *p++ = '\0';
259 pp->args[i] = strdup(argv[i + 2]); 838 else
260 if (!pp->args[i]) 839 p = argv[i + 2];
261 die("Failed to copy argument."); 840 tev->args[i].name = strdup(argv[i + 2]);
841 /* TODO: parse regs and offset */
842 tev->args[i].value = strdup(p);
843 if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
844 ret = -ENOMEM;
845 goto out;
846 }
262 } 847 }
263 848 ret = 0;
849out:
264 argv_free(argv); 850 argv_free(argv);
851 return ret;
265} 852}
266 853
267/* Synthesize only probe point (not argument) */ 854/* Compose only probe arg */
268int synthesize_perf_probe_point(struct probe_point *pp) 855int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
269{ 856{
270 char *buf; 857 struct perf_probe_arg_field *field = pa->field;
271 char offs[64] = "", line[64] = "";
272 int ret; 858 int ret;
859 char *tmp = buf;
273 860
274 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 861 if (pa->name && pa->var)
275 if (!buf) 862 ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
276 die("Failed to allocate memory by zalloc."); 863 else
864 ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
865 if (ret <= 0)
866 goto error;
867 tmp += ret;
868 len -= ret;
869
870 while (field) {
871 if (field->name[0] == '[')
872 ret = e_snprintf(tmp, len, "%s", field->name);
873 else
874 ret = e_snprintf(tmp, len, "%s%s",
875 field->ref ? "->" : ".", field->name);
876 if (ret <= 0)
877 goto error;
878 tmp += ret;
879 len -= ret;
880 field = field->next;
881 }
882
883 if (pa->type) {
884 ret = e_snprintf(tmp, len, ":%s", pa->type);
885 if (ret <= 0)
886 goto error;
887 tmp += ret;
888 len -= ret;
889 }
890
891 return tmp - buf;
892error:
893 pr_debug("Failed to synthesize perf probe argument: %s",
894 strerror(-ret));
895 return ret;
896}
897
898/* Compose only probe point (not argument) */
899static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
900{
901 char *buf, *tmp;
902 char offs[32] = "", line[32] = "", file[32] = "";
903 int ret, len;
904
905 buf = zalloc(MAX_CMDLEN);
906 if (buf == NULL) {
907 ret = -ENOMEM;
908 goto error;
909 }
277 if (pp->offset) { 910 if (pp->offset) {
278 ret = e_snprintf(offs, 64, "+%d", pp->offset); 911 ret = e_snprintf(offs, 32, "+%lu", pp->offset);
279 if (ret <= 0) 912 if (ret <= 0)
280 goto error; 913 goto error;
281 } 914 }
282 if (pp->line) { 915 if (pp->line) {
283 ret = e_snprintf(line, 64, ":%d", pp->line); 916 ret = e_snprintf(line, 32, ":%d", pp->line);
917 if (ret <= 0)
918 goto error;
919 }
920 if (pp->file) {
921 len = strlen(pp->file) - 31;
922 if (len < 0)
923 len = 0;
924 tmp = strchr(pp->file + len, '/');
925 if (!tmp)
926 tmp = pp->file + len;
927 ret = e_snprintf(file, 32, "@%s", tmp + 1);
284 if (ret <= 0) 928 if (ret <= 0)
285 goto error; 929 goto error;
286 } 930 }
287 931
288 if (pp->function) 932 if (pp->function)
289 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 933 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
290 offs, pp->retprobe ? "%return" : "", line); 934 offs, pp->retprobe ? "%return" : "", line,
935 file);
291 else 936 else
292 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 937 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
293 if (ret <= 0) { 938 if (ret <= 0)
939 goto error;
940
941 return buf;
294error: 942error:
295 free(pp->probes[0]); 943 pr_debug("Failed to synthesize perf probe point: %s",
296 pp->probes[0] = NULL; 944 strerror(-ret));
297 } 945 if (buf)
298 return ret; 946 free(buf);
947 return NULL;
299} 948}
300 949
301int synthesize_perf_probe_event(struct probe_point *pp) 950#if 0
951char *synthesize_perf_probe_command(struct perf_probe_event *pev)
302{ 952{
303 char *buf; 953 char *buf;
304 int i, len, ret; 954 int i, len, ret;
305 955
306 len = synthesize_perf_probe_point(pp); 956 buf = synthesize_perf_probe_point(&pev->point);
307 if (len < 0) 957 if (!buf)
308 return 0; 958 return NULL;
309 959
310 buf = pp->probes[0]; 960 len = strlen(buf);
311 for (i = 0; i < pp->nr_args; i++) { 961 for (i = 0; i < pev->nargs; i++) {
312 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 962 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
313 pp->args[i]); 963 pev->args[i].name);
314 if (ret <= 0) 964 if (ret <= 0) {
315 goto error; 965 free(buf);
966 return NULL;
967 }
316 len += ret; 968 len += ret;
317 } 969 }
318 pp->found = 1;
319 970
320 return pp->found; 971 return buf;
321error: 972}
322 free(pp->probes[0]); 973#endif
323 pp->probes[0] = NULL;
324 974
325 return ret; 975static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
976 char **buf, size_t *buflen,
977 int depth)
978{
979 int ret;
980 if (ref->next) {
981 depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
982 buflen, depth + 1);
983 if (depth < 0)
984 goto out;
985 }
986
987 ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
988 if (ret < 0)
989 depth = ret;
990 else {
991 *buf += ret;
992 *buflen -= ret;
993 }
994out:
995 return depth;
996
997}
998
999static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
1000 char *buf, size_t buflen)
1001{
1002 struct probe_trace_arg_ref *ref = arg->ref;
1003 int ret, depth = 0;
1004 char *tmp = buf;
1005
1006 /* Argument name or separator */
1007 if (arg->name)
1008 ret = e_snprintf(buf, buflen, " %s=", arg->name);
1009 else
1010 ret = e_snprintf(buf, buflen, " ");
1011 if (ret < 0)
1012 return ret;
1013 buf += ret;
1014 buflen -= ret;
1015
1016 /* Special case: @XXX */
1017 if (arg->value[0] == '@' && arg->ref)
1018 ref = ref->next;
1019
1020 /* Dereferencing arguments */
1021 if (ref) {
1022 depth = __synthesize_probe_trace_arg_ref(ref, &buf,
1023 &buflen, 1);
1024 if (depth < 0)
1025 return depth;
1026 }
1027
1028 /* Print argument value */
1029 if (arg->value[0] == '@' && arg->ref)
1030 ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
1031 arg->ref->offset);
1032 else
1033 ret = e_snprintf(buf, buflen, "%s", arg->value);
1034 if (ret < 0)
1035 return ret;
1036 buf += ret;
1037 buflen -= ret;
1038
1039 /* Closing */
1040 while (depth--) {
1041 ret = e_snprintf(buf, buflen, ")");
1042 if (ret < 0)
1043 return ret;
1044 buf += ret;
1045 buflen -= ret;
1046 }
1047 /* Print argument type */
1048 if (arg->type) {
1049 ret = e_snprintf(buf, buflen, ":%s", arg->type);
1050 if (ret <= 0)
1051 return ret;
1052 buf += ret;
1053 }
1054
1055 return buf - tmp;
326} 1056}
327 1057
328int synthesize_trace_kprobe_event(struct probe_point *pp) 1058char *synthesize_probe_trace_command(struct probe_trace_event *tev)
329{ 1059{
1060 struct probe_trace_point *tp = &tev->point;
330 char *buf; 1061 char *buf;
331 int i, len, ret; 1062 int i, len, ret;
332 1063
333 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 1064 buf = zalloc(MAX_CMDLEN);
334 if (!buf) 1065 if (buf == NULL)
335 die("Failed to allocate memory by zalloc."); 1066 return NULL;
336 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 1067
337 if (ret <= 0) 1068 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
1069 tp->retprobe ? 'r' : 'p',
1070 tev->group, tev->event,
1071 tp->symbol, tp->offset);
1072 if (len <= 0)
338 goto error; 1073 goto error;
339 len = ret;
340 1074
341 for (i = 0; i < pp->nr_args; i++) { 1075 for (i = 0; i < tev->nargs; i++) {
342 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 1076 ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
343 pp->args[i]); 1077 MAX_CMDLEN - len);
344 if (ret <= 0) 1078 if (ret <= 0)
345 goto error; 1079 goto error;
346 len += ret; 1080 len += ret;
347 } 1081 }
348 pp->found = 1;
349 1082
350 return pp->found; 1083 return buf;
351error: 1084error:
352 free(pp->probes[0]); 1085 free(buf);
353 pp->probes[0] = NULL; 1086 return NULL;
1087}
1088
1089static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1090 struct perf_probe_event *pev)
1091{
1092 char buf[64] = "";
1093 int i, ret;
1094
1095 /* Convert event/group name */
1096 pev->event = strdup(tev->event);
1097 pev->group = strdup(tev->group);
1098 if (pev->event == NULL || pev->group == NULL)
1099 return -ENOMEM;
1100
1101 /* Convert trace_point to probe_point */
1102 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1103 if (ret < 0)
1104 return ret;
1105
1106 /* Convert trace_arg to probe_arg */
1107 pev->nargs = tev->nargs;
1108 pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1109 if (pev->args == NULL)
1110 return -ENOMEM;
1111 for (i = 0; i < tev->nargs && ret >= 0; i++) {
1112 if (tev->args[i].name)
1113 pev->args[i].name = strdup(tev->args[i].name);
1114 else {
1115 ret = synthesize_probe_trace_arg(&tev->args[i],
1116 buf, 64);
1117 pev->args[i].name = strdup(buf);
1118 }
1119 if (pev->args[i].name == NULL && ret >= 0)
1120 ret = -ENOMEM;
1121 }
1122
1123 if (ret < 0)
1124 clear_perf_probe_event(pev);
354 1125
355 return ret; 1126 return ret;
356} 1127}
357 1128
358static int open_kprobe_events(int flags, int mode) 1129void clear_perf_probe_event(struct perf_probe_event *pev)
1130{
1131 struct perf_probe_point *pp = &pev->point;
1132 struct perf_probe_arg_field *field, *next;
1133 int i;
1134
1135 if (pev->event)
1136 free(pev->event);
1137 if (pev->group)
1138 free(pev->group);
1139 if (pp->file)
1140 free(pp->file);
1141 if (pp->function)
1142 free(pp->function);
1143 if (pp->lazy_line)
1144 free(pp->lazy_line);
1145 for (i = 0; i < pev->nargs; i++) {
1146 if (pev->args[i].name)
1147 free(pev->args[i].name);
1148 if (pev->args[i].var)
1149 free(pev->args[i].var);
1150 if (pev->args[i].type)
1151 free(pev->args[i].type);
1152 field = pev->args[i].field;
1153 while (field) {
1154 next = field->next;
1155 if (field->name)
1156 free(field->name);
1157 free(field);
1158 field = next;
1159 }
1160 }
1161 if (pev->args)
1162 free(pev->args);
1163 memset(pev, 0, sizeof(*pev));
1164}
1165
1166static void clear_probe_trace_event(struct probe_trace_event *tev)
1167{
1168 struct probe_trace_arg_ref *ref, *next;
1169 int i;
1170
1171 if (tev->event)
1172 free(tev->event);
1173 if (tev->group)
1174 free(tev->group);
1175 if (tev->point.symbol)
1176 free(tev->point.symbol);
1177 for (i = 0; i < tev->nargs; i++) {
1178 if (tev->args[i].name)
1179 free(tev->args[i].name);
1180 if (tev->args[i].value)
1181 free(tev->args[i].value);
1182 if (tev->args[i].type)
1183 free(tev->args[i].type);
1184 ref = tev->args[i].ref;
1185 while (ref) {
1186 next = ref->next;
1187 free(ref);
1188 ref = next;
1189 }
1190 }
1191 if (tev->args)
1192 free(tev->args);
1193 memset(tev, 0, sizeof(*tev));
1194}
1195
1196static int open_kprobe_events(bool readwrite)
359{ 1197{
360 char buf[PATH_MAX]; 1198 char buf[PATH_MAX];
1199 const char *__debugfs;
361 int ret; 1200 int ret;
362 1201
363 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path); 1202 __debugfs = debugfs_find_mountpoint();
364 if (ret < 0) 1203 if (__debugfs == NULL) {
365 die("Failed to make kprobe_events path."); 1204 pr_warning("Debugfs is not mounted.\n");
1205 return -ENOENT;
1206 }
1207
1208 ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
1209 if (ret >= 0) {
1210 pr_debug("Opening %s write=%d\n", buf, readwrite);
1211 if (readwrite && !probe_event_dry_run)
1212 ret = open(buf, O_RDWR, O_APPEND);
1213 else
1214 ret = open(buf, O_RDONLY, 0);
1215 }
366 1216
367 ret = open(buf, flags, mode);
368 if (ret < 0) { 1217 if (ret < 0) {
369 if (errno == ENOENT) 1218 if (errno == ENOENT)
370 die("kprobe_events file does not exist -" 1219 pr_warning("kprobe_events file does not exist - please"
371 " please rebuild with CONFIG_KPROBE_TRACER."); 1220 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
372 else 1221 else
373 die("Could not open kprobe_events file: %s", 1222 pr_warning("Failed to open kprobe_events file: %s\n",
374 strerror(errno)); 1223 strerror(errno));
375 } 1224 }
376 return ret; 1225 return ret;
377} 1226}
378 1227
379/* Get raw string list of current kprobe_events */ 1228/* Get raw string list of current kprobe_events */
380static struct strlist *get_trace_kprobe_event_rawlist(int fd) 1229static struct strlist *get_probe_trace_command_rawlist(int fd)
381{ 1230{
382 int ret, idx; 1231 int ret, idx;
383 FILE *fp; 1232 FILE *fp;
@@ -397,266 +1246,491 @@ static struct strlist *get_trace_kprobe_event_rawlist(int fd)
397 if (p[idx] == '\n') 1246 if (p[idx] == '\n')
398 p[idx] = '\0'; 1247 p[idx] = '\0';
399 ret = strlist__add(sl, buf); 1248 ret = strlist__add(sl, buf);
400 if (ret < 0) 1249 if (ret < 0) {
401 die("strlist__add failed: %s", strerror(-ret)); 1250 pr_debug("strlist__add failed: %s\n", strerror(-ret));
1251 strlist__delete(sl);
1252 return NULL;
1253 }
402 } 1254 }
403 fclose(fp); 1255 fclose(fp);
404 1256
405 return sl; 1257 return sl;
406} 1258}
407 1259
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 */ 1260/* Show an event */
431static void show_perf_probe_event(const char *event, const char *place, 1261static int show_perf_probe_event(struct perf_probe_event *pev)
432 struct probe_point *pp)
433{ 1262{
434 int i, ret; 1263 int i, ret;
435 char buf[128]; 1264 char buf[128];
1265 char *place;
436 1266
437 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); 1267 /* Synthesize only event probe point */
1268 place = synthesize_perf_probe_point(&pev->point);
1269 if (!place)
1270 return -EINVAL;
1271
1272 ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
438 if (ret < 0) 1273 if (ret < 0)
439 die("Failed to copy event: %s", strerror(-ret)); 1274 return ret;
440 printf(" %-40s (on %s", buf, place); 1275
1276 printf(" %-20s (on %s", buf, place);
441 1277
442 if (pp->nr_args > 0) { 1278 if (pev->nargs > 0) {
443 printf(" with"); 1279 printf(" with");
444 for (i = 0; i < pp->nr_args; i++) 1280 for (i = 0; i < pev->nargs; i++) {
445 printf(" %s", pp->args[i]); 1281 ret = synthesize_perf_probe_arg(&pev->args[i],
1282 buf, 128);
1283 if (ret < 0)
1284 break;
1285 printf(" %s", buf);
1286 }
446 } 1287 }
447 printf(")\n"); 1288 printf(")\n");
1289 free(place);
1290 return ret;
448} 1291}
449 1292
450/* List up current perf-probe events */ 1293/* List up current perf-probe events */
451void show_perf_probe_events(void) 1294int show_perf_probe_events(void)
452{ 1295{
453 int fd; 1296 int fd, ret;
454 struct probe_point pp; 1297 struct probe_trace_event tev;
1298 struct perf_probe_event pev;
455 struct strlist *rawlist; 1299 struct strlist *rawlist;
456 struct str_node *ent; 1300 struct str_node *ent;
457 1301
458 fd = open_kprobe_events(O_RDONLY, 0); 1302 setup_pager();
459 rawlist = get_trace_kprobe_event_rawlist(fd); 1303 ret = init_vmlinux();
1304 if (ret < 0)
1305 return ret;
1306
1307 memset(&tev, 0, sizeof(tev));
1308 memset(&pev, 0, sizeof(pev));
1309
1310 fd = open_kprobe_events(false);
1311 if (fd < 0)
1312 return fd;
1313
1314 rawlist = get_probe_trace_command_rawlist(fd);
460 close(fd); 1315 close(fd);
1316 if (!rawlist)
1317 return -ENOENT;
461 1318
462 strlist__for_each(ent, rawlist) { 1319 strlist__for_each(ent, rawlist) {
463 parse_trace_kprobe_event(ent->s, &pp); 1320 ret = parse_probe_trace_command(ent->s, &tev);
464 /* Synthesize only event probe point */ 1321 if (ret >= 0) {
465 synthesize_perf_probe_point(&pp); 1322 ret = convert_to_perf_probe_event(&tev, &pev);
466 /* Show an event */ 1323 if (ret >= 0)
467 show_perf_probe_event(pp.event, pp.probes[0], &pp); 1324 ret = show_perf_probe_event(&pev);
468 clear_probe_point(&pp); 1325 }
1326 clear_perf_probe_event(&pev);
1327 clear_probe_trace_event(&tev);
1328 if (ret < 0)
1329 break;
469 } 1330 }
470
471 strlist__delete(rawlist); 1331 strlist__delete(rawlist);
1332
1333 return ret;
472} 1334}
473 1335
474/* Get current perf-probe event names */ 1336/* Get current perf-probe event names */
475static struct strlist *get_perf_event_names(int fd, bool include_group) 1337static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
476{ 1338{
477 char buf[128]; 1339 char buf[128];
478 struct strlist *sl, *rawlist; 1340 struct strlist *sl, *rawlist;
479 struct str_node *ent; 1341 struct str_node *ent;
480 struct probe_point pp; 1342 struct probe_trace_event tev;
481 1343 int ret = 0;
482 memset(&pp, 0, sizeof(pp));
483 rawlist = get_trace_kprobe_event_rawlist(fd);
484 1344
1345 memset(&tev, 0, sizeof(tev));
1346 rawlist = get_probe_trace_command_rawlist(fd);
485 sl = strlist__new(true, NULL); 1347 sl = strlist__new(true, NULL);
486 strlist__for_each(ent, rawlist) { 1348 strlist__for_each(ent, rawlist) {
487 parse_trace_kprobe_event(ent->s, &pp); 1349 ret = parse_probe_trace_command(ent->s, &tev);
1350 if (ret < 0)
1351 break;
488 if (include_group) { 1352 if (include_group) {
489 if (e_snprintf(buf, 128, "%s:%s", pp.group, 1353 ret = e_snprintf(buf, 128, "%s:%s", tev.group,
490 pp.event) < 0) 1354 tev.event);
491 die("Failed to copy group:event name."); 1355 if (ret >= 0)
492 strlist__add(sl, buf); 1356 ret = strlist__add(sl, buf);
493 } else 1357 } else
494 strlist__add(sl, pp.event); 1358 ret = strlist__add(sl, tev.event);
495 clear_probe_point(&pp); 1359 clear_probe_trace_event(&tev);
1360 if (ret < 0)
1361 break;
496 } 1362 }
497
498 strlist__delete(rawlist); 1363 strlist__delete(rawlist);
499 1364
1365 if (ret < 0) {
1366 strlist__delete(sl);
1367 return NULL;
1368 }
500 return sl; 1369 return sl;
501} 1370}
502 1371
503static void write_trace_kprobe_event(int fd, const char *buf) 1372static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
504{ 1373{
505 int ret; 1374 int ret = 0;
1375 char *buf = synthesize_probe_trace_command(tev);
1376
1377 if (!buf) {
1378 pr_debug("Failed to synthesize probe trace event.\n");
1379 return -EINVAL;
1380 }
506 1381
507 pr_debug("Writing event: %s\n", buf); 1382 pr_debug("Writing event: %s\n", buf);
508 ret = write(fd, buf, strlen(buf)); 1383 if (!probe_event_dry_run) {
509 if (ret <= 0) 1384 ret = write(fd, buf, strlen(buf));
510 die("Failed to write event: %s", strerror(errno)); 1385 if (ret <= 0)
1386 pr_warning("Failed to write event: %s\n",
1387 strerror(errno));
1388 }
1389 free(buf);
1390 return ret;
511} 1391}
512 1392
513static void get_new_event_name(char *buf, size_t len, const char *base, 1393static int get_new_event_name(char *buf, size_t len, const char *base,
514 struct strlist *namelist, bool allow_suffix) 1394 struct strlist *namelist, bool allow_suffix)
515{ 1395{
516 int i, ret; 1396 int i, ret;
517 1397
518 /* Try no suffix */ 1398 /* Try no suffix */
519 ret = e_snprintf(buf, len, "%s", base); 1399 ret = e_snprintf(buf, len, "%s", base);
520 if (ret < 0) 1400 if (ret < 0) {
521 die("snprintf() failed: %s", strerror(-ret)); 1401 pr_debug("snprintf() failed: %s\n", strerror(-ret));
1402 return ret;
1403 }
522 if (!strlist__has_entry(namelist, buf)) 1404 if (!strlist__has_entry(namelist, buf))
523 return; 1405 return 0;
524 1406
525 if (!allow_suffix) { 1407 if (!allow_suffix) {
526 pr_warning("Error: event \"%s\" already exists. " 1408 pr_warning("Error: event \"%s\" already exists. "
527 "(Use -f to force duplicates.)\n", base); 1409 "(Use -f to force duplicates.)\n", base);
528 die("Can't add new event."); 1410 return -EEXIST;
529 } 1411 }
530 1412
531 /* Try to add suffix */ 1413 /* Try to add suffix */
532 for (i = 1; i < MAX_EVENT_INDEX; i++) { 1414 for (i = 1; i < MAX_EVENT_INDEX; i++) {
533 ret = e_snprintf(buf, len, "%s_%d", base, i); 1415 ret = e_snprintf(buf, len, "%s_%d", base, i);
534 if (ret < 0) 1416 if (ret < 0) {
535 die("snprintf() failed: %s", strerror(-ret)); 1417 pr_debug("snprintf() failed: %s\n", strerror(-ret));
1418 return ret;
1419 }
536 if (!strlist__has_entry(namelist, buf)) 1420 if (!strlist__has_entry(namelist, buf))
537 break; 1421 break;
538 } 1422 }
539 if (i == MAX_EVENT_INDEX) 1423 if (i == MAX_EVENT_INDEX) {
540 die("Too many events are on the same function."); 1424 pr_warning("Too many events are on the same function.\n");
1425 ret = -ERANGE;
1426 }
1427
1428 return ret;
541} 1429}
542 1430
543void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 1431static int __add_probe_trace_events(struct perf_probe_event *pev,
544 bool force_add) 1432 struct probe_trace_event *tevs,
1433 int ntevs, bool allow_suffix)
545{ 1434{
546 int i, j, fd; 1435 int i, fd, ret;
547 struct probe_point *pp; 1436 struct probe_trace_event *tev = NULL;
548 char buf[MAX_CMDLEN]; 1437 char buf[64];
549 char event[64]; 1438 const char *event, *group;
550 struct strlist *namelist; 1439 struct strlist *namelist;
551 bool allow_suffix;
552 1440
553 fd = open_kprobe_events(O_RDWR, O_APPEND); 1441 fd = open_kprobe_events(true);
1442 if (fd < 0)
1443 return fd;
554 /* Get current event names */ 1444 /* Get current event names */
555 namelist = get_perf_event_names(fd, false); 1445 namelist = get_probe_trace_event_names(fd, false);
556 1446 if (!namelist) {
557 for (j = 0; j < nr_probes; j++) { 1447 pr_debug("Failed to get current event list.\n");
558 pp = probes + j; 1448 return -EIO;
559 if (!pp->event) 1449 }
560 pp->event = strdup(pp->function); 1450
561 if (!pp->group) 1451 ret = 0;
562 pp->group = strdup(PERFPROBE_GROUP); 1452 printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
563 DIE_IF(!pp->event || !pp->group); 1453 for (i = 0; i < ntevs; i++) {
564 /* If force_add is true, suffix search is allowed */ 1454 tev = &tevs[i];
565 allow_suffix = force_add; 1455 if (pev->event)
566 for (i = 0; i < pp->found; i++) { 1456 event = pev->event;
567 /* Get an unused new event name */ 1457 else
568 get_new_event_name(event, 64, pp->event, namelist, 1458 if (pev->point.function)
569 allow_suffix); 1459 event = pev->point.function;
570 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 1460 else
571 pp->retprobe ? 'r' : 'p', 1461 event = tev->point.symbol;
572 pp->group, event, 1462 if (pev->group)
573 pp->probes[i]); 1463 group = pev->group;
574 write_trace_kprobe_event(fd, buf); 1464 else
575 printf("Added new event:\n"); 1465 group = PERFPROBE_GROUP;
576 /* Get the first parameter (probe-point) */ 1466
577 sscanf(pp->probes[i], "%s", buf); 1467 /* Get an unused new event name */
578 show_perf_probe_event(event, buf, pp); 1468 ret = get_new_event_name(buf, 64, event,
579 /* Add added event name to namelist */ 1469 namelist, allow_suffix);
580 strlist__add(namelist, event); 1470 if (ret < 0)
581 /* 1471 break;
582 * Probes after the first probe which comes from same 1472 event = buf;
583 * user input are always allowed to add suffix, because 1473
584 * there might be several addresses corresponding to 1474 tev->event = strdup(event);
585 * one code line. 1475 tev->group = strdup(group);
586 */ 1476 if (tev->event == NULL || tev->group == NULL) {
587 allow_suffix = true; 1477 ret = -ENOMEM;
1478 break;
588 } 1479 }
1480 ret = write_probe_trace_event(fd, tev);
1481 if (ret < 0)
1482 break;
1483 /* Add added event name to namelist */
1484 strlist__add(namelist, event);
1485
1486 /* Trick here - save current event/group */
1487 event = pev->event;
1488 group = pev->group;
1489 pev->event = tev->event;
1490 pev->group = tev->group;
1491 show_perf_probe_event(pev);
1492 /* Trick here - restore current event/group */
1493 pev->event = (char *)event;
1494 pev->group = (char *)group;
1495
1496 /*
1497 * Probes after the first probe which comes from same
1498 * user input are always allowed to add suffix, because
1499 * there might be several addresses corresponding to
1500 * one code line.
1501 */
1502 allow_suffix = true;
1503 }
1504
1505 if (ret >= 0) {
1506 /* Show how to use the event. */
1507 printf("\nYou can now use it on all perf tools, such as:\n\n");
1508 printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1509 tev->event);
589 } 1510 }
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 1511
594 strlist__delete(namelist); 1512 strlist__delete(namelist);
595 close(fd); 1513 close(fd);
1514 return ret;
596} 1515}
597 1516
598static void __del_trace_kprobe_event(int fd, struct str_node *ent) 1517static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1518 struct probe_trace_event **tevs,
1519 int max_tevs)
1520{
1521 struct symbol *sym;
1522 int ret = 0, i;
1523 struct probe_trace_event *tev;
1524
1525 /* Convert perf_probe_event with debuginfo */
1526 ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
1527 if (ret != 0)
1528 return ret;
1529
1530 /* Allocate trace event buffer */
1531 tev = *tevs = zalloc(sizeof(struct probe_trace_event));
1532 if (tev == NULL)
1533 return -ENOMEM;
1534
1535 /* Copy parameters */
1536 tev->point.symbol = strdup(pev->point.function);
1537 if (tev->point.symbol == NULL) {
1538 ret = -ENOMEM;
1539 goto error;
1540 }
1541 tev->point.offset = pev->point.offset;
1542 tev->point.retprobe = pev->point.retprobe;
1543 tev->nargs = pev->nargs;
1544 if (tev->nargs) {
1545 tev->args = zalloc(sizeof(struct probe_trace_arg)
1546 * tev->nargs);
1547 if (tev->args == NULL) {
1548 ret = -ENOMEM;
1549 goto error;
1550 }
1551 for (i = 0; i < tev->nargs; i++) {
1552 if (pev->args[i].name) {
1553 tev->args[i].name = strdup(pev->args[i].name);
1554 if (tev->args[i].name == NULL) {
1555 ret = -ENOMEM;
1556 goto error;
1557 }
1558 }
1559 tev->args[i].value = strdup(pev->args[i].var);
1560 if (tev->args[i].value == NULL) {
1561 ret = -ENOMEM;
1562 goto error;
1563 }
1564 if (pev->args[i].type) {
1565 tev->args[i].type = strdup(pev->args[i].type);
1566 if (tev->args[i].type == NULL) {
1567 ret = -ENOMEM;
1568 goto error;
1569 }
1570 }
1571 }
1572 }
1573
1574 /* Currently just checking function name from symbol map */
1575 sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
1576 tev->point.symbol, NULL);
1577 if (!sym) {
1578 pr_warning("Kernel symbol \'%s\' not found.\n",
1579 tev->point.symbol);
1580 ret = -ENOENT;
1581 goto error;
1582 }
1583
1584 return 1;
1585error:
1586 clear_probe_trace_event(tev);
1587 free(tev);
1588 *tevs = NULL;
1589 return ret;
1590}
1591
1592struct __event_package {
1593 struct perf_probe_event *pev;
1594 struct probe_trace_event *tevs;
1595 int ntevs;
1596};
1597
1598int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1599 bool force_add, int max_tevs)
1600{
1601 int i, j, ret;
1602 struct __event_package *pkgs;
1603
1604 pkgs = zalloc(sizeof(struct __event_package) * npevs);
1605 if (pkgs == NULL)
1606 return -ENOMEM;
1607
1608 /* Init vmlinux path */
1609 ret = init_vmlinux();
1610 if (ret < 0) {
1611 free(pkgs);
1612 return ret;
1613 }
1614
1615 /* Loop 1: convert all events */
1616 for (i = 0; i < npevs; i++) {
1617 pkgs[i].pev = &pevs[i];
1618 /* Convert with or without debuginfo */
1619 ret = convert_to_probe_trace_events(pkgs[i].pev,
1620 &pkgs[i].tevs, max_tevs);
1621 if (ret < 0)
1622 goto end;
1623 pkgs[i].ntevs = ret;
1624 }
1625
1626 /* Loop 2: add all events */
1627 for (i = 0; i < npevs && ret >= 0; i++)
1628 ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
1629 pkgs[i].ntevs, force_add);
1630end:
1631 /* Loop 3: cleanup and free trace events */
1632 for (i = 0; i < npevs; i++) {
1633 for (j = 0; j < pkgs[i].ntevs; j++)
1634 clear_probe_trace_event(&pkgs[i].tevs[j]);
1635 free(pkgs[i].tevs);
1636 }
1637 free(pkgs);
1638
1639 return ret;
1640}
1641
1642static int __del_trace_probe_event(int fd, struct str_node *ent)
599{ 1643{
600 char *p; 1644 char *p;
601 char buf[128]; 1645 char buf[128];
1646 int ret;
1647
1648 /* Convert from perf-probe event to trace-probe event */
1649 ret = e_snprintf(buf, 128, "-:%s", ent->s);
1650 if (ret < 0)
1651 goto error;
602 1652
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, ':'); 1653 p = strchr(buf + 2, ':');
607 if (!p) 1654 if (!p) {
608 die("Internal error: %s should have ':' but not.", ent->s); 1655 pr_debug("Internal error: %s should have ':' but not.\n",
1656 ent->s);
1657 ret = -ENOTSUP;
1658 goto error;
1659 }
609 *p = '/'; 1660 *p = '/';
610 1661
611 write_trace_kprobe_event(fd, buf); 1662 pr_debug("Writing event: %s\n", buf);
1663 ret = write(fd, buf, strlen(buf));
1664 if (ret < 0)
1665 goto error;
1666
612 printf("Remove event: %s\n", ent->s); 1667 printf("Remove event: %s\n", ent->s);
1668 return 0;
1669error:
1670 pr_warning("Failed to delete event: %s\n", strerror(-ret));
1671 return ret;
613} 1672}
614 1673
615static void del_trace_kprobe_event(int fd, const char *group, 1674static int del_trace_probe_event(int fd, const char *group,
616 const char *event, struct strlist *namelist) 1675 const char *event, struct strlist *namelist)
617{ 1676{
618 char buf[128]; 1677 char buf[128];
619 struct str_node *ent, *n; 1678 struct str_node *ent, *n;
620 int found = 0; 1679 int found = 0, ret = 0;
621 1680
622 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 1681 ret = e_snprintf(buf, 128, "%s:%s", group, event);
623 die("Failed to copy event."); 1682 if (ret < 0) {
1683 pr_err("Failed to copy event.");
1684 return ret;
1685 }
624 1686
625 if (strpbrk(buf, "*?")) { /* Glob-exp */ 1687 if (strpbrk(buf, "*?")) { /* Glob-exp */
626 strlist__for_each_safe(ent, n, namelist) 1688 strlist__for_each_safe(ent, n, namelist)
627 if (strglobmatch(ent->s, buf)) { 1689 if (strglobmatch(ent->s, buf)) {
628 found++; 1690 found++;
629 __del_trace_kprobe_event(fd, ent); 1691 ret = __del_trace_probe_event(fd, ent);
1692 if (ret < 0)
1693 break;
630 strlist__remove(namelist, ent); 1694 strlist__remove(namelist, ent);
631 } 1695 }
632 } else { 1696 } else {
633 ent = strlist__find(namelist, buf); 1697 ent = strlist__find(namelist, buf);
634 if (ent) { 1698 if (ent) {
635 found++; 1699 found++;
636 __del_trace_kprobe_event(fd, ent); 1700 ret = __del_trace_probe_event(fd, ent);
637 strlist__remove(namelist, ent); 1701 if (ret >= 0)
1702 strlist__remove(namelist, ent);
638 } 1703 }
639 } 1704 }
640 if (found == 0) 1705 if (found == 0 && ret >= 0)
641 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); 1706 pr_info("Info: Event \"%s\" does not exist.\n", buf);
1707
1708 return ret;
642} 1709}
643 1710
644void del_trace_kprobe_events(struct strlist *dellist) 1711int del_perf_probe_events(struct strlist *dellist)
645{ 1712{
646 int fd; 1713 int fd, ret = 0;
647 const char *group, *event; 1714 const char *group, *event;
648 char *p, *str; 1715 char *p, *str;
649 struct str_node *ent; 1716 struct str_node *ent;
650 struct strlist *namelist; 1717 struct strlist *namelist;
651 1718
652 fd = open_kprobe_events(O_RDWR, O_APPEND); 1719 fd = open_kprobe_events(true);
1720 if (fd < 0)
1721 return fd;
1722
653 /* Get current event names */ 1723 /* Get current event names */
654 namelist = get_perf_event_names(fd, true); 1724 namelist = get_probe_trace_event_names(fd, true);
1725 if (namelist == NULL)
1726 return -EINVAL;
655 1727
656 strlist__for_each(ent, dellist) { 1728 strlist__for_each(ent, dellist) {
657 str = strdup(ent->s); 1729 str = strdup(ent->s);
658 if (!str) 1730 if (str == NULL) {
659 die("Failed to copy event."); 1731 ret = -ENOMEM;
1732 break;
1733 }
660 pr_debug("Parsing: %s\n", str); 1734 pr_debug("Parsing: %s\n", str);
661 p = strchr(str, ':'); 1735 p = strchr(str, ':');
662 if (p) { 1736 if (p) {
@@ -668,10 +1742,14 @@ void del_trace_kprobe_events(struct strlist *dellist)
668 event = str; 1742 event = str;
669 } 1743 }
670 pr_debug("Group: %s, Event: %s\n", group, event); 1744 pr_debug("Group: %s, Event: %s\n", group, event);
671 del_trace_kprobe_event(fd, group, event, namelist); 1745 ret = del_trace_probe_event(fd, group, event, namelist);
672 free(str); 1746 free(str);
1747 if (ret < 0)
1748 break;
673 } 1749 }
674 strlist__delete(namelist); 1750 strlist__delete(namelist);
675 close(fd); 1751 close(fd);
1752
1753 return ret;
676} 1754}
677 1755
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 7f1d499118c0..5af39243a25b 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -2,19 +2,120 @@
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/* Command string to events */
94extern int parse_perf_probe_command(const char *cmd,
95 struct perf_probe_event *pev);
96
97/* Events to command string */
98extern char *synthesize_perf_probe_command(struct perf_probe_event *pev);
99extern char *synthesize_probe_trace_command(struct probe_trace_event *tev);
100extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf,
101 size_t len);
102
103/* Check the perf_probe_event needs debuginfo */
104extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
105
106/* Release event contents */
107extern void clear_perf_probe_event(struct perf_probe_event *pev);
108
109/* Command string to line-range */
110extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
111
112
113extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
114 bool force_add, int max_probe_points);
115extern int del_perf_probe_events(struct strlist *dellist);
116extern int show_perf_probe_events(void);
117extern int show_line_range(struct line_range *lr);
118
18 119
19/* Maximum index number of event-name postfix */ 120/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024 121#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4b852c0d16a5..32b81f707ff5 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,1401 @@ 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)
118{ 91{
119 Dwarf_Signed cnt, i; 92 struct line_node *ln;
120 Dwarf_Unsigned found = 0; 93
121 char **srcs; 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 wrappers */
120
121/* Find the realpath of the target file. */
122static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
123{
124 Dwarf_Files *files;
125 size_t nfiles, i;
126 const char *src = NULL;
122 int ret; 127 int ret;
123 128
124 if (!fname) 129 if (!fname)
125 return 0; 130 return NULL;
126 131
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 132 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
128 if (ret == DW_DLV_OK) { 133 if (ret != 0)
129 for (i = 0; i < cnt && !found; i++) { 134 return NULL;
130 if (strtailcmp(srcs[i], fname) == 0) 135
131 found = i + 1; 136 for (i = 0; i < nfiles; i++) {
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 137 src = dwarf_filesrc(files, i, NULL, NULL);
133 } 138 if (strtailcmp(src, fname) == 0)
134 for (; i < cnt; i++) 139 break;
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
137 } 140 }
138 if (found) 141 if (i == nfiles)
139 pr_debug("found fno: %d\n", (int)found); 142 return NULL;
140 return found; 143 return src;
141} 144}
142 145
143/* Compare diename and tname */ 146/* Get DW_AT_comp_dir (should be NULL with older gcc) */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname) 147static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
145{ 148{
146 char *name; 149 Dwarf_Attribute attr;
147 int ret; 150 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
148 ret = dwarf_diename(dw_die, &name, &__dw_error); 151 return NULL;
149 DIE_IF(ret == DW_DLV_ERROR); 152 return dwarf_formstring(&attr);
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} 153}
157 154
158/* Check the address is in the subprogram(function). */ 155/* Compare diename and tname */
159static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 156static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
160 Dwarf_Signed *offs)
161{ 157{
162 Dwarf_Addr lopc, hipc; 158 const char *name;
163 int ret; 159 name = dwarf_diename(dw_die);
160 return name ? (strcmp(tname, name) == 0) : false;
161}
164 162
165 /* TODO: check ranges */ 163/* Get type die, but skip qualifiers and typedef */
166 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error); 164static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
167 DIE_IF(ret == DW_DLV_ERROR); 165{
168 if (ret == DW_DLV_NO_ENTRY) 166 Dwarf_Attribute attr;
169 return 0; 167 int tag;
170 ret = dwarf_highpc(sp_die, &hipc, &__dw_error); 168
171 DIE_IF(ret != DW_DLV_OK); 169 do {
172 if (lopc <= addr && addr < hipc) { 170 if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
173 *offs = addr - lopc; 171 dwarf_formref_die(&attr, die_mem) == NULL)
174 return 1; 172 return NULL;
175 } else 173
176 return 0; 174 tag = dwarf_tag(die_mem);
175 vr_die = die_mem;
176 } while (tag == DW_TAG_const_type ||
177 tag == DW_TAG_restrict_type ||
178 tag == DW_TAG_volatile_type ||
179 tag == DW_TAG_shared_type ||
180 tag == DW_TAG_typedef);
181
182 return die_mem;
177} 183}
178 184
179/* Check the die is inlined function */ 185static bool die_is_signed_type(Dwarf_Die *tp_die)
180static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die)
181{ 186{
182 /* TODO: check strictly */ 187 Dwarf_Attribute attr;
183 Dwarf_Bool inl; 188 Dwarf_Word ret;
184 int ret; 189
190 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL ||
191 dwarf_formudata(&attr, &ret) != 0)
192 return false;
185 193
186 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 194 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
187 DIE_IF(ret == DW_DLV_ERROR); 195 ret == DW_ATE_signed_fixed);
188 return inl;
189} 196}
190 197
191/* Get the offset of abstruct_origin */ 198static int die_get_byte_size(Dwarf_Die *tp_die)
192static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die)
193{ 199{
194 Dwarf_Attribute attr; 200 Dwarf_Attribute attr;
195 Dwarf_Off cu_offs; 201 Dwarf_Word ret;
196 int ret;
197 202
198 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 203 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL ||
199 DIE_IF(ret != DW_DLV_OK); 204 dwarf_formudata(&attr, &ret) != 0)
200 ret = dwarf_formref(attr, &cu_offs, &__dw_error); 205 return 0;
201 DIE_IF(ret != DW_DLV_OK); 206
202 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 207 return (int)ret;
203 return cu_offs;
204} 208}
205 209
206/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 210/* Get data_member_location offset */
207static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) 211static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
208{ 212{
209 Dwarf_Attribute attr; 213 Dwarf_Attribute attr;
210 Dwarf_Addr addr; 214 Dwarf_Op *expr;
211 Dwarf_Off offs; 215 size_t nexpr;
212 Dwarf_Ranges *ranges;
213 Dwarf_Signed cnt;
214 int ret; 216 int ret;
215 217
216 /* Try to get entry pc */ 218 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
217 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 219 return -ENOENT;
218 DIE_IF(ret == DW_DLV_ERROR); 220
219 if (ret == DW_DLV_OK) { 221 if (dwarf_formudata(&attr, offs) != 0) {
220 ret = dwarf_formaddr(attr, &addr, &__dw_error); 222 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
221 DIE_IF(ret != DW_DLV_OK); 223 ret = dwarf_getlocation(&attr, &expr, &nexpr);
222 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 224 if (ret < 0 || nexpr == 0)
223 return addr; 225 return -ENOENT;
224 } 226
225 227 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
226 /* Try to get low pc */ 228 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
227 ret = dwarf_lowpc(dw_die, &addr, &__dw_error); 229 expr[0].atom, nexpr);
228 DIE_IF(ret == DW_DLV_ERROR); 230 return -ENOTSUP;
229 if (ret == DW_DLV_OK) 231 }
230 return addr; 232 *offs = (Dwarf_Word)expr[0].number;
231 233 }
232 /* Try to get ranges */ 234 return 0;
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} 235}
244 236
245/* 237/* Return values for die_find callbacks */
246 * Search a Die from Die tree. 238enum {
247 * Note: cur_link->die should be deallocated in this function. 239 DIE_FIND_CB_FOUND = 0, /* End of Search */
248 */ 240 DIE_FIND_CB_CHILD = 1, /* Search only children */
249static int __search_die_tree(struct die_link *cur_link, 241 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
250 int (*die_cb)(struct die_link *, void *), 242 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
251 void *data) 243};
244
245/* Search a child die */
246static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
247 int (*callback)(Dwarf_Die *, void *),
248 void *data, Dwarf_Die *die_mem)
252{ 249{
253 Dwarf_Die new_die; 250 Dwarf_Die child_die;
254 struct die_link new_link;
255 int ret; 251 int ret;
256 252
257 if (!die_cb) 253 ret = dwarf_child(rt_die, die_mem);
258 return 0; 254 if (ret != 0)
255 return NULL;
259 256
260 /* Check current die */ 257 do {
261 while (!(ret = die_cb(cur_link, data))) { 258 ret = callback(die_mem, data);
262 /* Check child die */ 259 if (ret == DIE_FIND_CB_FOUND)
263 ret = dwarf_child(cur_link->die, &new_die, &__dw_error); 260 return die_mem;
264 DIE_IF(ret == DW_DLV_ERROR); 261
265 if (ret == DW_DLV_OK) { 262 if ((ret & DIE_FIND_CB_CHILD) &&
266 new_link.parent = cur_link; 263 die_find_child(die_mem, callback, data, &child_die)) {
267 new_link.die = new_die; 264 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
268 ret = __search_die_tree(&new_link, die_cb, data); 265 return die_mem;
269 if (ret) 266 }
270 break; 267 } while ((ret & DIE_FIND_CB_SIBLING) &&
271 } 268 dwarf_siblingof(die_mem, die_mem) == 0);
272 269
273 /* Move to next sibling */ 270 return NULL;
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 }
282 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
283 return ret;
284} 271}
285 272
286/* Search a die in its children's die tree */ 273struct __addr_die_search_param {
287static int search_die_from_children(Dwarf_Die parent_die, 274 Dwarf_Addr addr;
288 int (*die_cb)(struct die_link *, void *), 275 Dwarf_Die *die_mem;
289 void *data) 276};
277
278static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
290{ 279{
291 struct die_link new_link; 280 struct __addr_die_search_param *ad = data;
292 int ret; 281
282 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
283 dwarf_haspc(fn_die, ad->addr)) {
284 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
285 return DWARF_CB_ABORT;
286 }
287 return DWARF_CB_OK;
288}
293 289
294 new_link.parent = NULL; 290/* Search a real subprogram including this line, */
295 ret = dwarf_child(parent_die, &new_link.die, &__dw_error); 291static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
296 DIE_IF(ret == DW_DLV_ERROR); 292 Dwarf_Die *die_mem)
297 if (ret == DW_DLV_OK) 293{
298 return __search_die_tree(&new_link, die_cb, data); 294 struct __addr_die_search_param ad;
295 ad.addr = addr;
296 ad.die_mem = die_mem;
297 /* dwarf_getscopes can't find subprogram. */
298 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
299 return NULL;
299 else 300 else
300 return 0; 301 return die_mem;
301} 302}
302 303
303/* Find a locdesc corresponding to the address */ 304/* die_find callback for inline function search */
304static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, 305static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
305 Dwarf_Addr addr)
306{ 306{
307 Dwarf_Signed lcnt; 307 Dwarf_Addr *addr = data;
308 Dwarf_Locdesc **llbuf;
309 int ret, i;
310 308
311 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error); 309 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
312 DIE_IF(ret != DW_DLV_OK); 310 dwarf_haspc(die_mem, *addr))
313 ret = DW_DLV_NO_ENTRY; 311 return DIE_FIND_CB_FOUND;
314 for (i = 0; i < lcnt; ++i) { 312
315 if (llbuf[i]->ld_lopc <= addr && 313 return DIE_FIND_CB_CONTINUE;
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 }
329 /* Releasing loop */
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} 314}
337 315
338/* Get decl_file attribute value (file number) */ 316/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
339static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) 317static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
318 Dwarf_Die *die_mem)
340{ 319{
341 Dwarf_Attribute attr; 320 return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
342 Dwarf_Unsigned fno; 321}
343 int ret; 322
323static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
324{
325 const char *name = data;
326 int tag;
344 327
345 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); 328 tag = dwarf_tag(die_mem);
346 DIE_IF(ret != DW_DLV_OK); 329 if ((tag == DW_TAG_formal_parameter ||
347 dwarf_formudata(attr, &fno, &__dw_error); 330 tag == DW_TAG_variable) &&
348 DIE_IF(ret != DW_DLV_OK); 331 die_compare_name(die_mem, name))
349 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 332 return DIE_FIND_CB_FOUND;
350 return fno; 333
334 return DIE_FIND_CB_CONTINUE;
351} 335}
352 336
353/* Get decl_line attribute value (line number) */ 337/* Find a variable called 'name' */
354static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) 338static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
339 Dwarf_Die *die_mem)
355{ 340{
356 Dwarf_Attribute attr; 341 return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
357 Dwarf_Unsigned lno; 342 die_mem);
358 int ret; 343}
359 344
360 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); 345static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
361 DIE_IF(ret != DW_DLV_OK); 346{
362 dwarf_formudata(attr, &lno, &__dw_error); 347 const char *name = data;
363 DIE_IF(ret != DW_DLV_OK); 348
364 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 349 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
365 return lno; 350 die_compare_name(die_mem, name))
351 return DIE_FIND_CB_FOUND;
352
353 return DIE_FIND_CB_SIBLING;
354}
355
356/* Find a member called 'name' */
357static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
358 Dwarf_Die *die_mem)
359{
360 return die_find_child(st_die, __die_find_member_cb, (void *)name,
361 die_mem);
366} 362}
367 363
368/* 364/*
369 * Probe finder related functions 365 * Probe finder related functions
370 */ 366 */
371 367
368static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
369{
370 struct probe_trace_arg_ref *ref;
371 ref = zalloc(sizeof(struct probe_trace_arg_ref));
372 if (ref != NULL)
373 ref->offset = offs;
374 return ref;
375}
376
372/* Show a location */ 377/* Show a location */
373static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) 378static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
374{ 379{
375 Dwarf_Small op; 380 Dwarf_Attribute attr;
376 Dwarf_Unsigned regn; 381 Dwarf_Op *op;
377 Dwarf_Signed offs; 382 size_t nops;
378 int deref = 0, ret; 383 unsigned int regn;
384 Dwarf_Word offs = 0;
385 bool ref = false;
379 const char *regs; 386 const char *regs;
387 struct probe_trace_arg *tvar = pf->tvar;
388 int ret;
380 389
381 op = loc->lr_atom; 390 /* TODO: handle more than 1 exprs */
391 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
392 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
393 nops == 0) {
394 /* TODO: Support const_value */
395 pr_err("Failed to find the location of %s at this address.\n"
396 " Perhaps, it has been optimized out.\n", pf->pvar->var);
397 return -ENOENT;
398 }
399
400 if (op->atom == DW_OP_addr) {
401 /* Static variables on memory (not stack), make @varname */
402 ret = strlen(dwarf_diename(vr_die));
403 tvar->value = zalloc(ret + 2);
404 if (tvar->value == NULL)
405 return -ENOMEM;
406 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
407 tvar->ref = alloc_trace_arg_ref((long)offs);
408 if (tvar->ref == NULL)
409 return -ENOMEM;
410 return 0;
411 }
382 412
383 /* If this is based on frame buffer, set the offset */ 413 /* If this is based on frame buffer, set the offset */
384 if (op == DW_OP_fbreg) { 414 if (op->atom == DW_OP_fbreg) {
385 deref = 1; 415 if (pf->fb_ops == NULL) {
386 offs = (Dwarf_Signed)loc->lr_number; 416 pr_warning("The attribute of frame base is not "
387 op = pf->fbloc.ld_s[0].lr_atom; 417 "supported.\n");
388 loc = &pf->fbloc.ld_s[0]; 418 return -ENOTSUP;
389 } else 419 }
390 offs = 0; 420 ref = true;
391 421 offs = op->number;
392 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 422 op = &pf->fb_ops[0];
393 regn = op - DW_OP_breg0; 423 }
394 offs += (Dwarf_Signed)loc->lr_number; 424
395 deref = 1; 425 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
396 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 426 regn = op->atom - DW_OP_breg0;
397 regn = op - DW_OP_reg0; 427 offs += op->number;
398 } else if (op == DW_OP_bregx) { 428 ref = true;
399 regn = loc->lr_number; 429 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
400 offs += (Dwarf_Signed)loc->lr_number2; 430 regn = op->atom - DW_OP_reg0;
401 deref = 1; 431 } else if (op->atom == DW_OP_bregx) {
402 } else if (op == DW_OP_regx) { 432 regn = op->number;
403 regn = loc->lr_number; 433 offs += op->number2;
404 } else 434 ref = true;
405 die("Dwarf_OP %d is not supported.\n", op); 435 } else if (op->atom == DW_OP_regx) {
436 regn = op->number;
437 } else {
438 pr_warning("DW_OP %x is not supported.\n", op->atom);
439 return -ENOTSUP;
440 }
406 441
407 regs = get_arch_regstr(regn); 442 regs = get_arch_regstr(regn);
408 if (!regs) 443 if (!regs) {
409 die("%lld exceeds max register number.\n", regn); 444 pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);
445 return -ERANGE;
446 }
410 447
411 if (deref) 448 tvar->value = strdup(regs);
412 ret = snprintf(pf->buf, pf->len, 449 if (tvar->value == NULL)
413 " %s=%+lld(%s)", pf->var, offs, regs); 450 return -ENOMEM;
414 else 451
415 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 452 if (ref) {
416 DIE_IF(ret < 0); 453 tvar->ref = alloc_trace_arg_ref((long)offs);
417 DIE_IF(ret >= pf->len); 454 if (tvar->ref == NULL)
455 return -ENOMEM;
456 }
457 return 0;
418} 458}
419 459
420/* Show a variables in kprobe event format */ 460static int convert_variable_type(Dwarf_Die *vr_die,
421static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 461 struct probe_trace_arg *tvar,
462 const char *cast)
422{ 463{
423 Dwarf_Attribute attr; 464 struct probe_trace_arg_ref **ref_ptr = &tvar->ref;
424 Dwarf_Locdesc ld; 465 Dwarf_Die type;
466 char buf[16];
425 int ret; 467 int ret;
426 468
427 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 469 /* TODO: check all types */
428 if (ret != DW_DLV_OK) 470 if (cast && strcmp(cast, "string") != 0) {
429 goto error; 471 /* Non string type is OK */
430 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 472 tvar->type = strdup(cast);
431 if (ret != DW_DLV_OK) 473 return (tvar->type == NULL) ? -ENOMEM : 0;
432 goto error; 474 }
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
444static int variable_callback(struct die_link *dlink, void *data)
445{
446 struct probe_finder *pf = (struct probe_finder *)data;
447 Dwarf_Half tag;
448 int ret;
449 475
450 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 476 if (die_get_real_type(vr_die, &type) == NULL) {
451 DIE_IF(ret == DW_DLV_ERROR); 477 pr_warning("Failed to get a type information of %s.\n",
452 if ((tag == DW_TAG_formal_parameter || 478 dwarf_diename(vr_die));
453 tag == DW_TAG_variable) && 479 return -ENOENT;
454 (die_compare_name(dlink->die, pf->var) == 0)) { 480 }
455 show_variable(dlink->die, pf); 481
456 return 1; 482 pr_debug("%s type is %s.\n",
483 dwarf_diename(vr_die), dwarf_diename(&type));
484
485 if (cast && strcmp(cast, "string") == 0) { /* String type */
486 ret = dwarf_tag(&type);
487 if (ret != DW_TAG_pointer_type &&
488 ret != DW_TAG_array_type) {
489 pr_warning("Failed to cast into string: "
490 "%s(%s) is not a pointer nor array.",
491 dwarf_diename(vr_die), dwarf_diename(&type));
492 return -EINVAL;
493 }
494 if (ret == DW_TAG_pointer_type) {
495 if (die_get_real_type(&type, &type) == NULL) {
496 pr_warning("Failed to get a type information.");
497 return -ENOENT;
498 }
499 while (*ref_ptr)
500 ref_ptr = &(*ref_ptr)->next;
501 /* Add new reference with offset +0 */
502 *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref));
503 if (*ref_ptr == NULL) {
504 pr_warning("Out of memory error\n");
505 return -ENOMEM;
506 }
507 }
508 if (!die_compare_name(&type, "char") &&
509 !die_compare_name(&type, "unsigned char")) {
510 pr_warning("Failed to cast into string: "
511 "%s is not (unsigned) char *.",
512 dwarf_diename(vr_die));
513 return -EINVAL;
514 }
515 tvar->type = strdup(cast);
516 return (tvar->type == NULL) ? -ENOMEM : 0;
517 }
518
519 ret = die_get_byte_size(&type) * 8;
520 if (ret) {
521 /* Check the bitwidth */
522 if (ret > MAX_BASIC_TYPE_BITS) {
523 pr_info("%s exceeds max-bitwidth."
524 " Cut down to %d bits.\n",
525 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
526 ret = MAX_BASIC_TYPE_BITS;
527 }
528
529 ret = snprintf(buf, 16, "%c%d",
530 die_is_signed_type(&type) ? 's' : 'u', ret);
531 if (ret < 0 || ret >= 16) {
532 if (ret >= 16)
533 ret = -E2BIG;
534 pr_warning("Failed to convert variable type: %s\n",
535 strerror(-ret));
536 return ret;
537 }
538 tvar->type = strdup(buf);
539 if (tvar->type == NULL)
540 return -ENOMEM;
457 } 541 }
458 /* TODO: Support struct members and arrays */
459 return 0; 542 return 0;
460} 543}
461 544
462/* Find a variable in a subprogram die */ 545static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
463static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 546 struct perf_probe_arg_field *field,
547 struct probe_trace_arg_ref **ref_ptr,
548 Dwarf_Die *die_mem)
464{ 549{
465 int ret; 550 struct probe_trace_arg_ref *ref = *ref_ptr;
551 Dwarf_Die type;
552 Dwarf_Word offs;
553 int ret, tag;
554
555 pr_debug("converting %s in %s\n", field->name, varname);
556 if (die_get_real_type(vr_die, &type) == NULL) {
557 pr_warning("Failed to get the type of %s.\n", varname);
558 return -ENOENT;
559 }
560 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
561 tag = dwarf_tag(&type);
562
563 if (field->name[0] == '[' &&
564 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
565 if (field->next)
566 /* Save original type for next field */
567 memcpy(die_mem, &type, sizeof(*die_mem));
568 /* Get the type of this array */
569 if (die_get_real_type(&type, &type) == NULL) {
570 pr_warning("Failed to get the type of %s.\n", varname);
571 return -ENOENT;
572 }
573 pr_debug2("Array real type: (%x)\n",
574 (unsigned)dwarf_dieoffset(&type));
575 if (tag == DW_TAG_pointer_type) {
576 ref = zalloc(sizeof(struct probe_trace_arg_ref));
577 if (ref == NULL)
578 return -ENOMEM;
579 if (*ref_ptr)
580 (*ref_ptr)->next = ref;
581 else
582 *ref_ptr = ref;
583 }
584 ref->offset += die_get_byte_size(&type) * field->index;
585 if (!field->next)
586 /* Save vr_die for converting types */
587 memcpy(die_mem, vr_die, sizeof(*die_mem));
588 goto next;
589 } else if (tag == DW_TAG_pointer_type) {
590 /* Check the pointer and dereference */
591 if (!field->ref) {
592 pr_err("Semantic error: %s must be referred by '->'\n",
593 field->name);
594 return -EINVAL;
595 }
596 /* Get the type pointed by this pointer */
597 if (die_get_real_type(&type, &type) == NULL) {
598 pr_warning("Failed to get the type of %s.\n", varname);
599 return -ENOENT;
600 }
601 /* Verify it is a data structure */
602 if (dwarf_tag(&type) != DW_TAG_structure_type) {
603 pr_warning("%s is not a data structure.\n", varname);
604 return -EINVAL;
605 }
466 606
467 if (!is_c_varname(pf->var)) { 607 ref = zalloc(sizeof(struct probe_trace_arg_ref));
468 /* Output raw parameters */ 608 if (ref == NULL)
469 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 609 return -ENOMEM;
470 DIE_IF(ret < 0); 610 if (*ref_ptr)
471 DIE_IF(ret >= pf->len); 611 (*ref_ptr)->next = ref;
472 return ; 612 else
613 *ref_ptr = ref;
614 } else {
615 /* Verify it is a data structure */
616 if (tag != DW_TAG_structure_type) {
617 pr_warning("%s is not a data structure.\n", varname);
618 return -EINVAL;
619 }
620 if (field->name[0] == '[') {
621 pr_err("Semantic error: %s is not a pointor nor array.",
622 varname);
623 return -EINVAL;
624 }
625 if (field->ref) {
626 pr_err("Semantic error: %s must be referred by '.'\n",
627 field->name);
628 return -EINVAL;
629 }
630 if (!ref) {
631 pr_warning("Structure on a register is not "
632 "supported yet.\n");
633 return -ENOTSUP;
634 }
473 } 635 }
474 636
475 pr_debug("Searching '%s' variable in context.\n", pf->var); 637 if (die_find_member(&type, field->name, die_mem) == NULL) {
476 /* Search child die for local variables and parameters. */ 638 pr_warning("%s(tyep:%s) has no member %s.\n", varname,
477 ret = search_die_from_children(sp_die, variable_callback, pf); 639 dwarf_diename(&type), field->name);
478 if (!ret) 640 return -EINVAL;
479 die("Failed to find '%s' in this function.\n", pf->var); 641 }
642
643 /* Get the offset of the field */
644 ret = die_get_data_member_location(die_mem, &offs);
645 if (ret < 0) {
646 pr_warning("Failed to get the offset of %s.\n", field->name);
647 return ret;
648 }
649 ref->offset += (long)offs;
650
651next:
652 /* Converting next field */
653 if (field->next)
654 return convert_variable_fields(die_mem, field->name,
655 field->next, &ref, die_mem);
656 else
657 return 0;
480} 658}
481 659
482/* Get a frame base on the address */ 660/* Show a variables in kprobe event format */
483static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf) 661static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
484{ 662{
485 Dwarf_Attribute attr; 663 Dwarf_Die die_mem;
486 int ret; 664 int ret;
487 665
488 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error); 666 pr_debug("Converting variable %s into trace event.\n",
489 DIE_IF(ret != DW_DLV_OK); 667 dwarf_diename(vr_die));
490 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base)); 668
491 DIE_IF(ret != DW_DLV_OK); 669 ret = convert_variable_location(vr_die, pf);
492 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 670 if (ret == 0 && pf->pvar->field) {
671 ret = convert_variable_fields(vr_die, pf->pvar->var,
672 pf->pvar->field, &pf->tvar->ref,
673 &die_mem);
674 vr_die = &die_mem;
675 }
676 if (ret == 0)
677 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
678 /* *expr will be cached in libdw. Don't free it. */
679 return ret;
493} 680}
494 681
495static void free_current_frame_base(struct probe_finder *pf) 682/* Find a variable in a subprogram die */
683static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
496{ 684{
497 free(pf->fbloc.ld_s); 685 Dwarf_Die vr_die, *scopes;
498 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc)); 686 char buf[32], *ptr;
687 int ret, nscopes;
688
689 if (!is_c_varname(pf->pvar->var)) {
690 /* Copy raw parameters */
691 pf->tvar->value = strdup(pf->pvar->var);
692 if (pf->tvar->value == NULL)
693 return -ENOMEM;
694 if (pf->pvar->type) {
695 pf->tvar->type = strdup(pf->pvar->type);
696 if (pf->tvar->type == NULL)
697 return -ENOMEM;
698 }
699 if (pf->pvar->name) {
700 pf->tvar->name = strdup(pf->pvar->name);
701 if (pf->tvar->name == NULL)
702 return -ENOMEM;
703 } else
704 pf->tvar->name = NULL;
705 return 0;
706 }
707
708 if (pf->pvar->name)
709 pf->tvar->name = strdup(pf->pvar->name);
710 else {
711 ret = synthesize_perf_probe_arg(pf->pvar, buf, 32);
712 if (ret < 0)
713 return ret;
714 ptr = strchr(buf, ':'); /* Change type separator to _ */
715 if (ptr)
716 *ptr = '_';
717 pf->tvar->name = strdup(buf);
718 }
719 if (pf->tvar->name == NULL)
720 return -ENOMEM;
721
722 pr_debug("Searching '%s' variable in context.\n",
723 pf->pvar->var);
724 /* Search child die for local variables and parameters. */
725 if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
726 ret = convert_variable(&vr_die, pf);
727 else {
728 /* Search upper class */
729 nscopes = dwarf_getscopes_die(sp_die, &scopes);
730 if (nscopes > 0) {
731 ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
732 0, NULL, 0, 0, &vr_die);
733 if (ret >= 0)
734 ret = convert_variable(&vr_die, pf);
735 else
736 ret = -ENOENT;
737 free(scopes);
738 } else
739 ret = -ENOENT;
740 }
741 if (ret < 0)
742 pr_warning("Failed to find '%s' in this function.\n",
743 pf->pvar->var);
744 return ret;
499} 745}
500 746
501/* Show a probe point to output buffer */ 747/* Show a probe point to output buffer */
502static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, 748static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
503 struct probe_finder *pf) 749{
504{ 750 struct probe_trace_event *tev;
505 struct probe_point *pp = pf->pp; 751 Dwarf_Addr eaddr;
506 char *name; 752 Dwarf_Die die_mem;
507 char tmp[MAX_PROBE_BUFFER]; 753 const char *name;
508 int ret, i, len; 754 int ret, i;
509 755 Dwarf_Attribute fb_attr;
510 /* Output name of probe point */ 756 size_t nops;
511 ret = dwarf_diename(sp_die, &name, &__dw_error); 757
512 DIE_IF(ret == DW_DLV_ERROR); 758 if (pf->ntevs == pf->max_tevs) {
513 if (ret == DW_DLV_OK) { 759 pr_warning("Too many( > %d) probe point found.\n",
514 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 760 pf->max_tevs);
515 (unsigned int)offs); 761 return -ERANGE;
516 /* Copy the function name if possible */ 762 }
517 if (!pp->function) { 763 tev = &pf->tevs[pf->ntevs++];
518 pp->function = strdup(name); 764
519 pp->offset = offs; 765 /* If no real subprogram, find a real one */
520 } 766 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
521 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING); 767 sp_die = die_find_real_subprogram(&pf->cu_die,
522 } else { 768 pf->addr, &die_mem);
769 if (!sp_die) {
770 pr_warning("Failed to find probe point in any "
771 "functions.\n");
772 return -ENOENT;
773 }
774 }
775
776 /* Copy the name of probe point */
777 name = dwarf_diename(sp_die);
778 if (name) {
779 if (dwarf_entrypc(sp_die, &eaddr) != 0) {
780 pr_warning("Failed to get entry pc of %s\n",
781 dwarf_diename(sp_die));
782 return -ENOENT;
783 }
784 tev->point.symbol = strdup(name);
785 if (tev->point.symbol == NULL)
786 return -ENOMEM;
787 tev->point.offset = (unsigned long)(pf->addr - eaddr);
788 } else
523 /* This function has no name. */ 789 /* This function has no name. */
524 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 790 tev->point.offset = (unsigned long)pf->addr;
525 if (!pp->function) { 791
526 /* TODO: Use _stext */ 792 /* Return probe must be on the head of a subprogram */
527 pp->function = strdup(""); 793 if (pf->pev->point.retprobe) {
528 pp->offset = (int)pf->addr; 794 if (tev->point.offset != 0) {
795 pr_warning("Return probe must be on the head of"
796 " a real function\n");
797 return -EINVAL;
529 } 798 }
799 tev->point.retprobe = true;
800 }
801
802 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
803 tev->point.offset);
804
805 /* Get the frame base attribute/ops */
806 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
807 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
808 if (ret <= 0 || nops == 0) {
809 pf->fb_ops = NULL;
810#if _ELFUTILS_PREREQ(0, 142)
811 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
812 pf->cfi != NULL) {
813 Dwarf_Frame *frame;
814 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
815 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
816 pr_warning("Failed to get CFA on 0x%jx\n",
817 (uintmax_t)pf->addr);
818 return -ENOENT;
819 }
820#endif
530 } 821 }
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 822
536 /* Find each argument */ 823 /* Find each argument */
537 get_current_frame_base(sp_die, pf); 824 tev->nargs = pf->pev->nargs;
538 for (i = 0; i < pp->nr_args; i++) { 825 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
539 pf->var = pp->args[i]; 826 if (tev->args == NULL)
540 pf->buf = &tmp[len]; 827 return -ENOMEM;
541 pf->len = MAX_PROBE_BUFFER - len; 828 for (i = 0; i < pf->pev->nargs; i++) {
542 find_variable(sp_die, pf); 829 pf->pvar = &pf->pev->args[i];
543 len += strlen(pf->buf); 830 pf->tvar = &tev->args[i];
831 ret = find_variable(sp_die, pf);
832 if (ret != 0)
833 return ret;
544 } 834 }
545 free_current_frame_base(pf);
546 835
547 pp->probes[pp->found] = strdup(tmp); 836 /* *pf->fb_ops will be cached in libdw. Don't free it. */
548 pp->found++; 837 pf->fb_ops = NULL;
838 return 0;
549} 839}
550 840
551static int probeaddr_callback(struct die_link *dlink, void *data) 841/* Find probe point from its line number */
842static int find_probe_point_by_line(struct probe_finder *pf)
552{ 843{
553 struct probe_finder *pf = (struct probe_finder *)data; 844 Dwarf_Lines *lines;
554 Dwarf_Half tag; 845 Dwarf_Line *line;
555 Dwarf_Signed offs; 846 size_t nlines, i;
556 int ret; 847 Dwarf_Addr addr;
848 int lineno;
849 int ret = 0;
557 850
558 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 851 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
559 DIE_IF(ret == DW_DLV_ERROR); 852 pr_warning("No source lines found in this CU.\n");
560 /* Check the address is in this subprogram */ 853 return -ENOENT;
561 if (tag == DW_TAG_subprogram &&
562 die_within_subprogram(dlink->die, pf->addr, &offs)) {
563 show_probepoint(dlink->die, offs, pf);
564 return 1;
565 } 854 }
566 return 0; 855
856 for (i = 0; i < nlines && ret == 0; i++) {
857 line = dwarf_onesrcline(lines, i);
858 if (dwarf_lineno(line, &lineno) != 0 ||
859 lineno != pf->lno)
860 continue;
861
862 /* TODO: Get fileno from line, but how? */
863 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
864 continue;
865
866 if (dwarf_lineaddr(line, &addr) != 0) {
867 pr_warning("Failed to get the address of the line.\n");
868 return -ENOENT;
869 }
870 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
871 (int)i, lineno, (uintmax_t)addr);
872 pf->addr = addr;
873
874 ret = convert_probe_point(NULL, pf);
875 /* Continuing, because target line might be inlined. */
876 }
877 return ret;
567} 878}
568 879
569/* Find probe point from its line number */ 880/* Find lines which match lazy pattern */
570static void find_by_line(struct probe_finder *pf) 881static int find_lazy_match_lines(struct list_head *head,
882 const char *fname, const char *pat)
571{ 883{
572 Dwarf_Signed cnt, i, clm; 884 char *fbuf, *p1, *p2;
573 Dwarf_Line *lines; 885 int fd, line, nlines = -1;
574 Dwarf_Unsigned lineno = 0; 886 struct stat st;
887
888 fd = open(fname, O_RDONLY);
889 if (fd < 0) {
890 pr_warning("Failed to open %s: %s\n", fname, strerror(-fd));
891 return -errno;
892 }
893
894 if (fstat(fd, &st) < 0) {
895 pr_warning("Failed to get the size of %s: %s\n",
896 fname, strerror(errno));
897 nlines = -errno;
898 goto out_close;
899 }
900
901 nlines = -ENOMEM;
902 fbuf = malloc(st.st_size + 2);
903 if (fbuf == NULL)
904 goto out_close;
905 if (read(fd, fbuf, st.st_size) < 0) {
906 pr_warning("Failed to read %s: %s\n", fname, strerror(errno));
907 nlines = -errno;
908 goto out_free_fbuf;
909 }
910 fbuf[st.st_size] = '\n'; /* Dummy line */
911 fbuf[st.st_size + 1] = '\0';
912 p1 = fbuf;
913 line = 1;
914 nlines = 0;
915 while ((p2 = strchr(p1, '\n')) != NULL) {
916 *p2 = '\0';
917 if (strlazymatch(p1, pat)) {
918 line_list__add_line(head, line);
919 nlines++;
920 }
921 line++;
922 p1 = p2 + 1;
923 }
924out_free_fbuf:
925 free(fbuf);
926out_close:
927 close(fd);
928 return nlines;
929}
930
931/* Find probe points from lazy pattern */
932static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
933{
934 Dwarf_Lines *lines;
935 Dwarf_Line *line;
936 size_t nlines, i;
575 Dwarf_Addr addr; 937 Dwarf_Addr addr;
576 Dwarf_Unsigned fno; 938 Dwarf_Die die_mem;
577 int ret; 939 int lineno;
940 int ret = 0;
941
942 if (list_empty(&pf->lcache)) {
943 /* Matching lazy line pattern */
944 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
945 pf->pev->point.lazy_line);
946 if (ret == 0) {
947 pr_debug("No matched lines found in %s.\n", pf->fname);
948 return 0;
949 } else if (ret < 0)
950 return ret;
951 }
578 952
579 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 953 if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) {
580 DIE_IF(ret != DW_DLV_OK); 954 pr_warning("No source lines found in this CU.\n");
955 return -ENOENT;
956 }
581 957
582 for (i = 0; i < cnt; i++) { 958 for (i = 0; i < nlines && ret >= 0; i++) {
583 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 959 line = dwarf_onesrcline(lines, i);
584 DIE_IF(ret != DW_DLV_OK); 960
585 if (fno != pf->fno) 961 if (dwarf_lineno(line, &lineno) != 0 ||
962 !line_list__has_line(&pf->lcache, lineno))
586 continue; 963 continue;
587 964
588 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 965 /* TODO: Get fileno from line, but how? */
589 DIE_IF(ret != DW_DLV_OK); 966 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
590 if (lineno != pf->lno)
591 continue; 967 continue;
592 968
593 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 969 if (dwarf_lineaddr(line, &addr) != 0) {
594 DIE_IF(ret != DW_DLV_OK); 970 pr_debug("Failed to get the address of line %d.\n",
971 lineno);
972 continue;
973 }
974 if (sp_die) {
975 /* Address filtering 1: does sp_die include addr? */
976 if (!dwarf_haspc(sp_die, addr))
977 continue;
978 /* Address filtering 2: No child include addr? */
979 if (die_find_inlinefunc(sp_die, addr, &die_mem))
980 continue;
981 }
595 982
596 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 983 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
597 DIE_IF(ret != DW_DLV_OK); 984 (int)i, lineno, (unsigned long long)addr);
598 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599 (int)i, (unsigned)lineno, (int)clm, addr);
600 pf->addr = addr; 985 pf->addr = addr;
601 /* Search a real subprogram including this line, */ 986
602 ret = search_die_from_children(pf->cu_die, 987 ret = convert_probe_point(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. */ 988 /* Continuing, because target line might be inlined. */
607 } 989 }
608 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 990 /* TODO: deallocate lines, but how? */
991 return ret;
609} 992}
610 993
611/* Search function from function name */ 994/* Callback parameter with return value */
612static int probefunc_callback(struct die_link *dlink, void *data) 995struct dwarf_callback_param {
996 void *data;
997 int retval;
998};
999
1000static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
613{ 1001{
614 struct probe_finder *pf = (struct probe_finder *)data; 1002 struct dwarf_callback_param *param = data;
615 struct probe_point *pp = pf->pp; 1003 struct probe_finder *pf = param->data;
616 struct die_link *lk; 1004 struct perf_probe_point *pp = &pf->pev->point;
617 Dwarf_Signed offs; 1005 Dwarf_Addr addr;
618 Dwarf_Half tag;
619 int ret;
620 1006
621 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 1007 if (pp->lazy_line)
622 DIE_IF(ret == DW_DLV_ERROR); 1008 param->retval = find_probe_point_lazy(in_die, pf);
623 if (tag == DW_TAG_subprogram) { 1009 else {
624 if (die_compare_name(dlink->die, pp->function) == 0) { 1010 /* Get probe address */
625 if (pp->line) { /* Function relative line */ 1011 if (dwarf_entrypc(in_die, &addr) != 0) {
626 pf->fno = die_get_decl_file(dlink->die); 1012 pr_warning("Failed to get entry pc of %s.\n",
627 pf->lno = die_get_decl_line(dlink->die) 1013 dwarf_diename(in_die));
628 + pp->line; 1014 param->retval = -ENOENT;
629 find_by_line(pf); 1015 return DWARF_CB_ABORT;
630 return 1; 1016 }
631 } 1017 pf->addr = addr;
632 if (die_inlined_subprogram(dlink->die)) { 1018 pf->addr += pp->offset;
633 /* Inlined function, save it. */ 1019 pr_debug("found inline addr: 0x%jx\n",
634 ret = dwarf_die_CU_offset(dlink->die, 1020 (uintmax_t)pf->addr);
635 &pf->inl_offs, 1021
636 &__dw_error); 1022 param->retval = convert_probe_point(in_die, pf);
637 DIE_IF(ret != DW_DLV_OK); 1023 if (param->retval < 0)
638 pr_debug("inline definition offset %lld\n", 1024 return DWARF_CB_ABORT;
639 pf->inl_offs); 1025 }
640 return 0; /* Continue to search */ 1026
1027 return DWARF_CB_OK;
1028}
1029
1030/* Search function from function name */
1031static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1032{
1033 struct dwarf_callback_param *param = data;
1034 struct probe_finder *pf = param->data;
1035 struct perf_probe_point *pp = &pf->pev->point;
1036
1037 /* Check tag and diename */
1038 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
1039 !die_compare_name(sp_die, pp->function))
1040 return DWARF_CB_OK;
1041
1042 pf->fname = dwarf_decl_file(sp_die);
1043 if (pp->line) { /* Function relative line */
1044 dwarf_decl_line(sp_die, &pf->lno);
1045 pf->lno += pp->line;
1046 param->retval = find_probe_point_by_line(pf);
1047 } else if (!dwarf_func_inline(sp_die)) {
1048 /* Real function */
1049 if (pp->lazy_line)
1050 param->retval = find_probe_point_lazy(sp_die, pf);
1051 else {
1052 if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
1053 pr_warning("Failed to get entry pc of %s.\n",
1054 dwarf_diename(sp_die));
1055 param->retval = -ENOENT;
1056 return DWARF_CB_ABORT;
641 } 1057 }
642 /* Get probe address */
643 pf->addr = die_get_entrypc(dlink->die);
644 pf->addr += pp->offset; 1058 pf->addr += pp->offset;
645 /* TODO: Check the address in this function */ 1059 /* TODO: Check the address in this function */
646 show_probepoint(dlink->die, pp->offset, pf); 1060 param->retval = convert_probe_point(sp_die, pf);
647 return 1; /* Exit; no same symbol in this CU. */
648 } 1061 }
649 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) { 1062 } else {
650 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) { 1063 struct dwarf_callback_param _param = {.data = (void *)pf,
651 /* Get probe address */ 1064 .retval = 0};
652 pf->addr = die_get_entrypc(dlink->die); 1065 /* Inlined function: search instances */
653 pf->addr += pp->offset; 1066 dwarf_func_inline_instances(sp_die, probe_point_inline_cb,
654 pr_debug("found inline addr: 0x%llx\n", pf->addr); 1067 &_param);
655 /* Inlined function. Get a real subprogram */ 1068 param->retval = _param.retval;
656 for (lk = dlink->parent; lk != NULL; lk = lk->parent) { 1069 }
657 tag = 0; 1070
658 dwarf_tag(lk->die, &tag, &__dw_error); 1071 return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
659 DIE_IF(ret == DW_DLV_ERROR); 1072}
660 if (tag == DW_TAG_subprogram && 1073
661 !die_inlined_subprogram(lk->die)) 1074static int find_probe_point_by_func(struct probe_finder *pf)
662 goto found; 1075{
1076 struct dwarf_callback_param _param = {.data = (void *)pf,
1077 .retval = 0};
1078 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
1079 return _param.retval;
1080}
1081
1082/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1083int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1084 struct probe_trace_event **tevs, int max_tevs)
1085{
1086 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
1087 struct perf_probe_point *pp = &pev->point;
1088 Dwarf_Off off, noff;
1089 size_t cuhl;
1090 Dwarf_Die *diep;
1091 Dwarf *dbg;
1092 int ret = 0;
1093
1094 pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1095 if (pf.tevs == NULL)
1096 return -ENOMEM;
1097 *tevs = pf.tevs;
1098 pf.ntevs = 0;
1099
1100 dbg = dwarf_begin(fd, DWARF_C_READ);
1101 if (!dbg) {
1102 pr_warning("No dwarf info found in the vmlinux - "
1103 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1104 free(pf.tevs);
1105 *tevs = NULL;
1106 return -EBADF;
1107 }
1108
1109#if _ELFUTILS_PREREQ(0, 142)
1110 /* Get the call frame information from this dwarf */
1111 pf.cfi = dwarf_getcfi(dbg);
1112#endif
1113
1114 off = 0;
1115 line_list__init(&pf.lcache);
1116 /* Loop on CUs (Compilation Unit) */
1117 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
1118 ret >= 0) {
1119 /* Get the DIE(Debugging Information Entry) of this CU */
1120 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
1121 if (!diep)
1122 continue;
1123
1124 /* Check if target file is included. */
1125 if (pp->file)
1126 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
1127 else
1128 pf.fname = NULL;
1129
1130 if (!pp->file || pf.fname) {
1131 if (pp->function)
1132 ret = find_probe_point_by_func(&pf);
1133 else if (pp->lazy_line)
1134 ret = find_probe_point_lazy(NULL, &pf);
1135 else {
1136 pf.lno = pp->line;
1137 ret = find_probe_point_by_line(&pf);
663 } 1138 }
664 die("Failed to find real subprogram.\n"); 1139 }
1140 off = noff;
1141 }
1142 line_list__free(&pf.lcache);
1143 dwarf_end(dbg);
1144
1145 return (ret < 0) ? ret : pf.ntevs;
1146}
1147
1148/* Reverse search */
1149int find_perf_probe_point(int fd, unsigned long addr,
1150 struct perf_probe_point *ppt)
1151{
1152 Dwarf_Die cudie, spdie, indie;
1153 Dwarf *dbg;
1154 Dwarf_Line *line;
1155 Dwarf_Addr laddr, eaddr;
1156 const char *tmp;
1157 int lineno, ret = 0;
1158 bool found = false;
1159
1160 dbg = dwarf_begin(fd, DWARF_C_READ);
1161 if (!dbg)
1162 return -EBADF;
1163
1164 /* Find cu die */
1165 if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
1166 ret = -EINVAL;
1167 goto end;
1168 }
1169
1170 /* Find a corresponding line */
1171 line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr);
1172 if (line) {
1173 if (dwarf_lineaddr(line, &laddr) == 0 &&
1174 (Dwarf_Addr)addr == laddr &&
1175 dwarf_lineno(line, &lineno) == 0) {
1176 tmp = dwarf_linesrc(line, NULL, NULL);
1177 if (tmp) {
1178 ppt->line = lineno;
1179 ppt->file = strdup(tmp);
1180 if (ppt->file == NULL) {
1181 ret = -ENOMEM;
1182 goto end;
1183 }
1184 found = true;
1185 }
1186 }
1187 }
1188
1189 /* Find a corresponding function */
1190 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) {
1191 tmp = dwarf_diename(&spdie);
1192 if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0)
1193 goto end;
1194
1195 if (ppt->line) {
1196 if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr,
1197 &indie)) {
1198 /* addr in an inline function */
1199 tmp = dwarf_diename(&indie);
1200 if (!tmp)
1201 goto end;
1202 ret = dwarf_decl_line(&indie, &lineno);
1203 } else {
1204 if (eaddr == addr) { /* Function entry */
1205 lineno = ppt->line;
1206 ret = 0;
1207 } else
1208 ret = dwarf_decl_line(&spdie, &lineno);
1209 }
1210 if (ret == 0) {
1211 /* Make a relative line number */
1212 ppt->line -= lineno;
1213 goto found;
1214 }
1215 }
1216 /* We don't have a line number, let's use offset */
1217 ppt->offset = addr - (unsigned long)eaddr;
665found: 1218found:
666 /* Get offset from subprogram */ 1219 ppt->function = strdup(tmp);
667 ret = die_within_subprogram(lk->die, pf->addr, &offs); 1220 if (ppt->function == NULL) {
668 DIE_IF(!ret); 1221 ret = -ENOMEM;
669 show_probepoint(lk->die, offs, pf); 1222 goto end;
670 /* Continue to search */
671 } 1223 }
1224 found = true;
672 } 1225 }
673 return 0; 1226
1227end:
1228 dwarf_end(dbg);
1229 if (ret >= 0)
1230 ret = found ? 1 : 0;
1231 return ret;
674} 1232}
675 1233
676static void find_by_func(struct probe_finder *pf) 1234/* Add a line and store the src path */
1235static int line_range_add_line(const char *src, unsigned int lineno,
1236 struct line_range *lr)
677{ 1237{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf); 1238 /* Copy source path */
1239 if (!lr->path) {
1240 lr->path = strdup(src);
1241 if (lr->path == NULL)
1242 return -ENOMEM;
1243 }
1244 return line_list__add_line(&lr->line_list, lineno);
679} 1245}
680 1246
681/* Find a probe point */ 1247/* Search function declaration lines */
682int find_probepoint(int fd, struct probe_point *pp) 1248static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data)
683{ 1249{
684 Dwarf_Half addr_size = 0; 1250 struct dwarf_callback_param *param = data;
685 Dwarf_Unsigned next_cuh = 0; 1251 struct line_finder *lf = param->data;
686 int cu_number = 0, ret; 1252 const char *src;
687 struct probe_finder pf = {.pp = pp}; 1253 int lineno;
1254
1255 src = dwarf_decl_file(sp_die);
1256 if (src && strtailcmp(src, lf->fname) != 0)
1257 return DWARF_CB_OK;
1258
1259 if (dwarf_decl_line(sp_die, &lineno) != 0 ||
1260 (lf->lno_s > lineno || lf->lno_e < lineno))
1261 return DWARF_CB_OK;
1262
1263 param->retval = line_range_add_line(src, lineno, lf->lr);
1264 if (param->retval < 0)
1265 return DWARF_CB_ABORT;
1266 return DWARF_CB_OK;
1267}
688 1268
689 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 1269static int find_line_range_func_decl_lines(struct line_finder *lf)
690 if (ret != DW_DLV_OK) 1270{
1271 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1272 dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, &param, 0);
1273 return param.retval;
1274}
1275
1276/* Find line range from its line number */
1277static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
1278{
1279 Dwarf_Lines *lines;
1280 Dwarf_Line *line;
1281 size_t nlines, i;
1282 Dwarf_Addr addr;
1283 int lineno, ret = 0;
1284 const char *src;
1285 Dwarf_Die die_mem;
1286
1287 line_list__init(&lf->lr->line_list);
1288 if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) {
1289 pr_warning("No source lines found in this CU.\n");
691 return -ENOENT; 1290 return -ENOENT;
1291 }
1292
1293 /* Search probable lines on lines list */
1294 for (i = 0; i < nlines; i++) {
1295 line = dwarf_onesrcline(lines, i);
1296 if (dwarf_lineno(line, &lineno) != 0 ||
1297 (lf->lno_s > lineno || lf->lno_e < lineno))
1298 continue;
1299
1300 if (sp_die) {
1301 /* Address filtering 1: does sp_die include addr? */
1302 if (dwarf_lineaddr(line, &addr) != 0 ||
1303 !dwarf_haspc(sp_die, addr))
1304 continue;
1305
1306 /* Address filtering 2: No child include addr? */
1307 if (die_find_inlinefunc(sp_die, addr, &die_mem))
1308 continue;
1309 }
1310
1311 /* TODO: Get fileno from line, but how? */
1312 src = dwarf_linesrc(line, NULL, NULL);
1313 if (strtailcmp(src, lf->fname) != 0)
1314 continue;
1315
1316 ret = line_range_add_line(src, lineno, lf->lr);
1317 if (ret < 0)
1318 return ret;
1319 }
1320
1321 /*
1322 * Dwarf lines doesn't include function declarations. We have to
1323 * check functions list or given function.
1324 */
1325 if (sp_die) {
1326 src = dwarf_decl_file(sp_die);
1327 if (src && dwarf_decl_line(sp_die, &lineno) == 0 &&
1328 (lf->lno_s <= lineno && lf->lno_e >= lineno))
1329 ret = line_range_add_line(src, lineno, lf->lr);
1330 } else
1331 ret = find_line_range_func_decl_lines(lf);
1332
1333 /* Update status */
1334 if (ret >= 0)
1335 if (!list_empty(&lf->lr->line_list))
1336 ret = lf->found = 1;
1337 else
1338 ret = 0; /* Lines are not found */
1339 else {
1340 free(lf->lr->path);
1341 lf->lr->path = NULL;
1342 }
1343 return ret;
1344}
1345
1346static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
1347{
1348 struct dwarf_callback_param *param = data;
692 1349
693 pp->found = 0; 1350 param->retval = find_line_range_by_line(in_die, param->data);
694 while (++cu_number) { 1351 return DWARF_CB_ABORT; /* No need to find other instances */
695 /* Search CU (Compilation Unit) */ 1352}
696 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 1353
697 &addr_size, &next_cuh, &__dw_error); 1354/* Search function from function name */
698 DIE_IF(ret == DW_DLV_ERROR); 1355static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
699 if (ret == DW_DLV_NO_ENTRY) 1356{
1357 struct dwarf_callback_param *param = data;
1358 struct line_finder *lf = param->data;
1359 struct line_range *lr = lf->lr;
1360
1361 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
1362 die_compare_name(sp_die, lr->function)) {
1363 lf->fname = dwarf_decl_file(sp_die);
1364 dwarf_decl_line(sp_die, &lr->offset);
1365 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
1366 lf->lno_s = lr->offset + lr->start;
1367 if (lf->lno_s < 0) /* Overflow */
1368 lf->lno_s = INT_MAX;
1369 lf->lno_e = lr->offset + lr->end;
1370 if (lf->lno_e < 0) /* Overflow */
1371 lf->lno_e = INT_MAX;
1372 pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
1373 lr->start = lf->lno_s;
1374 lr->end = lf->lno_e;
1375 if (dwarf_func_inline(sp_die)) {
1376 struct dwarf_callback_param _param;
1377 _param.data = (void *)lf;
1378 _param.retval = 0;
1379 dwarf_func_inline_instances(sp_die,
1380 line_range_inline_cb,
1381 &_param);
1382 param->retval = _param.retval;
1383 } else
1384 param->retval = find_line_range_by_line(sp_die, lf);
1385 return DWARF_CB_ABORT;
1386 }
1387 return DWARF_CB_OK;
1388}
1389
1390static int find_line_range_by_func(struct line_finder *lf)
1391{
1392 struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
1393 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, &param, 0);
1394 return param.retval;
1395}
1396
1397int find_line_range(int fd, struct line_range *lr)
1398{
1399 struct line_finder lf = {.lr = lr, .found = 0};
1400 int ret = 0;
1401 Dwarf_Off off = 0, noff;
1402 size_t cuhl;
1403 Dwarf_Die *diep;
1404 Dwarf *dbg;
1405 const char *comp_dir;
1406
1407 dbg = dwarf_begin(fd, DWARF_C_READ);
1408 if (!dbg) {
1409 pr_warning("No dwarf info found in the vmlinux - "
1410 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1411 return -EBADF;
1412 }
1413
1414 /* Loop on CUs (Compilation Unit) */
1415 while (!lf.found && ret >= 0) {
1416 if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0)
700 break; 1417 break;
701 1418
702 /* Get the DIE(Debugging Information Entry) of this CU */ 1419 /* Get the DIE(Debugging Information Entry) of this CU */
703 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 1420 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
704 DIE_IF(ret != DW_DLV_OK); 1421 if (!diep)
1422 continue;
705 1423
706 /* Check if target file is included. */ 1424 /* Check if target file is included. */
707 if (pp->file) 1425 if (lr->file)
708 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 1426 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
709 1427 else
710 if (!pp->file || pf.fno) { 1428 lf.fname = 0;
711 /* Save CU base address (for frame_base) */ 1429
712 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 1430 if (!lr->file || lf.fname) {
713 DIE_IF(ret == DW_DLV_ERROR); 1431 if (lr->function)
714 if (ret == DW_DLV_NO_ENTRY) 1432 ret = find_line_range_by_func(&lf);
715 pf.cu_base = 0;
716 if (pp->function)
717 find_by_func(&pf);
718 else { 1433 else {
719 pf.lno = pp->line; 1434 lf.lno_s = lr->start;
720 find_by_line(&pf); 1435 lf.lno_e = lr->end;
1436 ret = find_line_range_by_line(NULL, &lf);
721 } 1437 }
722 } 1438 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 1439 off = noff;
724 } 1440 }
725 ret = dwarf_finish(__dw_debug, &__dw_error);
726 DIE_IF(ret != DW_DLV_OK);
727 1441
728 return pp->found; 1442 /* Store comp_dir */
1443 if (lf.found) {
1444 comp_dir = cu_get_comp_dir(&lf.cu_die);
1445 if (comp_dir) {
1446 lr->comp_dir = strdup(comp_dir);
1447 if (!lr->comp_dir)
1448 ret = -ENOMEM;
1449 }
1450 }
1451
1452 pr_debug("path: %s\n", lr->path);
1453 dwarf_end(dbg);
1454
1455 return (ret < 0) ? ret : lf.found;
729} 1456}
730 1457
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index a4086aaddb73..4507d519f183 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,54 @@ 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,
17 21 struct probe_trace_event **tevs,
18 /* Inputs */ 22 int max_tevs);
19 char *file; /* File name */
20 int line; /* Line number */
21 23
22 char *function; /* Function name */ 24/* Find a perf_probe_point from debuginfo */
23 int offset; /* Offset bytes */ 25extern int find_perf_probe_point(int fd, unsigned long addr,
26 struct perf_probe_point *ppt);
24 27
25 int nr_args; /* Number of arguments */ 28extern int find_line_range(int fd, struct line_range *lr);
26 char **args; /* Arguments */
27
28 int retprobe; /* Return probe */
29
30 /* Output */
31 int found; /* Number of found probe points */
32 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
33};
34
35#ifndef NO_LIBDWARF
36extern int find_probepoint(int fd, struct probe_point *pp);
37
38/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
39#ifndef _MIPS_SZLONG
40# define _MIPS_SZLONG 0
41#endif
42 29
43#include <dwarf.h> 30#include <dwarf.h>
44#include <libdwarf.h> 31#include <libdw.h>
32#include <version.h>
45 33
46struct probe_finder { 34struct probe_finder {
47 struct probe_point *pp; /* Target probe point */ 35 struct perf_probe_event *pev; /* Target probe event */
36 struct probe_trace_event *tevs; /* Result trace events */
37 int ntevs; /* Number of trace events */
38 int max_tevs; /* Max number of trace events */
48 39
49 /* For function searching */ 40 /* For function searching */
50 Dwarf_Addr addr; /* Address */ 41 int lno; /* Line number */
51 Dwarf_Unsigned fno; /* File number */ 42 Dwarf_Addr addr; /* Address */
52 Dwarf_Unsigned lno; /* Line number */ 43 const char *fname; /* Real file name */
53 Dwarf_Off inl_offs; /* Inline offset */ 44 Dwarf_Die cu_die; /* Current CU */
54 Dwarf_Die cu_die; /* Current CU */ 45 struct list_head lcache; /* Line cache for lazy match */
55 46
56 /* For variable searching */ 47 /* For variable searching */
57 Dwarf_Addr cu_base; /* Current CU base address */ 48#if _ELFUTILS_PREREQ(0, 142)
58 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 49 Dwarf_CFI *cfi; /* Call Frame Information */
59 const char *var; /* Current variable name */ 50#endif
60 char *buf; /* Current output buffer */ 51 Dwarf_Op *fb_ops; /* Frame base attribute */
61 int len; /* Length of output buffer */ 52 struct perf_probe_arg *pvar; /* Current target variable */
53 struct probe_trace_arg *tvar; /* Current result variable */
54};
55
56struct line_finder {
57 struct line_range *lr; /* Target line range */
58
59 const char *fname; /* File name */
60 int lno_s; /* Start line number */
61 int lno_e; /* End line number */
62 Dwarf_Die cu_die; /* Current CU */
63 int found;
62}; 64};
63#endif /* NO_LIBDWARF */ 65
66#endif /* DWARF_SUPPORT */
64 67
65#endif /*_PROBE_FINDER_H */ 68#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..b059dc50cc2d 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -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
@@ -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..33a632523743
--- /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 trace event handlers, "
446 "generated by perf trace -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..fa9d652c2dc3 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,27 @@ 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) 68void perf_session__update_sample_type(struct perf_session *self)
69{
70 self->sample_type = perf_header__sample_type(&self->header);
71}
72
73int perf_session__create_kernel_maps(struct perf_session *self)
74{
75 int ret = machine__create_kernel_maps(&self->host_machine);
76
77 if (ret >= 0)
78 ret = machines__create_guest_kernel_maps(&self->machines);
79 return ret;
80}
81
82static void perf_session__destroy_kernel_maps(struct perf_session *self)
83{
84 machine__destroy_kernel_maps(&self->host_machine);
85 machines__destroy_guest_kernel_maps(&self->machines);
86}
87
88struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe)
53{ 89{
54 size_t len = filename ? strlen(filename) + 1 : 0; 90 size_t len = filename ? strlen(filename) + 1 : 0;
55 struct perf_session *self = zalloc(sizeof(*self) + len); 91 struct perf_session *self = zalloc(sizeof(*self) + len);
@@ -62,17 +98,28 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
62 98
63 memcpy(self->filename, filename, len); 99 memcpy(self->filename, filename, len);
64 self->threads = RB_ROOT; 100 self->threads = RB_ROOT;
101 INIT_LIST_HEAD(&self->dead_threads);
102 self->hists_tree = RB_ROOT;
65 self->last_match = NULL; 103 self->last_match = NULL;
66 self->mmap_window = 32; 104 self->mmap_window = 32;
67 self->cwd = NULL; 105 self->machines = RB_ROOT;
68 self->cwdlen = 0; 106 self->repipe = repipe;
69 map_groups__init(&self->kmaps); 107 INIT_LIST_HEAD(&self->ordered_samples.samples_head);
108 machine__init(&self->host_machine, "", HOST_KERNEL_ID);
70 109
71 if (perf_session__create_kernel_maps(self) < 0) 110 if (mode == O_RDONLY) {
72 goto out_delete; 111 if (perf_session__open(self, force) < 0)
112 goto out_delete;
113 } else if (mode == O_WRONLY) {
114 /*
115 * In O_RDONLY mode this will be performed when reading the
116 * kernel MMAP event, in event__process_mmap().
117 */
118 if (perf_session__create_kernel_maps(self) < 0)
119 goto out_delete;
120 }
73 121
74 if (mode == O_RDONLY && perf_session__open(self, force) < 0) 122 perf_session__update_sample_type(self);
75 goto out_delete;
76out: 123out:
77 return self; 124 return self;
78out_free: 125out_free:
@@ -83,14 +130,51 @@ out_delete:
83 return NULL; 130 return NULL;
84} 131}
85 132
133static void perf_session__delete_dead_threads(struct perf_session *self)
134{
135 struct thread *n, *t;
136
137 list_for_each_entry_safe(t, n, &self->dead_threads, node) {
138 list_del(&t->node);
139 thread__delete(t);
140 }
141}
142
143static void perf_session__delete_threads(struct perf_session *self)
144{
145 struct rb_node *nd = rb_first(&self->threads);
146
147 while (nd) {
148 struct thread *t = rb_entry(nd, struct thread, rb_node);
149
150 rb_erase(&t->rb_node, &self->threads);
151 nd = rb_next(nd);
152 thread__delete(t);
153 }
154}
155
86void perf_session__delete(struct perf_session *self) 156void perf_session__delete(struct perf_session *self)
87{ 157{
88 perf_header__exit(&self->header); 158 perf_header__exit(&self->header);
159 perf_session__destroy_kernel_maps(self);
160 perf_session__delete_dead_threads(self);
161 perf_session__delete_threads(self);
162 machine__exit(&self->host_machine);
89 close(self->fd); 163 close(self->fd);
90 free(self->cwd);
91 free(self); 164 free(self);
92} 165}
93 166
167void perf_session__remove_thread(struct perf_session *self, struct thread *th)
168{
169 self->last_match = NULL;
170 rb_erase(&th->rb_node, &self->threads);
171 /*
172 * We may have references to this thread, for instance in some hist_entry
173 * instances, so just move them to a separate list.
174 */
175 list_add_tail(&th->node, &self->dead_threads);
176}
177
94static bool symbol__match_parent_regex(struct symbol *sym) 178static bool symbol__match_parent_regex(struct symbol *sym)
95{ 179{
96 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 180 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
@@ -99,22 +183,17 @@ static bool symbol__match_parent_regex(struct symbol *sym)
99 return 0; 183 return 0;
100} 184}
101 185
102struct symbol **perf_session__resolve_callchain(struct perf_session *self, 186struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
103 struct thread *thread, 187 struct thread *thread,
104 struct ip_callchain *chain, 188 struct ip_callchain *chain,
105 struct symbol **parent) 189 struct symbol **parent)
106{ 190{
107 u8 cpumode = PERF_RECORD_MISC_USER; 191 u8 cpumode = PERF_RECORD_MISC_USER;
108 struct symbol **syms = NULL;
109 unsigned int i; 192 unsigned int i;
193 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms));
110 194
111 if (symbol_conf.use_callchain) { 195 if (!syms)
112 syms = calloc(chain->nr, sizeof(*syms)); 196 return NULL;
113 if (!syms) {
114 fprintf(stderr, "Can't allocate memory for symbols\n");
115 exit(-1);
116 }
117 }
118 197
119 for (i = 0; i < chain->nr; i++) { 198 for (i = 0; i < chain->nr; i++) {
120 u64 ip = chain->ips[i]; 199 u64 ip = chain->ips[i];
@@ -134,17 +213,719 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
134 continue; 213 continue;
135 } 214 }
136 215
216 al.filtered = false;
137 thread__find_addr_location(thread, self, cpumode, 217 thread__find_addr_location(thread, self, cpumode,
138 MAP__FUNCTION, ip, &al, NULL); 218 MAP__FUNCTION, thread->pid, ip, &al, NULL);
139 if (al.sym != NULL) { 219 if (al.sym != NULL) {
140 if (sort__has_parent && !*parent && 220 if (sort__has_parent && !*parent &&
141 symbol__match_parent_regex(al.sym)) 221 symbol__match_parent_regex(al.sym))
142 *parent = al.sym; 222 *parent = al.sym;
143 if (!symbol_conf.use_callchain) 223 if (!symbol_conf.use_callchain)
144 break; 224 break;
145 syms[i] = al.sym; 225 syms[i].map = al.map;
226 syms[i].sym = al.sym;
146 } 227 }
147 } 228 }
148 229
149 return syms; 230 return syms;
150} 231}
232
233static int process_event_stub(event_t *event __used,
234 struct perf_session *session __used)
235{
236 dump_printf(": unhandled!\n");
237 return 0;
238}
239
240static int process_finished_round_stub(event_t *event __used,
241 struct perf_session *session __used,
242 struct perf_event_ops *ops __used)
243{
244 dump_printf(": unhandled!\n");
245 return 0;
246}
247
248static int process_finished_round(event_t *event,
249 struct perf_session *session,
250 struct perf_event_ops *ops);
251
252static void perf_event_ops__fill_defaults(struct perf_event_ops *handler)
253{
254 if (handler->sample == NULL)
255 handler->sample = process_event_stub;
256 if (handler->mmap == NULL)
257 handler->mmap = process_event_stub;
258 if (handler->comm == NULL)
259 handler->comm = process_event_stub;
260 if (handler->fork == NULL)
261 handler->fork = process_event_stub;
262 if (handler->exit == NULL)
263 handler->exit = process_event_stub;
264 if (handler->lost == NULL)
265 handler->lost = process_event_stub;
266 if (handler->read == NULL)
267 handler->read = process_event_stub;
268 if (handler->throttle == NULL)
269 handler->throttle = process_event_stub;
270 if (handler->unthrottle == NULL)
271 handler->unthrottle = process_event_stub;
272 if (handler->attr == NULL)
273 handler->attr = process_event_stub;
274 if (handler->event_type == NULL)
275 handler->event_type = process_event_stub;
276 if (handler->tracing_data == NULL)
277 handler->tracing_data = process_event_stub;
278 if (handler->build_id == NULL)
279 handler->build_id = process_event_stub;
280 if (handler->finished_round == NULL) {
281 if (handler->ordered_samples)
282 handler->finished_round = process_finished_round;
283 else
284 handler->finished_round = process_finished_round_stub;
285 }
286}
287
288void mem_bswap_64(void *src, int byte_size)
289{
290 u64 *m = src;
291
292 while (byte_size > 0) {
293 *m = bswap_64(*m);
294 byte_size -= sizeof(u64);
295 ++m;
296 }
297}
298
299static void event__all64_swap(event_t *self)
300{
301 struct perf_event_header *hdr = &self->header;
302 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
303}
304
305static void event__comm_swap(event_t *self)
306{
307 self->comm.pid = bswap_32(self->comm.pid);
308 self->comm.tid = bswap_32(self->comm.tid);
309}
310
311static void event__mmap_swap(event_t *self)
312{
313 self->mmap.pid = bswap_32(self->mmap.pid);
314 self->mmap.tid = bswap_32(self->mmap.tid);
315 self->mmap.start = bswap_64(self->mmap.start);
316 self->mmap.len = bswap_64(self->mmap.len);
317 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
318}
319
320static void event__task_swap(event_t *self)
321{
322 self->fork.pid = bswap_32(self->fork.pid);
323 self->fork.tid = bswap_32(self->fork.tid);
324 self->fork.ppid = bswap_32(self->fork.ppid);
325 self->fork.ptid = bswap_32(self->fork.ptid);
326 self->fork.time = bswap_64(self->fork.time);
327}
328
329static void event__read_swap(event_t *self)
330{
331 self->read.pid = bswap_32(self->read.pid);
332 self->read.tid = bswap_32(self->read.tid);
333 self->read.value = bswap_64(self->read.value);
334 self->read.time_enabled = bswap_64(self->read.time_enabled);
335 self->read.time_running = bswap_64(self->read.time_running);
336 self->read.id = bswap_64(self->read.id);
337}
338
339static void event__attr_swap(event_t *self)
340{
341 size_t size;
342
343 self->attr.attr.type = bswap_32(self->attr.attr.type);
344 self->attr.attr.size = bswap_32(self->attr.attr.size);
345 self->attr.attr.config = bswap_64(self->attr.attr.config);
346 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period);
347 self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type);
348 self->attr.attr.read_format = bswap_64(self->attr.attr.read_format);
349 self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events);
350 self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type);
351 self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr);
352 self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len);
353
354 size = self->header.size;
355 size -= (void *)&self->attr.id - (void *)self;
356 mem_bswap_64(self->attr.id, size);
357}
358
359static void event__event_type_swap(event_t *self)
360{
361 self->event_type.event_type.event_id =
362 bswap_64(self->event_type.event_type.event_id);
363}
364
365static void event__tracing_data_swap(event_t *self)
366{
367 self->tracing_data.size = bswap_32(self->tracing_data.size);
368}
369
370typedef void (*event__swap_op)(event_t *self);
371
372static event__swap_op event__swap_ops[] = {
373 [PERF_RECORD_MMAP] = event__mmap_swap,
374 [PERF_RECORD_COMM] = event__comm_swap,
375 [PERF_RECORD_FORK] = event__task_swap,
376 [PERF_RECORD_EXIT] = event__task_swap,
377 [PERF_RECORD_LOST] = event__all64_swap,
378 [PERF_RECORD_READ] = event__read_swap,
379 [PERF_RECORD_SAMPLE] = event__all64_swap,
380 [PERF_RECORD_HEADER_ATTR] = event__attr_swap,
381 [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap,
382 [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap,
383 [PERF_RECORD_HEADER_BUILD_ID] = NULL,
384 [PERF_RECORD_HEADER_MAX] = NULL,
385};
386
387struct sample_queue {
388 u64 timestamp;
389 struct sample_event *event;
390 struct list_head list;
391};
392
393static void flush_sample_queue(struct perf_session *s,
394 struct perf_event_ops *ops)
395{
396 struct list_head *head = &s->ordered_samples.samples_head;
397 u64 limit = s->ordered_samples.next_flush;
398 struct sample_queue *tmp, *iter;
399
400 if (!ops->ordered_samples || !limit)
401 return;
402
403 list_for_each_entry_safe(iter, tmp, head, list) {
404 if (iter->timestamp > limit)
405 return;
406
407 if (iter == s->ordered_samples.last_inserted)
408 s->ordered_samples.last_inserted = NULL;
409
410 ops->sample((event_t *)iter->event, s);
411
412 s->ordered_samples.last_flush = iter->timestamp;
413 list_del(&iter->list);
414 free(iter->event);
415 free(iter);
416 }
417}
418
419/*
420 * When perf record finishes a pass on every buffers, it records this pseudo
421 * event.
422 * We record the max timestamp t found in the pass n.
423 * Assuming these timestamps are monotonic across cpus, we know that if
424 * a buffer still has events with timestamps below t, they will be all
425 * available and then read in the pass n + 1.
426 * Hence when we start to read the pass n + 2, we can safely flush every
427 * events with timestamps below t.
428 *
429 * ============ PASS n =================
430 * CPU 0 | CPU 1
431 * |
432 * cnt1 timestamps | cnt2 timestamps
433 * 1 | 2
434 * 2 | 3
435 * - | 4 <--- max recorded
436 *
437 * ============ PASS n + 1 ==============
438 * CPU 0 | CPU 1
439 * |
440 * cnt1 timestamps | cnt2 timestamps
441 * 3 | 5
442 * 4 | 6
443 * 5 | 7 <---- max recorded
444 *
445 * Flush every events below timestamp 4
446 *
447 * ============ PASS n + 2 ==============
448 * CPU 0 | CPU 1
449 * |
450 * cnt1 timestamps | cnt2 timestamps
451 * 6 | 8
452 * 7 | 9
453 * - | 10
454 *
455 * Flush every events below timestamp 7
456 * etc...
457 */
458static int process_finished_round(event_t *event __used,
459 struct perf_session *session,
460 struct perf_event_ops *ops)
461{
462 flush_sample_queue(session, ops);
463 session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
464
465 return 0;
466}
467
468static void __queue_sample_end(struct sample_queue *new, struct list_head *head)
469{
470 struct sample_queue *iter;
471
472 list_for_each_entry_reverse(iter, head, list) {
473 if (iter->timestamp < new->timestamp) {
474 list_add(&new->list, &iter->list);
475 return;
476 }
477 }
478
479 list_add(&new->list, head);
480}
481
482static void __queue_sample_before(struct sample_queue *new,
483 struct sample_queue *iter,
484 struct list_head *head)
485{
486 list_for_each_entry_continue_reverse(iter, head, list) {
487 if (iter->timestamp < new->timestamp) {
488 list_add(&new->list, &iter->list);
489 return;
490 }
491 }
492
493 list_add(&new->list, head);
494}
495
496static void __queue_sample_after(struct sample_queue *new,
497 struct sample_queue *iter,
498 struct list_head *head)
499{
500 list_for_each_entry_continue(iter, head, list) {
501 if (iter->timestamp > new->timestamp) {
502 list_add_tail(&new->list, &iter->list);
503 return;
504 }
505 }
506 list_add_tail(&new->list, head);
507}
508
509/* The queue is ordered by time */
510static void __queue_sample_event(struct sample_queue *new,
511 struct perf_session *s)
512{
513 struct sample_queue *last_inserted = s->ordered_samples.last_inserted;
514 struct list_head *head = &s->ordered_samples.samples_head;
515
516
517 if (!last_inserted) {
518 __queue_sample_end(new, head);
519 return;
520 }
521
522 /*
523 * Most of the time the current event has a timestamp
524 * very close to the last event inserted, unless we just switched
525 * to another event buffer. Having a sorting based on a list and
526 * on the last inserted event that is close to the current one is
527 * probably more efficient than an rbtree based sorting.
528 */
529 if (last_inserted->timestamp >= new->timestamp)
530 __queue_sample_before(new, last_inserted, head);
531 else
532 __queue_sample_after(new, last_inserted, head);
533}
534
535static int queue_sample_event(event_t *event, struct sample_data *data,
536 struct perf_session *s)
537{
538 u64 timestamp = data->time;
539 struct sample_queue *new;
540
541
542 if (timestamp < s->ordered_samples.last_flush) {
543 printf("Warning: Timestamp below last timeslice flush\n");
544 return -EINVAL;
545 }
546
547 new = malloc(sizeof(*new));
548 if (!new)
549 return -ENOMEM;
550
551 new->timestamp = timestamp;
552
553 new->event = malloc(event->header.size);
554 if (!new->event) {
555 free(new);
556 return -ENOMEM;
557 }
558
559 memcpy(new->event, event, event->header.size);
560
561 __queue_sample_event(new, s);
562 s->ordered_samples.last_inserted = new;
563
564 if (new->timestamp > s->ordered_samples.max_timestamp)
565 s->ordered_samples.max_timestamp = new->timestamp;
566
567 return 0;
568}
569
570static int perf_session__process_sample(event_t *event, struct perf_session *s,
571 struct perf_event_ops *ops)
572{
573 struct sample_data data;
574
575 if (!ops->ordered_samples)
576 return ops->sample(event, s);
577
578 bzero(&data, sizeof(struct sample_data));
579 event__parse_sample(event, s->sample_type, &data);
580
581 queue_sample_event(event, &data, s);
582
583 return 0;
584}
585
586static int perf_session__process_event(struct perf_session *self,
587 event_t *event,
588 struct perf_event_ops *ops,
589 u64 offset, u64 head)
590{
591 trace_event(event);
592
593 if (event->header.type < PERF_RECORD_HEADER_MAX) {
594 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
595 offset + head, event->header.size,
596 event__name[event->header.type]);
597 hists__inc_nr_events(&self->hists, event->header.type);
598 }
599
600 if (self->header.needs_swap && event__swap_ops[event->header.type])
601 event__swap_ops[event->header.type](event);
602
603 switch (event->header.type) {
604 case PERF_RECORD_SAMPLE:
605 return perf_session__process_sample(event, self, ops);
606 case PERF_RECORD_MMAP:
607 return ops->mmap(event, self);
608 case PERF_RECORD_COMM:
609 return ops->comm(event, self);
610 case PERF_RECORD_FORK:
611 return ops->fork(event, self);
612 case PERF_RECORD_EXIT:
613 return ops->exit(event, self);
614 case PERF_RECORD_LOST:
615 return ops->lost(event, self);
616 case PERF_RECORD_READ:
617 return ops->read(event, self);
618 case PERF_RECORD_THROTTLE:
619 return ops->throttle(event, self);
620 case PERF_RECORD_UNTHROTTLE:
621 return ops->unthrottle(event, self);
622 case PERF_RECORD_HEADER_ATTR:
623 return ops->attr(event, self);
624 case PERF_RECORD_HEADER_EVENT_TYPE:
625 return ops->event_type(event, self);
626 case PERF_RECORD_HEADER_TRACING_DATA:
627 /* setup for reading amidst mmap */
628 lseek(self->fd, offset + head, SEEK_SET);
629 return ops->tracing_data(event, self);
630 case PERF_RECORD_HEADER_BUILD_ID:
631 return ops->build_id(event, self);
632 case PERF_RECORD_FINISHED_ROUND:
633 return ops->finished_round(event, self, ops);
634 default:
635 ++self->hists.stats.nr_unknown_events;
636 return -1;
637 }
638}
639
640void perf_event_header__bswap(struct perf_event_header *self)
641{
642 self->type = bswap_32(self->type);
643 self->misc = bswap_16(self->misc);
644 self->size = bswap_16(self->size);
645}
646
647static struct thread *perf_session__register_idle_thread(struct perf_session *self)
648{
649 struct thread *thread = perf_session__findnew(self, 0);
650
651 if (thread == NULL || thread__set_comm(thread, "swapper")) {
652 pr_err("problem inserting idle task.\n");
653 thread = NULL;
654 }
655
656 return thread;
657}
658
659int do_read(int fd, void *buf, size_t size)
660{
661 void *buf_start = buf;
662
663 while (size) {
664 int ret = read(fd, buf, size);
665
666 if (ret <= 0)
667 return ret;
668
669 size -= ret;
670 buf += ret;
671 }
672
673 return buf - buf_start;
674}
675
676#define session_done() (*(volatile int *)(&session_done))
677volatile int session_done;
678
679static int __perf_session__process_pipe_events(struct perf_session *self,
680 struct perf_event_ops *ops)
681{
682 event_t event;
683 uint32_t size;
684 int skip = 0;
685 u64 head;
686 int err;
687 void *p;
688
689 perf_event_ops__fill_defaults(ops);
690
691 head = 0;
692more:
693 err = do_read(self->fd, &event, sizeof(struct perf_event_header));
694 if (err <= 0) {
695 if (err == 0)
696 goto done;
697
698 pr_err("failed to read event header\n");
699 goto out_err;
700 }
701
702 if (self->header.needs_swap)
703 perf_event_header__bswap(&event.header);
704
705 size = event.header.size;
706 if (size == 0)
707 size = 8;
708
709 p = &event;
710 p += sizeof(struct perf_event_header);
711
712 if (size - sizeof(struct perf_event_header)) {
713 err = do_read(self->fd, p,
714 size - sizeof(struct perf_event_header));
715 if (err <= 0) {
716 if (err == 0) {
717 pr_err("unexpected end of event stream\n");
718 goto done;
719 }
720
721 pr_err("failed to read event data\n");
722 goto out_err;
723 }
724 }
725
726 if (size == 0 ||
727 (skip = perf_session__process_event(self, &event, ops,
728 0, head)) < 0) {
729 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
730 head, event.header.size, event.header.type);
731 /*
732 * assume we lost track of the stream, check alignment, and
733 * increment a single u64 in the hope to catch on again 'soon'.
734 */
735 if (unlikely(head & 7))
736 head &= ~7ULL;
737
738 size = 8;
739 }
740
741 head += size;
742
743 dump_printf("\n%#Lx [%#x]: event: %d\n",
744 head, event.header.size, event.header.type);
745
746 if (skip > 0)
747 head += skip;
748
749 if (!session_done())
750 goto more;
751done:
752 err = 0;
753out_err:
754 return err;
755}
756
757int __perf_session__process_events(struct perf_session *self,
758 u64 data_offset, u64 data_size,
759 u64 file_size, struct perf_event_ops *ops)
760{
761 int err, mmap_prot, mmap_flags;
762 u64 head, shift;
763 u64 offset = 0;
764 size_t page_size;
765 event_t *event;
766 uint32_t size;
767 char *buf;
768 struct ui_progress *progress = ui_progress__new("Processing events...",
769 self->size);
770 if (progress == NULL)
771 return -1;
772
773 perf_event_ops__fill_defaults(ops);
774
775 page_size = sysconf(_SC_PAGESIZE);
776
777 head = data_offset;
778 shift = page_size * (head / page_size);
779 offset += shift;
780 head -= shift;
781
782 mmap_prot = PROT_READ;
783 mmap_flags = MAP_SHARED;
784
785 if (self->header.needs_swap) {
786 mmap_prot |= PROT_WRITE;
787 mmap_flags = MAP_PRIVATE;
788 }
789remap:
790 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
791 mmap_flags, self->fd, offset);
792 if (buf == MAP_FAILED) {
793 pr_err("failed to mmap file\n");
794 err = -errno;
795 goto out_err;
796 }
797
798more:
799 event = (event_t *)(buf + head);
800 ui_progress__update(progress, offset);
801
802 if (self->header.needs_swap)
803 perf_event_header__bswap(&event->header);
804 size = event->header.size;
805 if (size == 0)
806 size = 8;
807
808 if (head + event->header.size >= page_size * self->mmap_window) {
809 int munmap_ret;
810
811 shift = page_size * (head / page_size);
812
813 munmap_ret = munmap(buf, page_size * self->mmap_window);
814 assert(munmap_ret == 0);
815
816 offset += shift;
817 head -= shift;
818 goto remap;
819 }
820
821 size = event->header.size;
822
823 dump_printf("\n%#Lx [%#x]: event: %d\n",
824 offset + head, event->header.size, event->header.type);
825
826 if (size == 0 ||
827 perf_session__process_event(self, event, ops, offset, head) < 0) {
828 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
829 offset + head, event->header.size,
830 event->header.type);
831 /*
832 * assume we lost track of the stream, check alignment, and
833 * increment a single u64 in the hope to catch on again 'soon'.
834 */
835 if (unlikely(head & 7))
836 head &= ~7ULL;
837
838 size = 8;
839 }
840
841 head += size;
842
843 if (offset + head >= data_offset + data_size)
844 goto done;
845
846 if (offset + head < file_size)
847 goto more;
848done:
849 err = 0;
850 /* do the final flush for ordered samples */
851 self->ordered_samples.next_flush = ULLONG_MAX;
852 flush_sample_queue(self, ops);
853out_err:
854 ui_progress__delete(progress);
855 return err;
856}
857
858int perf_session__process_events(struct perf_session *self,
859 struct perf_event_ops *ops)
860{
861 int err;
862
863 if (perf_session__register_idle_thread(self) == NULL)
864 return -ENOMEM;
865
866 if (!self->fd_pipe)
867 err = __perf_session__process_events(self,
868 self->header.data_offset,
869 self->header.data_size,
870 self->size, ops);
871 else
872 err = __perf_session__process_pipe_events(self, ops);
873
874 return err;
875}
876
877bool perf_session__has_traces(struct perf_session *self, const char *msg)
878{
879 if (!(self->sample_type & PERF_SAMPLE_RAW)) {
880 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
881 return false;
882 }
883
884 return true;
885}
886
887int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
888 const char *symbol_name,
889 u64 addr)
890{
891 char *bracket;
892 enum map_type i;
893 struct ref_reloc_sym *ref;
894
895 ref = zalloc(sizeof(struct ref_reloc_sym));
896 if (ref == NULL)
897 return -ENOMEM;
898
899 ref->name = strdup(symbol_name);
900 if (ref->name == NULL) {
901 free(ref);
902 return -ENOMEM;
903 }
904
905 bracket = strchr(ref->name, ']');
906 if (bracket)
907 *bracket = '\0';
908
909 ref->addr = addr;
910
911 for (i = 0; i < MAP__NR_TYPES; ++i) {
912 struct kmap *kmap = map__kmap(maps[i]);
913 kmap->ref_reloc_sym = ref;
914 }
915
916 return 0;
917}
918
919size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
920{
921 return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) +
922 __dsos__fprintf(&self->host_machine.user_dsos, fp) +
923 machines__fprintf_dsos(&self->machines, fp);
924}
925
926size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
927 bool with_hits)
928{
929 size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
930 return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
931}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 32eaa1bada06..9fa0fc2a863f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -1,61 +1,145 @@
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_head;
21 struct sample_queue *last_inserted;
22};
13 23
14struct perf_session { 24struct perf_session {
15 struct perf_header header; 25 struct perf_header header;
16 unsigned long size; 26 unsigned long size;
17 unsigned long mmap_window; 27 unsigned long mmap_window;
18 struct map_groups kmaps;
19 struct rb_root threads; 28 struct rb_root threads;
29 struct list_head dead_threads;
20 struct thread *last_match; 30 struct thread *last_match;
21 struct events_stats events_stats; 31 struct machine host_machine;
22 unsigned long event_total[PERF_RECORD_MAX]; 32 struct rb_root machines;
23 struct rb_root hists; 33 struct rb_root hists_tree;
34 /*
35 * FIXME: should point to the first entry in hists_tree and
36 * be a hists instance. Right now its only 'report'
37 * that is using ->hists_tree while all the rest use
38 * ->hists.
39 */
40 struct hists hists;
24 u64 sample_type; 41 u64 sample_type;
25 int fd; 42 int fd;
43 bool fd_pipe;
44 bool repipe;
26 int cwdlen; 45 int cwdlen;
27 char *cwd; 46 char *cwd;
47 struct ordered_samples ordered_samples;
28 char filename[0]; 48 char filename[0];
29}; 49};
30 50
51struct perf_event_ops;
52
31typedef int (*event_op)(event_t *self, struct perf_session *session); 53typedef int (*event_op)(event_t *self, struct perf_session *session);
54typedef int (*event_op2)(event_t *self, struct perf_session *session,
55 struct perf_event_ops *ops);
32 56
33struct perf_event_ops { 57struct perf_event_ops {
34 event_op process_sample_event; 58 event_op sample,
35 event_op process_mmap_event; 59 mmap,
36 event_op process_comm_event; 60 comm,
37 event_op process_fork_event; 61 fork,
38 event_op process_exit_event; 62 exit,
39 event_op process_lost_event; 63 lost,
40 event_op process_read_event; 64 read,
41 event_op process_throttle_event; 65 throttle,
42 event_op process_unthrottle_event; 66 unthrottle,
43 int (*sample_type_check)(struct perf_session *session); 67 attr,
44 unsigned long total_unknown; 68 event_type,
45 bool full_paths; 69 tracing_data,
70 build_id;
71 event_op2 finished_round;
72 bool ordered_samples;
46}; 73};
47 74
48struct perf_session *perf_session__new(const char *filename, int mode, bool force); 75struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe);
49void perf_session__delete(struct perf_session *self); 76void perf_session__delete(struct perf_session *self);
50 77
78void perf_event_header__bswap(struct perf_event_header *self);
79
80int __perf_session__process_events(struct perf_session *self,
81 u64 data_offset, u64 data_size, u64 size,
82 struct perf_event_ops *ops);
51int perf_session__process_events(struct perf_session *self, 83int perf_session__process_events(struct perf_session *self,
52 struct perf_event_ops *event_ops); 84 struct perf_event_ops *event_ops);
53 85
54struct symbol **perf_session__resolve_callchain(struct perf_session *self, 86struct map_symbol *perf_session__resolve_callchain(struct perf_session *self,
55 struct thread *thread, 87 struct thread *thread,
56 struct ip_callchain *chain, 88 struct ip_callchain *chain,
57 struct symbol **parent); 89 struct symbol **parent);
90
91bool perf_session__has_traces(struct perf_session *self, const char *msg);
92
93int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps,
94 const char *symbol_name,
95 u64 addr);
96
97void mem_bswap_64(void *src, int byte_size);
98
99int perf_session__create_kernel_maps(struct perf_session *self);
100
101int do_read(int fd, void *buf, size_t size);
102void perf_session__update_sample_type(struct perf_session *self);
103void perf_session__remove_thread(struct perf_session *self, struct thread *th);
104
105static inline
106struct machine *perf_session__find_host_machine(struct perf_session *self)
107{
108 return &self->host_machine;
109}
110
111static inline
112struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
113{
114 if (pid == HOST_KERNEL_ID)
115 return &self->host_machine;
116 return machines__find(&self->machines, pid);
117}
118
119static inline
120struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
121{
122 if (pid == HOST_KERNEL_ID)
123 return &self->host_machine;
124 return machines__findnew(&self->machines, pid);
125}
126
127static inline
128void perf_session__process_machines(struct perf_session *self,
129 machine__process_t process)
130{
131 process(&self->host_machine, self);
132 return machines__process(&self->machines, process, self);
133}
134
135size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp);
58 136
59int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 137size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
138 FILE *fp, bool with_hits);
60 139
140static inline
141size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp)
142{
143 return hists__fprintf_nr_events(&self->hists, fp);
144}
61#endif /* __PERF_SESSION_H */ 145#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..b62a553cc67d 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, "%*Lx", width, self->ip);
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, "%*Lx %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, "%*Lx",
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..46e531d09e8b 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_node 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..0409fc7c0058 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 == '*') {
@@ -251,3 +265,32 @@ bool strglobmatch(const char *str, const char *pat)
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..b2f5ae97f33d 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1,14 +1,21 @@
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>
@@ -19,21 +26,14 @@
19#define NT_GNU_BUILD_ID 3 26#define NT_GNU_BUILD_ID 3
20#endif 27#endif
21 28
22enum dso_origin { 29static bool dso__build_id_equal(const struct dso *self, u8 *build_id);
23 DSO__ORIG_KERNEL = 0, 30static 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); 31static void dsos__add(struct list_head *head, struct dso *dso);
34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 32static 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, 33static int dso__load_kernel_sym(struct dso *self, struct map *map,
36 struct perf_session *session, symbol_filter_t filter); 34 symbol_filter_t filter);
35static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
36 symbol_filter_t filter);
37static int vmlinux_path__nr_entries; 37static int vmlinux_path__nr_entries;
38static char **vmlinux_path; 38static char **vmlinux_path;
39 39
@@ -43,6 +43,14 @@ struct symbol_conf symbol_conf = {
43 .try_vmlinux_path = true, 43 .try_vmlinux_path = true,
44}; 44};
45 45
46int dso__name_len(const struct dso *self)
47{
48 if (verbose)
49 return self->long_name_len;
50
51 return self->short_name_len;
52}
53
46bool dso__loaded(const struct dso *self, enum map_type type) 54bool dso__loaded(const struct dso *self, enum map_type type)
47{ 55{
48 return self->loaded & (1 << type); 56 return self->loaded & (1 << type);
@@ -53,17 +61,12 @@ bool dso__sorted_by_name(const struct dso *self, enum map_type type)
53 return self->sorted_by_name & (1 << type); 61 return self->sorted_by_name & (1 << type);
54} 62}
55 63
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) 64static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
62{ 65{
63 self->sorted_by_name |= (1 << type); 66 self->sorted_by_name |= (1 << type);
64} 67}
65 68
66static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 69bool symbol_type__is_a(char symbol_type, enum map_type map_type)
67{ 70{
68 switch (map_type) { 71 switch (map_type) {
69 case MAP__FUNCTION: 72 case MAP__FUNCTION:
@@ -128,39 +131,45 @@ static void map_groups__fixup_end(struct map_groups *self)
128 __map_groups__fixup_end(self, i); 131 __map_groups__fixup_end(self, i);
129} 132}
130 133
131static struct symbol *symbol__new(u64 start, u64 len, const char *name) 134static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
135 const char *name)
132{ 136{
133 size_t namelen = strlen(name) + 1; 137 size_t namelen = strlen(name) + 1;
134 struct symbol *self = zalloc(symbol_conf.priv_size + 138 struct symbol *self = calloc(1, (symbol_conf.priv_size +
135 sizeof(*self) + namelen); 139 sizeof(*self) + namelen));
136 if (self == NULL) 140 if (self == NULL)
137 return NULL; 141 return NULL;
138 142
139 if (symbol_conf.priv_size) 143 if (symbol_conf.priv_size)
140 self = ((void *)self) + symbol_conf.priv_size; 144 self = ((void *)self) + symbol_conf.priv_size;
141 145
142 self->start = start; 146 self->start = start;
143 self->end = len ? start + len - 1 : start; 147 self->end = len ? start + len - 1 : start;
148 self->binding = binding;
149 self->namelen = namelen - 1;
144 150
145 pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 151 pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
146 152
147 memcpy(self->name, name, namelen); 153 memcpy(self->name, name, namelen);
148 154
149 return self; 155 return self;
150} 156}
151 157
152static void symbol__delete(struct symbol *self) 158void symbol__delete(struct symbol *self)
153{ 159{
154 free(((void *)self) - symbol_conf.priv_size); 160 free(((void *)self) - symbol_conf.priv_size);
155} 161}
156 162
157static size_t symbol__fprintf(struct symbol *self, FILE *fp) 163static size_t symbol__fprintf(struct symbol *self, FILE *fp)
158{ 164{
159 return fprintf(fp, " %llx-%llx %s\n", 165 return fprintf(fp, " %llx-%llx %c %s\n",
160 self->start, self->end, self->name); 166 self->start, self->end,
167 self->binding == STB_GLOBAL ? 'g' :
168 self->binding == STB_LOCAL ? 'l' : 'w',
169 self->name);
161} 170}
162 171
163static void dso__set_long_name(struct dso *self, char *name) 172void dso__set_long_name(struct dso *self, char *name)
164{ 173{
165 if (name == NULL) 174 if (name == NULL)
166 return; 175 return;
@@ -168,20 +177,28 @@ static void dso__set_long_name(struct dso *self, char *name)
168 self->long_name_len = strlen(name); 177 self->long_name_len = strlen(name);
169} 178}
170 179
180static void dso__set_short_name(struct dso *self, const char *name)
181{
182 if (name == NULL)
183 return;
184 self->short_name = name;
185 self->short_name_len = strlen(name);
186}
187
171static void dso__set_basename(struct dso *self) 188static void dso__set_basename(struct dso *self)
172{ 189{
173 self->short_name = basename(self->long_name); 190 dso__set_short_name(self, basename(self->long_name));
174} 191}
175 192
176struct dso *dso__new(const char *name) 193struct dso *dso__new(const char *name)
177{ 194{
178 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 195 struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
179 196
180 if (self != NULL) { 197 if (self != NULL) {
181 int i; 198 int i;
182 strcpy(self->name, name); 199 strcpy(self->name, name);
183 dso__set_long_name(self, self->name); 200 dso__set_long_name(self, self->name);
184 self->short_name = self->name; 201 dso__set_short_name(self, self->name);
185 for (i = 0; i < MAP__NR_TYPES; ++i) 202 for (i = 0; i < MAP__NR_TYPES; ++i)
186 self->symbols[i] = self->symbol_names[i] = RB_ROOT; 203 self->symbols[i] = self->symbol_names[i] = RB_ROOT;
187 self->slen_calculated = 0; 204 self->slen_calculated = 0;
@@ -189,6 +206,8 @@ struct dso *dso__new(const char *name)
189 self->loaded = 0; 206 self->loaded = 0;
190 self->sorted_by_name = 0; 207 self->sorted_by_name = 0;
191 self->has_build_id = 0; 208 self->has_build_id = 0;
209 self->kernel = DSO_TYPE_USER;
210 INIT_LIST_HEAD(&self->node);
192 } 211 }
193 212
194 return self; 213 return self;
@@ -212,7 +231,9 @@ void dso__delete(struct dso *self)
212 int i; 231 int i;
213 for (i = 0; i < MAP__NR_TYPES; ++i) 232 for (i = 0; i < MAP__NR_TYPES; ++i)
214 symbols__delete(&self->symbols[i]); 233 symbols__delete(&self->symbols[i]);
215 if (self->long_name != self->name) 234 if (self->sname_alloc)
235 free((char *)self->short_name);
236 if (self->lname_alloc)
216 free(self->long_name); 237 free(self->long_name);
217 free(self); 238 free(self);
218} 239}
@@ -344,10 +365,10 @@ void dso__sort_by_name(struct dso *self, enum map_type type)
344 &self->symbols[type]); 365 &self->symbols[type]);
345} 366}
346 367
347int build_id__sprintf(u8 *self, int len, char *bf) 368int build_id__sprintf(const u8 *self, int len, char *bf)
348{ 369{
349 char *bid = bf; 370 char *bid = bf;
350 u8 *raw = self; 371 const u8 *raw = self;
351 int i; 372 int i;
352 373
353 for (i = 0; i < len; ++i) { 374 for (i = 0; i < len; ++i) {
@@ -372,6 +393,10 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
372 struct rb_node *nd; 393 struct rb_node *nd;
373 size_t ret = fprintf(fp, "dso: %s (", self->short_name); 394 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
374 395
396 if (self->short_name != self->long_name)
397 ret += fprintf(fp, "%s, ", self->long_name);
398 ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
399 self->loaded ? "" : "NOT ");
375 ret += dso__fprintf_buildid(self, fp); 400 ret += dso__fprintf_buildid(self, fp);
376 ret += fprintf(fp, ")\n"); 401 ret += fprintf(fp, ")\n");
377 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 402 for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
@@ -382,35 +407,28 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
382 return ret; 407 return ret;
383} 408}
384 409
385/* 410int kallsyms__parse(const char *filename, void *arg,
386 * Loads the function entries in /proc/kallsyms into kernel_map->dso, 411 int (*process_symbol)(void *arg, const char *name,
387 * so that we can in the next step set the symbol ->end address and then 412 char type, u64 start))
388 * call kernel_maps__split_kallsyms.
389 */
390static int dso__load_all_kallsyms(struct dso *self, struct map *map)
391{ 413{
392 char *line = NULL; 414 char *line = NULL;
393 size_t n; 415 size_t n;
394 struct rb_root *root = &self->symbols[map->type]; 416 int err = 0;
395 FILE *file = fopen("/proc/kallsyms", "r"); 417 FILE *file = fopen(filename, "r");
396 418
397 if (file == NULL) 419 if (file == NULL)
398 goto out_failure; 420 goto out_failure;
399 421
400 while (!feof(file)) { 422 while (!feof(file)) {
401 u64 start; 423 u64 start;
402 struct symbol *sym;
403 int line_len, len; 424 int line_len, len;
404 char symbol_type; 425 char symbol_type;
405 char *symbol_name; 426 char *symbol_name;
406 427
407 line_len = getline(&line, &n, file); 428 line_len = getline(&line, &n, file);
408 if (line_len < 0) 429 if (line_len < 0 || !line)
409 break; 430 break;
410 431
411 if (!line)
412 goto out_failure;
413
414 line[--line_len] = '\0'; /* \n */ 432 line[--line_len] = '\0'; /* \n */
415 433
416 len = hex2u64(line, &start); 434 len = hex2u64(line, &start);
@@ -420,43 +438,82 @@ static int dso__load_all_kallsyms(struct dso *self, struct map *map)
420 continue; 438 continue;
421 439
422 symbol_type = toupper(line[len]); 440 symbol_type = toupper(line[len]);
423 if (!symbol_type__is_a(symbol_type, map->type))
424 continue;
425
426 symbol_name = line + len + 2; 441 symbol_name = line + len + 2;
427 /*
428 * Will fix up the end later, when we have all symbols sorted.
429 */
430 sym = symbol__new(start, 0, symbol_name);
431 442
432 if (sym == NULL) 443 err = process_symbol(arg, symbol_name, symbol_type, start);
433 goto out_delete_line; 444 if (err)
434 /* 445 break;
435 * We will pass the symbols to the filter later, in
436 * map__split_kallsyms, when we have split the maps per module
437 */
438 symbols__insert(root, sym);
439 } 446 }
440 447
441 free(line); 448 free(line);
442 fclose(file); 449 fclose(file);
450 return err;
443 451
444 return 0;
445
446out_delete_line:
447 free(line);
448out_failure: 452out_failure:
449 return -1; 453 return -1;
450} 454}
451 455
456struct process_kallsyms_args {
457 struct map *map;
458 struct dso *dso;
459};
460
461static u8 kallsyms2elf_type(char type)
462{
463 if (type == 'W')
464 return STB_WEAK;
465
466 return isupper(type) ? STB_GLOBAL : STB_LOCAL;
467}
468
469static int map__process_kallsym_symbol(void *arg, const char *name,
470 char type, u64 start)
471{
472 struct symbol *sym;
473 struct process_kallsyms_args *a = arg;
474 struct rb_root *root = &a->dso->symbols[a->map->type];
475
476 if (!symbol_type__is_a(type, a->map->type))
477 return 0;
478
479 /*
480 * Will fix up the end later, when we have all symbols sorted.
481 */
482 sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
483
484 if (sym == NULL)
485 return -ENOMEM;
486 /*
487 * We will pass the symbols to the filter later, in
488 * map__split_kallsyms, when we have split the maps per module
489 */
490 symbols__insert(root, sym);
491
492 return 0;
493}
494
495/*
496 * Loads the function entries in /proc/kallsyms into kernel_map->dso,
497 * so that we can in the next step set the symbol ->end address and then
498 * call kernel_maps__split_kallsyms.
499 */
500static int dso__load_all_kallsyms(struct dso *self, const char *filename,
501 struct map *map)
502{
503 struct process_kallsyms_args args = { .map = map, .dso = self, };
504 return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
505}
506
452/* 507/*
453 * Split the symbols into maps, making sure there are no overlaps, i.e. the 508 * 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 509 * kernel range is broken in several maps, named [kernel].N, as we don't have
455 * the original ELF section names vmlinux have. 510 * the original ELF section names vmlinux have.
456 */ 511 */
457static int dso__split_kallsyms(struct dso *self, struct map *map, 512static int dso__split_kallsyms(struct dso *self, struct map *map,
458 struct perf_session *session, symbol_filter_t filter) 513 symbol_filter_t filter)
459{ 514{
515 struct map_groups *kmaps = map__kmap(map)->kmaps;
516 struct machine *machine = kmaps->machine;
460 struct map *curr_map = map; 517 struct map *curr_map = map;
461 struct symbol *pos; 518 struct symbol *pos;
462 int count = 0; 519 int count = 0;
@@ -477,13 +534,35 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
477 534
478 *module++ = '\0'; 535 *module++ = '\0';
479 536
480 if (strcmp(self->name, module)) { 537 if (strcmp(curr_map->dso->short_name, module)) {
481 curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 538 if (curr_map != map &&
539 self->kernel == DSO_TYPE_GUEST_KERNEL &&
540 machine__is_default_guest(machine)) {
541 /*
542 * We assume all symbols of a module are
543 * continuous in * kallsyms, so curr_map
544 * points to a module and all its
545 * symbols are in its kmap. Mark it as
546 * loaded.
547 */
548 dso__set_loaded(curr_map->dso,
549 curr_map->type);
550 }
551
552 curr_map = map_groups__find_by_name(kmaps,
553 map->type, module);
482 if (curr_map == NULL) { 554 if (curr_map == NULL) {
483 pr_debug("/proc/{kallsyms,modules} " 555 pr_debug("%s/proc/{kallsyms,modules} "
484 "inconsistency!\n"); 556 "inconsistency while looking "
485 return -1; 557 "for \"%s\" module!\n",
558 machine->root_dir, module);
559 curr_map = map;
560 goto discard_symbol;
486 } 561 }
562
563 if (curr_map->dso->loaded &&
564 !machine__is_default_guest(machine))
565 goto discard_symbol;
487 } 566 }
488 /* 567 /*
489 * So that we look just like we get from .ko files, 568 * So that we look just like we get from .ko files,
@@ -495,21 +574,29 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
495 char dso_name[PATH_MAX]; 574 char dso_name[PATH_MAX];
496 struct dso *dso; 575 struct dso *dso;
497 576
498 snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 577 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
499 kernel_range++); 578 snprintf(dso_name, sizeof(dso_name),
579 "[guest.kernel].%d",
580 kernel_range++);
581 else
582 snprintf(dso_name, sizeof(dso_name),
583 "[kernel].%d",
584 kernel_range++);
500 585
501 dso = dso__new(dso_name); 586 dso = dso__new(dso_name);
502 if (dso == NULL) 587 if (dso == NULL)
503 return -1; 588 return -1;
504 589
590 dso->kernel = self->kernel;
591
505 curr_map = map__new2(pos->start, dso, map->type); 592 curr_map = map__new2(pos->start, dso, map->type);
506 if (map == NULL) { 593 if (curr_map == NULL) {
507 dso__delete(dso); 594 dso__delete(dso);
508 return -1; 595 return -1;
509 } 596 }
510 597
511 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 598 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
512 map_groups__insert(&session->kmaps, curr_map); 599 map_groups__insert(kmaps, curr_map);
513 ++kernel_range; 600 ++kernel_range;
514 } 601 }
515 602
@@ -525,20 +612,28 @@ discard_symbol: rb_erase(&pos->rb_node, root);
525 } 612 }
526 } 613 }
527 614
615 if (curr_map != map &&
616 self->kernel == DSO_TYPE_GUEST_KERNEL &&
617 machine__is_default_guest(kmaps->machine)) {
618 dso__set_loaded(curr_map->dso, curr_map->type);
619 }
620
528 return count; 621 return count;
529} 622}
530 623
531 624int dso__load_kallsyms(struct dso *self, const char *filename,
532static int dso__load_kallsyms(struct dso *self, struct map *map, 625 struct map *map, symbol_filter_t filter)
533 struct perf_session *session, symbol_filter_t filter)
534{ 626{
535 if (dso__load_all_kallsyms(self, map) < 0) 627 if (dso__load_all_kallsyms(self, filename, map) < 0)
536 return -1; 628 return -1;
537 629
538 symbols__fixup_end(&self->symbols[map->type]); 630 symbols__fixup_end(&self->symbols[map->type]);
539 self->origin = DSO__ORIG_KERNEL; 631 if (self->kernel == DSO_TYPE_GUEST_KERNEL)
632 self->origin = DSO__ORIG_GUEST_KERNEL;
633 else
634 self->origin = DSO__ORIG_KERNEL;
540 635
541 return dso__split_kallsyms(self, map, session, filter); 636 return dso__split_kallsyms(self, map, filter);
542} 637}
543 638
544static int dso__load_perf_map(struct dso *self, struct map *map, 639static int dso__load_perf_map(struct dso *self, struct map *map,
@@ -579,7 +674,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
579 if (len + 2 >= line_len) 674 if (len + 2 >= line_len)
580 continue; 675 continue;
581 676
582 sym = symbol__new(start, size, line + len); 677 sym = symbol__new(start, size, STB_GLOBAL, line + len);
583 678
584 if (sym == NULL) 679 if (sym == NULL)
585 goto out_delete_line; 680 goto out_delete_line;
@@ -791,7 +886,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
791 "%s@plt", elf_sym__name(&sym, symstrs)); 886 "%s@plt", elf_sym__name(&sym, symstrs));
792 887
793 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 888 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
794 sympltname); 889 STB_GLOBAL, sympltname);
795 if (!f) 890 if (!f)
796 goto out_elf_end; 891 goto out_elf_end;
797 892
@@ -813,7 +908,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
813 "%s@plt", elf_sym__name(&sym, symstrs)); 908 "%s@plt", elf_sym__name(&sym, symstrs));
814 909
815 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 910 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
816 sympltname); 911 STB_GLOBAL, sympltname);
817 if (!f) 912 if (!f)
818 goto out_elf_end; 913 goto out_elf_end;
819 914
@@ -835,8 +930,8 @@ out_close:
835 if (err == 0) 930 if (err == 0)
836 return nr; 931 return nr;
837out: 932out:
838 pr_warning("%s: problems reading %s PLT info.\n", 933 pr_debug("%s: problems reading %s PLT info.\n",
839 __func__, self->long_name); 934 __func__, self->long_name);
840 return 0; 935 return 0;
841} 936}
842 937
@@ -864,43 +959,82 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type
864 } 959 }
865} 960}
866 961
867static int dso__load_sym(struct dso *self, struct map *map, 962static 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{ 963{
964 Elf_Scn *sec = NULL;
965 GElf_Shdr shdr;
966 size_t cnt = 1;
967
968 while ((sec = elf_nextscn(elf, sec)) != NULL) {
969 gelf_getshdr(sec, &shdr);
970
971 if ((addr >= shdr.sh_addr) &&
972 (addr < (shdr.sh_addr + shdr.sh_size)))
973 return cnt;
974
975 ++cnt;
976 }
977
978 return -1;
979}
980
981static int dso__load_sym(struct dso *self, struct map *map, const char *name,
982 int fd, symbol_filter_t filter, int kmodule,
983 int want_symtab)
984{
985 struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
871 struct map *curr_map = map; 986 struct map *curr_map = map;
872 struct dso *curr_dso = self; 987 struct dso *curr_dso = self;
873 size_t dso_name_len = strlen(self->short_name);
874 Elf_Data *symstrs, *secstrs; 988 Elf_Data *symstrs, *secstrs;
875 uint32_t nr_syms; 989 uint32_t nr_syms;
876 int err = -1; 990 int err = -1;
877 uint32_t idx; 991 uint32_t idx;
878 GElf_Ehdr ehdr; 992 GElf_Ehdr ehdr;
879 GElf_Shdr shdr; 993 GElf_Shdr shdr, opdshdr;
880 Elf_Data *syms; 994 Elf_Data *syms, *opddata = NULL;
881 GElf_Sym sym; 995 GElf_Sym sym;
882 Elf_Scn *sec, *sec_strndx; 996 Elf_Scn *sec, *sec_strndx, *opdsec;
883 Elf *elf; 997 Elf *elf;
884 int nr = 0; 998 int nr = 0;
999 size_t opdidx = 0;
885 1000
886 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1001 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
887 if (elf == NULL) { 1002 if (elf == NULL) {
888 pr_err("%s: cannot read %s ELF file.\n", __func__, name); 1003 pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
889 goto out_close; 1004 goto out_close;
890 } 1005 }
891 1006
892 if (gelf_getehdr(elf, &ehdr) == NULL) { 1007 if (gelf_getehdr(elf, &ehdr) == NULL) {
893 pr_err("%s: cannot get elf header.\n", __func__); 1008 pr_debug("%s: cannot get elf header.\n", __func__);
894 goto out_elf_end; 1009 goto out_elf_end;
895 } 1010 }
896 1011
1012 /* Always reject images with a mismatched build-id: */
1013 if (self->has_build_id) {
1014 u8 build_id[BUILD_ID_SIZE];
1015
1016 if (elf_read_build_id(elf, build_id,
1017 BUILD_ID_SIZE) != BUILD_ID_SIZE)
1018 goto out_elf_end;
1019
1020 if (!dso__build_id_equal(self, build_id))
1021 goto out_elf_end;
1022 }
1023
897 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 1024 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
898 if (sec == NULL) { 1025 if (sec == NULL) {
1026 if (want_symtab)
1027 goto out_elf_end;
1028
899 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1029 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
900 if (sec == NULL) 1030 if (sec == NULL)
901 goto out_elf_end; 1031 goto out_elf_end;
902 } 1032 }
903 1033
1034 opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
1035 if (opdsec)
1036 opddata = elf_rawdata(opdsec, NULL);
1037
904 syms = elf_getdata(sec, NULL); 1038 syms = elf_getdata(sec, NULL);
905 if (syms == NULL) 1039 if (syms == NULL)
906 goto out_elf_end; 1040 goto out_elf_end;
@@ -924,7 +1058,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
924 nr_syms = shdr.sh_size / shdr.sh_entsize; 1058 nr_syms = shdr.sh_size / shdr.sh_entsize;
925 1059
926 memset(&sym, 0, sizeof(sym)); 1060 memset(&sym, 0, sizeof(sym));
927 if (!kernel) { 1061 if (self->kernel == DSO_TYPE_USER) {
928 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 1062 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
929 elf_section_by_name(elf, &ehdr, &shdr, 1063 elf_section_by_name(elf, &ehdr, &shdr,
930 ".gnu.prelink_undo", 1064 ".gnu.prelink_undo",
@@ -933,14 +1067,35 @@ static int dso__load_sym(struct dso *self, struct map *map,
933 1067
934 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 1068 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
935 struct symbol *f; 1069 struct symbol *f;
936 const char *elf_name; 1070 const char *elf_name = elf_sym__name(&sym, symstrs);
937 char *demangled = NULL; 1071 char *demangled = NULL;
938 int is_label = elf_sym__is_label(&sym); 1072 int is_label = elf_sym__is_label(&sym);
939 const char *section_name; 1073 const char *section_name;
940 1074
1075 if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
1076 strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
1077 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
1078
941 if (!is_label && !elf_sym__is_a(&sym, map->type)) 1079 if (!is_label && !elf_sym__is_a(&sym, map->type))
942 continue; 1080 continue;
943 1081
1082 /* Reject ARM ELF "mapping symbols": these aren't unique and
1083 * don't identify functions, so will confuse the profile
1084 * output: */
1085 if (ehdr.e_machine == EM_ARM) {
1086 if (!strcmp(elf_name, "$a") ||
1087 !strcmp(elf_name, "$d") ||
1088 !strcmp(elf_name, "$t"))
1089 continue;
1090 }
1091
1092 if (opdsec && sym.st_shndx == opdidx) {
1093 u32 offset = sym.st_value - opdshdr.sh_addr;
1094 u64 *opd = opddata->d_buf + offset;
1095 sym.st_value = *opd;
1096 sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
1097 }
1098
944 sec = elf_getscn(elf, sym.st_shndx); 1099 sec = elf_getscn(elf, sym.st_shndx);
945 if (!sec) 1100 if (!sec)
946 goto out_elf_end; 1101 goto out_elf_end;
@@ -950,14 +1105,14 @@ static int dso__load_sym(struct dso *self, struct map *map,
950 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 1105 if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
951 continue; 1106 continue;
952 1107
953 elf_name = elf_sym__name(&sym, symstrs);
954 section_name = elf_sec__name(&shdr, secstrs); 1108 section_name = elf_sec__name(&shdr, secstrs);
955 1109
956 if (kernel || kmodule) { 1110 if (self->kernel != DSO_TYPE_USER || kmodule) {
957 char dso_name[PATH_MAX]; 1111 char dso_name[PATH_MAX];
958 1112
959 if (strcmp(section_name, 1113 if (strcmp(section_name,
960 curr_dso->short_name + dso_name_len) == 0) 1114 (curr_dso->short_name +
1115 self->short_name_len)) == 0)
961 goto new_symbol; 1116 goto new_symbol;
962 1117
963 if (strcmp(section_name, ".text") == 0) { 1118 if (strcmp(section_name, ".text") == 0) {
@@ -969,7 +1124,7 @@ static int dso__load_sym(struct dso *self, struct map *map,
969 snprintf(dso_name, sizeof(dso_name), 1124 snprintf(dso_name, sizeof(dso_name),
970 "%s%s", self->short_name, section_name); 1125 "%s%s", self->short_name, section_name);
971 1126
972 curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); 1127 curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
973 if (curr_map == NULL) { 1128 if (curr_map == NULL) {
974 u64 start = sym.st_value; 1129 u64 start = sym.st_value;
975 1130
@@ -979,17 +1134,19 @@ static int dso__load_sym(struct dso *self, struct map *map,
979 curr_dso = dso__new(dso_name); 1134 curr_dso = dso__new(dso_name);
980 if (curr_dso == NULL) 1135 if (curr_dso == NULL)
981 goto out_elf_end; 1136 goto out_elf_end;
1137 curr_dso->kernel = self->kernel;
982 curr_map = map__new2(start, curr_dso, 1138 curr_map = map__new2(start, curr_dso,
983 MAP__FUNCTION); 1139 map->type);
984 if (curr_map == NULL) { 1140 if (curr_map == NULL) {
985 dso__delete(curr_dso); 1141 dso__delete(curr_dso);
986 goto out_elf_end; 1142 goto out_elf_end;
987 } 1143 }
988 curr_map->map_ip = identity__map_ip; 1144 curr_map->map_ip = identity__map_ip;
989 curr_map->unmap_ip = identity__map_ip; 1145 curr_map->unmap_ip = identity__map_ip;
990 curr_dso->origin = DSO__ORIG_KERNEL; 1146 curr_dso->origin = self->origin;
991 map_groups__insert(&session->kmaps, curr_map); 1147 map_groups__insert(kmap->kmaps, curr_map);
992 dsos__add(&dsos__kernel, curr_dso); 1148 dsos__add(&self->node, curr_dso);
1149 dso__set_loaded(curr_dso, map->type);
993 } else 1150 } else
994 curr_dso = curr_map->dso; 1151 curr_dso = curr_map->dso;
995 1152
@@ -997,9 +1154,10 @@ static int dso__load_sym(struct dso *self, struct map *map,
997 } 1154 }
998 1155
999 if (curr_dso->adjust_symbols) { 1156 if (curr_dso->adjust_symbols) {
1000 pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 1157 pr_debug4("%s: adjusting symbol: st_value: %#Lx "
1001 "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 1158 "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
1002 (u64)shdr.sh_addr, (u64)shdr.sh_offset); 1159 (u64)sym.st_value, (u64)shdr.sh_addr,
1160 (u64)shdr.sh_offset);
1003 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1161 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1004 } 1162 }
1005 /* 1163 /*
@@ -1011,7 +1169,8 @@ static int dso__load_sym(struct dso *self, struct map *map,
1011 if (demangled != NULL) 1169 if (demangled != NULL)
1012 elf_name = demangled; 1170 elf_name = demangled;
1013new_symbol: 1171new_symbol:
1014 f = symbol__new(sym.st_value, sym.st_size, elf_name); 1172 f = symbol__new(sym.st_value, sym.st_size,
1173 GELF_ST_BIND(sym.st_info), elf_name);
1015 free(demangled); 1174 free(demangled);
1016 if (!f) 1175 if (!f)
1017 goto out_elf_end; 1176 goto out_elf_end;
@@ -1027,8 +1186,16 @@ new_symbol:
1027 /* 1186 /*
1028 * For misannotated, zeroed, ASM function sizes. 1187 * For misannotated, zeroed, ASM function sizes.
1029 */ 1188 */
1030 if (nr > 0) 1189 if (nr > 0) {
1031 symbols__fixup_end(&self->symbols[map->type]); 1190 symbols__fixup_end(&self->symbols[map->type]);
1191 if (kmap) {
1192 /*
1193 * We need to fixup this here too because we create new
1194 * maps here, for things like vsyscall sections.
1195 */
1196 __map_groups__fixup_end(kmap->kmaps, map->type);
1197 }
1198 }
1032 err = nr; 1199 err = nr;
1033out_elf_end: 1200out_elf_end:
1034 elf_end(elf); 1201 elf_end(elf);
@@ -1041,64 +1208,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; 1208 return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
1042} 1209}
1043 1210
1044static bool __dsos__read_build_ids(struct list_head *head) 1211bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1045{ 1212{
1046 bool have_build_id = false; 1213 bool have_build_id = false;
1047 struct dso *pos; 1214 struct dso *pos;
1048 1215
1049 list_for_each_entry(pos, head, node) 1216 list_for_each_entry(pos, head, node) {
1217 if (with_hits && !pos->hit)
1218 continue;
1219 if (pos->has_build_id) {
1220 have_build_id = true;
1221 continue;
1222 }
1050 if (filename__read_build_id(pos->long_name, pos->build_id, 1223 if (filename__read_build_id(pos->long_name, pos->build_id,
1051 sizeof(pos->build_id)) > 0) { 1224 sizeof(pos->build_id)) > 0) {
1052 have_build_id = true; 1225 have_build_id = true;
1053 pos->has_build_id = true; 1226 pos->has_build_id = true;
1054 } 1227 }
1228 }
1055 1229
1056 return have_build_id; 1230 return have_build_id;
1057} 1231}
1058 1232
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/* 1233/*
1067 * Align offset to 4 bytes as needed for note name and descriptor data. 1234 * Align offset to 4 bytes as needed for note name and descriptor data.
1068 */ 1235 */
1069#define NOTE_ALIGN(n) (((n) + 3) & -4U) 1236#define NOTE_ALIGN(n) (((n) + 3) & -4U)
1070 1237
1071int filename__read_build_id(const char *filename, void *bf, size_t size) 1238static int elf_read_build_id(Elf *elf, void *bf, size_t size)
1072{ 1239{
1073 int fd, err = -1; 1240 int err = -1;
1074 GElf_Ehdr ehdr; 1241 GElf_Ehdr ehdr;
1075 GElf_Shdr shdr; 1242 GElf_Shdr shdr;
1076 Elf_Data *data; 1243 Elf_Data *data;
1077 Elf_Scn *sec; 1244 Elf_Scn *sec;
1078 Elf_Kind ek; 1245 Elf_Kind ek;
1079 void *ptr; 1246 void *ptr;
1080 Elf *elf;
1081 1247
1082 if (size < BUILD_ID_SIZE) 1248 if (size < BUILD_ID_SIZE)
1083 goto out; 1249 goto out;
1084 1250
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); 1251 ek = elf_kind(elf);
1096 if (ek != ELF_K_ELF) 1252 if (ek != ELF_K_ELF)
1097 goto out_elf_end; 1253 goto out;
1098 1254
1099 if (gelf_getehdr(elf, &ehdr) == NULL) { 1255 if (gelf_getehdr(elf, &ehdr) == NULL) {
1100 pr_err("%s: cannot get elf header.\n", __func__); 1256 pr_err("%s: cannot get elf header.\n", __func__);
1101 goto out_elf_end; 1257 goto out;
1102 } 1258 }
1103 1259
1104 sec = elf_section_by_name(elf, &ehdr, &shdr, 1260 sec = elf_section_by_name(elf, &ehdr, &shdr,
@@ -1107,12 +1263,12 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
1107 sec = elf_section_by_name(elf, &ehdr, &shdr, 1263 sec = elf_section_by_name(elf, &ehdr, &shdr,
1108 ".notes", NULL); 1264 ".notes", NULL);
1109 if (sec == NULL) 1265 if (sec == NULL)
1110 goto out_elf_end; 1266 goto out;
1111 } 1267 }
1112 1268
1113 data = elf_getdata(sec, NULL); 1269 data = elf_getdata(sec, NULL);
1114 if (data == NULL) 1270 if (data == NULL)
1115 goto out_elf_end; 1271 goto out;
1116 1272
1117 ptr = data->d_buf; 1273 ptr = data->d_buf;
1118 while (ptr < (data->d_buf + data->d_size)) { 1274 while (ptr < (data->d_buf + data->d_size)) {
@@ -1134,7 +1290,31 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
1134 } 1290 }
1135 ptr += descsz; 1291 ptr += descsz;
1136 } 1292 }
1137out_elf_end: 1293
1294out:
1295 return err;
1296}
1297
1298int filename__read_build_id(const char *filename, void *bf, size_t size)
1299{
1300 int fd, err = -1;
1301 Elf *elf;
1302
1303 if (size < BUILD_ID_SIZE)
1304 goto out;
1305
1306 fd = open(filename, O_RDONLY);
1307 if (fd < 0)
1308 goto out;
1309
1310 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1311 if (elf == NULL) {
1312 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
1313 goto out_close;
1314 }
1315
1316 err = elf_read_build_id(elf, bf, size);
1317
1138 elf_end(elf); 1318 elf_end(elf);
1139out_close: 1319out_close:
1140 close(fd); 1320 close(fd);
@@ -1191,11 +1371,14 @@ char dso__symtab_origin(const struct dso *self)
1191 static const char origin[] = { 1371 static const char origin[] = {
1192 [DSO__ORIG_KERNEL] = 'k', 1372 [DSO__ORIG_KERNEL] = 'k',
1193 [DSO__ORIG_JAVA_JIT] = 'j', 1373 [DSO__ORIG_JAVA_JIT] = 'j',
1374 [DSO__ORIG_BUILD_ID_CACHE] = 'B',
1194 [DSO__ORIG_FEDORA] = 'f', 1375 [DSO__ORIG_FEDORA] = 'f',
1195 [DSO__ORIG_UBUNTU] = 'u', 1376 [DSO__ORIG_UBUNTU] = 'u',
1196 [DSO__ORIG_BUILDID] = 'b', 1377 [DSO__ORIG_BUILDID] = 'b',
1197 [DSO__ORIG_DSO] = 'd', 1378 [DSO__ORIG_DSO] = 'd',
1198 [DSO__ORIG_KMODULE] = 'K', 1379 [DSO__ORIG_KMODULE] = 'K',
1380 [DSO__ORIG_GUEST_KERNEL] = 'g',
1381 [DSO__ORIG_GUEST_KMODULE] = 'G',
1199 }; 1382 };
1200 1383
1201 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 1384 if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
@@ -1203,19 +1386,27 @@ char dso__symtab_origin(const struct dso *self)
1203 return origin[self->origin]; 1386 return origin[self->origin];
1204} 1387}
1205 1388
1206int dso__load(struct dso *self, struct map *map, struct perf_session *session, 1389int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
1207 symbol_filter_t filter)
1208{ 1390{
1209 int size = PATH_MAX; 1391 int size = PATH_MAX;
1210 char *name; 1392 char *name;
1211 u8 build_id[BUILD_ID_SIZE];
1212 int ret = -1; 1393 int ret = -1;
1213 int fd; 1394 int fd;
1395 struct machine *machine;
1396 const char *root_dir;
1397 int want_symtab;
1214 1398
1215 dso__set_loaded(self, map->type); 1399 dso__set_loaded(self, map->type);
1216 1400
1217 if (self->kernel) 1401 if (self->kernel == DSO_TYPE_KERNEL)
1218 return dso__load_kernel_sym(self, map, session, filter); 1402 return dso__load_kernel_sym(self, map, filter);
1403 else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
1404 return dso__load_guest_kernel_sym(self, map, filter);
1405
1406 if (map->groups && map->groups->machine)
1407 machine = map->groups->machine;
1408 else
1409 machine = NULL;
1219 1410
1220 name = malloc(size); 1411 name = malloc(size);
1221 if (!name) 1412 if (!name)
@@ -1230,12 +1421,18 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session,
1230 return ret; 1421 return ret;
1231 } 1422 }
1232 1423
1233 self->origin = DSO__ORIG_FEDORA - 1; 1424 /* Iterate over candidate debug images.
1234 1425 * On the first pass, only load images if they have a full symtab.
1235more: 1426 * Failing that, do a second pass where we accept .dynsym also
1236 do { 1427 */
1237 self->origin++; 1428 for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
1429 self->origin != DSO__ORIG_NOT_FOUND;
1430 self->origin++) {
1238 switch (self->origin) { 1431 switch (self->origin) {
1432 case DSO__ORIG_BUILD_ID_CACHE:
1433 if (dso__build_id_filename(self, name, size) == NULL)
1434 continue;
1435 break;
1239 case DSO__ORIG_FEDORA: 1436 case DSO__ORIG_FEDORA:
1240 snprintf(name, size, "/usr/lib/debug%s.debug", 1437 snprintf(name, size, "/usr/lib/debug%s.debug",
1241 self->long_name); 1438 self->long_name);
@@ -1244,57 +1441,67 @@ more:
1244 snprintf(name, size, "/usr/lib/debug%s", 1441 snprintf(name, size, "/usr/lib/debug%s",
1245 self->long_name); 1442 self->long_name);
1246 break; 1443 break;
1247 case DSO__ORIG_BUILDID: 1444 case DSO__ORIG_BUILDID: {
1248 if (filename__read_build_id(self->long_name, build_id, 1445 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
1249 sizeof(build_id))) { 1446
1250 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1447 if (!self->has_build_id)
1251 1448 continue;
1252 build_id__sprintf(build_id, sizeof(build_id), 1449
1253 build_id_hex); 1450 build_id__sprintf(self->build_id,
1254 snprintf(name, size, 1451 sizeof(self->build_id),
1255 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1452 build_id_hex);
1256 build_id_hex, build_id_hex + 2); 1453 snprintf(name, size,
1257 if (self->has_build_id) 1454 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1258 goto compare_build_id; 1455 build_id_hex, build_id_hex + 2);
1259 break;
1260 } 1456 }
1261 self->origin++; 1457 break;
1262 /* Fall thru */
1263 case DSO__ORIG_DSO: 1458 case DSO__ORIG_DSO:
1264 snprintf(name, size, "%s", self->long_name); 1459 snprintf(name, size, "%s", self->long_name);
1265 break; 1460 break;
1461 case DSO__ORIG_GUEST_KMODULE:
1462 if (map->groups && map->groups->machine)
1463 root_dir = map->groups->machine->root_dir;
1464 else
1465 root_dir = "";
1466 snprintf(name, size, "%s%s", root_dir, self->long_name);
1467 break;
1266 1468
1267 default: 1469 default:
1268 goto out; 1470 /*
1269 } 1471 * If we wanted a full symtab but no image had one,
1270 1472 * relax our requirements and repeat the search.
1271 if (self->has_build_id) { 1473 */
1272 if (filename__read_build_id(name, build_id, 1474 if (want_symtab) {
1273 sizeof(build_id)) < 0) 1475 want_symtab = 0;
1274 goto more; 1476 self->origin = DSO__ORIG_BUILD_ID_CACHE;
1275compare_build_id: 1477 } else
1276 if (!dso__build_id_equal(self, build_id)) 1478 continue;
1277 goto more;
1278 } 1479 }
1279 1480
1481 /* Name is now the name of the next image to try */
1280 fd = open(name, O_RDONLY); 1482 fd = open(name, O_RDONLY);
1281 } while (fd < 0); 1483 if (fd < 0)
1484 continue;
1282 1485
1283 ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 1486 ret = dso__load_sym(self, map, name, fd, filter, 0,
1284 close(fd); 1487 want_symtab);
1488 close(fd);
1285 1489
1286 /* 1490 /*
1287 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 1491 * Some people seem to have debuginfo files _WITHOUT_ debug
1288 */ 1492 * info!?!?
1289 if (!ret) 1493 */
1290 goto more; 1494 if (!ret)
1495 continue;
1291 1496
1292 if (ret > 0) { 1497 if (ret > 0) {
1293 int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1498 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1294 if (nr_plt > 0) 1499 if (nr_plt > 0)
1295 ret += nr_plt; 1500 ret += nr_plt;
1501 break;
1502 }
1296 } 1503 }
1297out: 1504
1298 free(name); 1505 free(name);
1299 if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 1506 if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
1300 return 0; 1507 return 0;
@@ -1309,35 +1516,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)) { 1516 for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1310 struct map *map = rb_entry(nd, struct map, rb_node); 1517 struct map *map = rb_entry(nd, struct map, rb_node);
1311 1518
1312 if (map->dso && strcmp(map->dso->name, name) == 0) 1519 if (map->dso && strcmp(map->dso->short_name, name) == 0)
1313 return map; 1520 return map;
1314 } 1521 }
1315 1522
1316 return NULL; 1523 return NULL;
1317} 1524}
1318 1525
1319static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 1526static int dso__kernel_module_get_build_id(struct dso *self,
1527 const char *root_dir)
1528{
1529 char filename[PATH_MAX];
1530 /*
1531 * kernel module short names are of the form "[module]" and
1532 * we need just "module" here.
1533 */
1534 const char *name = self->short_name + 1;
1535
1536 snprintf(filename, sizeof(filename),
1537 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1538 root_dir, (int)strlen(name) - 1, name);
1539
1540 if (sysfs__read_build_id(filename, self->build_id,
1541 sizeof(self->build_id)) == 0)
1542 self->has_build_id = true;
1543
1544 return 0;
1545}
1546
1547static int map_groups__set_modules_path_dir(struct map_groups *self,
1548 const char *dir_name)
1320{ 1549{
1321 struct dirent *dent; 1550 struct dirent *dent;
1322 DIR *dir = opendir(dirname); 1551 DIR *dir = opendir(dir_name);
1552 int ret = 0;
1323 1553
1324 if (!dir) { 1554 if (!dir) {
1325 pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1555 pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1326 return -1; 1556 return -1;
1327 } 1557 }
1328 1558
1329 while ((dent = readdir(dir)) != NULL) { 1559 while ((dent = readdir(dir)) != NULL) {
1330 char path[PATH_MAX]; 1560 char path[PATH_MAX];
1561 struct stat st;
1331 1562
1332 if (dent->d_type == DT_DIR) { 1563 /*sshfs might return bad dent->d_type, so we have to stat*/
1564 sprintf(path, "%s/%s", dir_name, dent->d_name);
1565 if (stat(path, &st))
1566 continue;
1567
1568 if (S_ISDIR(st.st_mode)) {
1333 if (!strcmp(dent->d_name, ".") || 1569 if (!strcmp(dent->d_name, ".") ||
1334 !strcmp(dent->d_name, "..")) 1570 !strcmp(dent->d_name, ".."))
1335 continue; 1571 continue;
1336 1572
1337 snprintf(path, sizeof(path), "%s/%s", 1573 snprintf(path, sizeof(path), "%s/%s",
1338 dirname, dent->d_name); 1574 dir_name, dent->d_name);
1339 if (perf_session__set_modules_path_dir(self, path) < 0) 1575 ret = map_groups__set_modules_path_dir(self, path);
1340 goto failure; 1576 if (ret < 0)
1577 goto out;
1341 } else { 1578 } else {
1342 char *dot = strrchr(dent->d_name, '.'), 1579 char *dot = strrchr(dent->d_name, '.'),
1343 dso_name[PATH_MAX]; 1580 dso_name[PATH_MAX];
@@ -1350,38 +1587,70 @@ static int perf_session__set_modules_path_dir(struct perf_session *self, char *d
1350 (int)(dot - dent->d_name), dent->d_name); 1587 (int)(dot - dent->d_name), dent->d_name);
1351 1588
1352 strxfrchar(dso_name, '-', '_'); 1589 strxfrchar(dso_name, '-', '_');
1353 map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); 1590 map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1354 if (map == NULL) 1591 if (map == NULL)
1355 continue; 1592 continue;
1356 1593
1357 snprintf(path, sizeof(path), "%s/%s", 1594 snprintf(path, sizeof(path), "%s/%s",
1358 dirname, dent->d_name); 1595 dir_name, dent->d_name);
1359 1596
1360 long_name = strdup(path); 1597 long_name = strdup(path);
1361 if (long_name == NULL) 1598 if (long_name == NULL) {
1362 goto failure; 1599 ret = -1;
1600 goto out;
1601 }
1363 dso__set_long_name(map->dso, long_name); 1602 dso__set_long_name(map->dso, long_name);
1603 map->dso->lname_alloc = 1;
1604 dso__kernel_module_get_build_id(map->dso, "");
1364 } 1605 }
1365 } 1606 }
1366 1607
1367 return 0; 1608out:
1368failure:
1369 closedir(dir); 1609 closedir(dir);
1370 return -1; 1610 return ret;
1371} 1611}
1372 1612
1373static int perf_session__set_modules_path(struct perf_session *self) 1613static char *get_kernel_version(const char *root_dir)
1374{ 1614{
1375 struct utsname uts; 1615 char version[PATH_MAX];
1616 FILE *file;
1617 char *name, *tmp;
1618 const char *prefix = "Linux version ";
1619
1620 sprintf(version, "%s/proc/version", root_dir);
1621 file = fopen(version, "r");
1622 if (!file)
1623 return NULL;
1624
1625 version[0] = '\0';
1626 tmp = fgets(version, sizeof(version), file);
1627 fclose(file);
1628
1629 name = strstr(version, prefix);
1630 if (!name)
1631 return NULL;
1632 name += strlen(prefix);
1633 tmp = strchr(name, ' ');
1634 if (tmp)
1635 *tmp = '\0';
1636
1637 return strdup(name);
1638}
1639
1640static int machine__set_modules_path(struct machine *self)
1641{
1642 char *version;
1376 char modules_path[PATH_MAX]; 1643 char modules_path[PATH_MAX];
1377 1644
1378 if (uname(&uts) < 0) 1645 version = get_kernel_version(self->root_dir);
1646 if (!version)
1379 return -1; 1647 return -1;
1380 1648
1381 snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1649 snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1382 uts.release); 1650 self->root_dir, version);
1651 free(version);
1383 1652
1384 return perf_session__set_modules_path_dir(self, modules_path); 1653 return map_groups__set_modules_path_dir(&self->kmaps, modules_path);
1385} 1654}
1386 1655
1387/* 1656/*
@@ -1391,8 +1660,8 @@ static int perf_session__set_modules_path(struct perf_session *self)
1391 */ 1660 */
1392static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1661static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1393{ 1662{
1394 struct map *self = malloc(sizeof(*self)); 1663 struct map *self = calloc(1, (sizeof(*self) +
1395 1664 (dso->kernel ? sizeof(struct kmap) : 0)));
1396 if (self != NULL) { 1665 if (self != NULL) {
1397 /* 1666 /*
1398 * ->end will be filled after we load all the symbols 1667 * ->end will be filled after we load all the symbols
@@ -1403,20 +1672,50 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1403 return self; 1672 return self;
1404} 1673}
1405 1674
1406static int perf_session__create_module_maps(struct perf_session *self) 1675struct map *machine__new_module(struct machine *self, u64 start,
1676 const char *filename)
1677{
1678 struct map *map;
1679 struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename);
1680
1681 if (dso == NULL)
1682 return NULL;
1683
1684 map = map__new2(start, dso, MAP__FUNCTION);
1685 if (map == NULL)
1686 return NULL;
1687
1688 if (machine__is_host(self))
1689 dso->origin = DSO__ORIG_KMODULE;
1690 else
1691 dso->origin = DSO__ORIG_GUEST_KMODULE;
1692 map_groups__insert(&self->kmaps, map);
1693 return map;
1694}
1695
1696static int machine__create_modules(struct machine *self)
1407{ 1697{
1408 char *line = NULL; 1698 char *line = NULL;
1409 size_t n; 1699 size_t n;
1410 FILE *file = fopen("/proc/modules", "r"); 1700 FILE *file;
1411 struct map *map; 1701 struct map *map;
1702 const char *modules;
1703 char path[PATH_MAX];
1704
1705 if (machine__is_default_guest(self))
1706 modules = symbol_conf.default_guest_modules;
1707 else {
1708 sprintf(path, "%s/proc/modules", self->root_dir);
1709 modules = path;
1710 }
1412 1711
1712 file = fopen(modules, "r");
1413 if (file == NULL) 1713 if (file == NULL)
1414 return -1; 1714 return -1;
1415 1715
1416 while (!feof(file)) { 1716 while (!feof(file)) {
1417 char name[PATH_MAX]; 1717 char name[PATH_MAX];
1418 u64 start; 1718 u64 start;
1419 struct dso *dso;
1420 char *sep; 1719 char *sep;
1421 int line_len; 1720 int line_len;
1422 1721
@@ -1442,32 +1741,16 @@ static int perf_session__create_module_maps(struct perf_session *self)
1442 *sep = '\0'; 1741 *sep = '\0';
1443 1742
1444 snprintf(name, sizeof(name), "[%s]", line); 1743 snprintf(name, sizeof(name), "[%s]", line);
1445 dso = dso__new(name); 1744 map = machine__new_module(self, start, name);
1446 1745 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; 1746 goto out_delete_line;
1454 } 1747 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 } 1748 }
1466 1749
1467 free(line); 1750 free(line);
1468 fclose(file); 1751 fclose(file);
1469 1752
1470 return perf_session__set_modules_path(self); 1753 return machine__set_modules_path(self);
1471 1754
1472out_delete_line: 1755out_delete_line:
1473 free(line); 1756 free(line);
@@ -1476,85 +1759,148 @@ out_failure:
1476} 1759}
1477 1760
1478static int dso__load_vmlinux(struct dso *self, struct map *map, 1761static int dso__load_vmlinux(struct dso *self, struct map *map,
1479 struct perf_session *session,
1480 const char *vmlinux, symbol_filter_t filter) 1762 const char *vmlinux, symbol_filter_t filter)
1481{ 1763{
1482 int err = -1, fd; 1764 int err = -1, fd;
1483 1765
1484 if (self->has_build_id) {
1485 u8 build_id[BUILD_ID_SIZE];
1486
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); 1766 fd = open(vmlinux, O_RDONLY);
1509 if (fd < 0) 1767 if (fd < 0)
1510 return -1; 1768 return -1;
1511 1769
1512 dso__set_loaded(self, map->type); 1770 dso__set_loaded(self, map->type);
1513 err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); 1771 err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
1514 close(fd); 1772 close(fd);
1515 1773
1774 if (err > 0)
1775 pr_debug("Using %s for symbols\n", vmlinux);
1776
1777 return err;
1778}
1779
1780int dso__load_vmlinux_path(struct dso *self, struct map *map,
1781 symbol_filter_t filter)
1782{
1783 int i, err = 0;
1784 char *filename;
1785
1786 pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1787 vmlinux_path__nr_entries + 1);
1788
1789 filename = dso__build_id_filename(self, NULL, 0);
1790 if (filename != NULL) {
1791 err = dso__load_vmlinux(self, map, filename, filter);
1792 if (err > 0) {
1793 dso__set_long_name(self, filename);
1794 goto out;
1795 }
1796 free(filename);
1797 }
1798
1799 for (i = 0; i < vmlinux_path__nr_entries; ++i) {
1800 err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1801 if (err > 0) {
1802 dso__set_long_name(self, strdup(vmlinux_path[i]));
1803 break;
1804 }
1805 }
1806out:
1516 return err; 1807 return err;
1517} 1808}
1518 1809
1519static int dso__load_kernel_sym(struct dso *self, struct map *map, 1810static int dso__load_kernel_sym(struct dso *self, struct map *map,
1520 struct perf_session *session, symbol_filter_t filter) 1811 symbol_filter_t filter)
1521{ 1812{
1522 int err; 1813 int err;
1523 bool is_kallsyms; 1814 const char *kallsyms_filename = NULL;
1815 char *kallsyms_allocated_filename = NULL;
1816 /*
1817 * Step 1: if the user specified a vmlinux filename, use it and only
1818 * it, reporting errors to the user if it cannot be used.
1819 *
1820 * For instance, try to analyse an ARM perf.data file _without_ a
1821 * build-id, or if the user specifies the wrong path to the right
1822 * vmlinux file, obviously we can't fallback to another vmlinux (a
1823 * x86_86 one, on the machine where analysis is being performed, say),
1824 * or worse, /proc/kallsyms.
1825 *
1826 * If the specified file _has_ a build-id and there is a build-id
1827 * section in the perf.data file, we will still do the expected
1828 * validation in dso__load_vmlinux and will bail out if they don't
1829 * match.
1830 */
1831 if (symbol_conf.vmlinux_name != NULL) {
1832 err = dso__load_vmlinux(self, map,
1833 symbol_conf.vmlinux_name, filter);
1834 if (err > 0) {
1835 dso__set_long_name(self,
1836 strdup(symbol_conf.vmlinux_name));
1837 goto out_fixup;
1838 }
1839 return err;
1840 }
1524 1841
1525 if (vmlinux_path != NULL) { 1842 if (vmlinux_path != NULL) {
1526 int i; 1843 err = dso__load_vmlinux_path(self, map, filter);
1527 pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1844 if (err > 0)
1528 vmlinux_path__nr_entries); 1845 goto out_fixup;
1529 for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1846 }
1530 err = dso__load_vmlinux(self, map, session, 1847
1531 vmlinux_path[i], filter); 1848 /*
1532 if (err > 0) { 1849 * Say the kernel DSO was created when processing the build-id header table,
1533 pr_debug("Using %s for symbols\n", 1850 * we have a build-id, so check if it is the same as the running kernel,
1534 vmlinux_path[i]); 1851 * using it if it is.
1535 dso__set_long_name(self, 1852 */
1536 strdup(vmlinux_path[i])); 1853 if (self->has_build_id) {
1537 goto out_fixup; 1854 u8 kallsyms_build_id[BUILD_ID_SIZE];
1855 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1856
1857 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1858 sizeof(kallsyms_build_id)) == 0) {
1859 if (dso__build_id_equal(self, kallsyms_build_id)) {
1860 kallsyms_filename = "/proc/kallsyms";
1861 goto do_kallsyms;
1538 } 1862 }
1539 } 1863 }
1540 } 1864 /*
1865 * Now look if we have it on the build-id cache in
1866 * $HOME/.debug/[kernel.kallsyms].
1867 */
1868 build_id__sprintf(self->build_id, sizeof(self->build_id),
1869 sbuild_id);
1541 1870
1542 is_kallsyms = self->long_name[0] == '['; 1871 if (asprintf(&kallsyms_allocated_filename,
1543 if (is_kallsyms) 1872 "%s/.debug/[kernel.kallsyms]/%s",
1544 goto do_kallsyms; 1873 getenv("HOME"), sbuild_id) == -1) {
1874 pr_err("Not enough memory for kallsyms file lookup\n");
1875 return -1;
1876 }
1545 1877
1546 err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1878 kallsyms_filename = kallsyms_allocated_filename;
1547 if (err <= 0) { 1879
1548 pr_info("The file %s cannot be used, " 1880 if (access(kallsyms_filename, F_OK)) {
1549 "trying to use /proc/kallsyms...", self->long_name); 1881 pr_err("No kallsyms or vmlinux with build-id %s "
1550do_kallsyms: 1882 "was found\n", sbuild_id);
1551 err = dso__load_kallsyms(self, map, session, filter); 1883 free(kallsyms_allocated_filename);
1552 if (err > 0 && !is_kallsyms) 1884 return -1;
1553 dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1885 }
1886 } else {
1887 /*
1888 * Last resort, if we don't have a build-id and couldn't find
1889 * any vmlinux file, try the running kernel kallsyms table.
1890 */
1891 kallsyms_filename = "/proc/kallsyms";
1554 } 1892 }
1555 1893
1894do_kallsyms:
1895 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1896 if (err > 0)
1897 pr_debug("Using %s for symbols\n", kallsyms_filename);
1898 free(kallsyms_allocated_filename);
1899
1556 if (err > 0) { 1900 if (err > 0) {
1557out_fixup: 1901out_fixup:
1902 if (kallsyms_filename != NULL)
1903 dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1558 map__fixup_start(map); 1904 map__fixup_start(map);
1559 map__fixup_end(map); 1905 map__fixup_end(map);
1560 } 1906 }
@@ -1562,9 +1908,56 @@ out_fixup:
1562 return err; 1908 return err;
1563} 1909}
1564 1910
1565LIST_HEAD(dsos__user); 1911static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1566LIST_HEAD(dsos__kernel); 1912 symbol_filter_t filter)
1567struct dso *vdso; 1913{
1914 int err;
1915 const char *kallsyms_filename = NULL;
1916 struct machine *machine;
1917 char path[PATH_MAX];
1918
1919 if (!map->groups) {
1920 pr_debug("Guest kernel map hasn't the point to groups\n");
1921 return -1;
1922 }
1923 machine = map->groups->machine;
1924
1925 if (machine__is_default_guest(machine)) {
1926 /*
1927 * if the user specified a vmlinux filename, use it and only
1928 * it, reporting errors to the user if it cannot be used.
1929 * Or use file guest_kallsyms inputted by user on commandline
1930 */
1931 if (symbol_conf.default_guest_vmlinux_name != NULL) {
1932 err = dso__load_vmlinux(self, map,
1933 symbol_conf.default_guest_vmlinux_name, filter);
1934 goto out_try_fixup;
1935 }
1936
1937 kallsyms_filename = symbol_conf.default_guest_kallsyms;
1938 if (!kallsyms_filename)
1939 return -1;
1940 } else {
1941 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1942 kallsyms_filename = path;
1943 }
1944
1945 err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1946 if (err > 0)
1947 pr_debug("Using %s for symbols\n", kallsyms_filename);
1948
1949out_try_fixup:
1950 if (err > 0) {
1951 if (kallsyms_filename != NULL) {
1952 machine__mmap_name(machine, path, sizeof(path));
1953 dso__set_long_name(self, strdup(path));
1954 }
1955 map__fixup_start(map);
1956 map__fixup_end(map);
1957 }
1958
1959 return err;
1960}
1568 1961
1569static void dsos__add(struct list_head *head, struct dso *dso) 1962static void dsos__add(struct list_head *head, struct dso *dso)
1570{ 1963{
@@ -1576,19 +1969,19 @@ static struct dso *dsos__find(struct list_head *head, const char *name)
1576 struct dso *pos; 1969 struct dso *pos;
1577 1970
1578 list_for_each_entry(pos, head, node) 1971 list_for_each_entry(pos, head, node)
1579 if (strcmp(pos->name, name) == 0) 1972 if (strcmp(pos->long_name, name) == 0)
1580 return pos; 1973 return pos;
1581 return NULL; 1974 return NULL;
1582} 1975}
1583 1976
1584struct dso *dsos__findnew(const char *name) 1977struct dso *__dsos__findnew(struct list_head *head, const char *name)
1585{ 1978{
1586 struct dso *dso = dsos__find(&dsos__user, name); 1979 struct dso *dso = dsos__find(head, name);
1587 1980
1588 if (!dso) { 1981 if (!dso) {
1589 dso = dso__new(name); 1982 dso = dso__new(name);
1590 if (dso != NULL) { 1983 if (dso != NULL) {
1591 dsos__add(&dsos__user, dso); 1984 dsos__add(head, dso);
1592 dso__set_basename(dso); 1985 dso__set_basename(dso);
1593 } 1986 }
1594 } 1987 }
@@ -1596,93 +1989,192 @@ struct dso *dsos__findnew(const char *name)
1596 return dso; 1989 return dso;
1597} 1990}
1598 1991
1599static void __dsos__fprintf(struct list_head *head, FILE *fp) 1992size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1600{ 1993{
1601 struct dso *pos; 1994 struct dso *pos;
1995 size_t ret = 0;
1602 1996
1603 list_for_each_entry(pos, head, node) { 1997 list_for_each_entry(pos, head, node) {
1604 int i; 1998 int i;
1605 for (i = 0; i < MAP__NR_TYPES; ++i) 1999 for (i = 0; i < MAP__NR_TYPES; ++i)
1606 dso__fprintf(pos, i, fp); 2000 ret += dso__fprintf(pos, i, fp);
1607 } 2001 }
2002
2003 return ret;
1608} 2004}
1609 2005
1610void dsos__fprintf(FILE *fp) 2006size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp)
1611{ 2007{
1612 __dsos__fprintf(&dsos__kernel, fp); 2008 struct rb_node *nd;
1613 __dsos__fprintf(&dsos__user, fp); 2009 size_t ret = 0;
2010
2011 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
2012 struct machine *pos = rb_entry(nd, struct machine, rb_node);
2013 ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2014 ret += __dsos__fprintf(&pos->user_dsos, fp);
2015 }
2016
2017 return ret;
1614} 2018}
1615 2019
1616static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 2020static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
2021 bool with_hits)
1617{ 2022{
1618 struct dso *pos; 2023 struct dso *pos;
1619 size_t ret = 0; 2024 size_t ret = 0;
1620 2025
1621 list_for_each_entry(pos, head, node) { 2026 list_for_each_entry(pos, head, node) {
2027 if (with_hits && !pos->hit)
2028 continue;
1622 ret += dso__fprintf_buildid(pos, fp); 2029 ret += dso__fprintf_buildid(pos, fp);
1623 ret += fprintf(fp, " %s\n", pos->long_name); 2030 ret += fprintf(fp, " %s\n", pos->long_name);
1624 } 2031 }
1625 return ret; 2032 return ret;
1626} 2033}
1627 2034
1628size_t dsos__fprintf_buildid(FILE *fp) 2035size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits)
1629{ 2036{
1630 return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 2037 return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) +
1631 __dsos__fprintf_buildid(&dsos__user, fp)); 2038 __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits);
1632} 2039}
1633 2040
1634static struct dso *dsos__create_kernel( const char *vmlinux) 2041size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
1635{ 2042{
1636 struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 2043 struct rb_node *nd;
2044 size_t ret = 0;
1637 2045
1638 if (kernel == NULL) 2046 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
1639 return NULL; 2047 struct machine *pos = rb_entry(nd, struct machine, rb_node);
2048 ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2049 }
2050 return ret;
2051}
2052
2053struct dso *dso__new_kernel(const char *name)
2054{
2055 struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
2056
2057 if (self != NULL) {
2058 dso__set_short_name(self, "[kernel]");
2059 self->kernel = DSO_TYPE_KERNEL;
2060 }
2061
2062 return self;
2063}
2064
2065static struct dso *dso__new_guest_kernel(struct machine *machine,
2066 const char *name)
2067{
2068 char bf[PATH_MAX];
2069 struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf)));
2070
2071 if (self != NULL) {
2072 dso__set_short_name(self, "[guest.kernel]");
2073 self->kernel = DSO_TYPE_GUEST_KERNEL;
2074 }
2075
2076 return self;
2077}
1640 2078
1641 kernel->short_name = "[kernel]"; 2079void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine)
1642 kernel->kernel = 1; 2080{
2081 char path[PATH_MAX];
1643 2082
1644 vdso = dso__new("[vdso]"); 2083 if (machine__is_default_guest(machine))
1645 if (vdso == NULL) 2084 return;
1646 goto out_delete_kernel_dso; 2085 sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
1647 dso__set_loaded(vdso, MAP__FUNCTION); 2086 if (sysfs__read_build_id(path, self->build_id,
2087 sizeof(self->build_id)) == 0)
2088 self->has_build_id = true;
2089}
1648 2090
1649 if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 2091static struct dso *machine__create_kernel(struct machine *self)
1650 sizeof(kernel->build_id)) == 0) 2092{
1651 kernel->has_build_id = true; 2093 const char *vmlinux_name = NULL;
2094 struct dso *kernel;
1652 2095
1653 dsos__add(&dsos__kernel, kernel); 2096 if (machine__is_host(self)) {
1654 dsos__add(&dsos__user, vdso); 2097 vmlinux_name = symbol_conf.vmlinux_name;
2098 kernel = dso__new_kernel(vmlinux_name);
2099 } else {
2100 if (machine__is_default_guest(self))
2101 vmlinux_name = symbol_conf.default_guest_vmlinux_name;
2102 kernel = dso__new_guest_kernel(self, vmlinux_name);
2103 }
1655 2104
2105 if (kernel != NULL) {
2106 dso__read_running_kernel_build_id(kernel, self);
2107 dsos__add(&self->kernel_dsos, kernel);
2108 }
1656 return kernel; 2109 return kernel;
2110}
1657 2111
1658out_delete_kernel_dso: 2112int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
1659 dso__delete(kernel); 2113{
1660 return NULL; 2114 enum map_type type;
2115
2116 for (type = 0; type < MAP__NR_TYPES; ++type) {
2117 struct kmap *kmap;
2118
2119 self->vmlinux_maps[type] = map__new2(0, kernel, type);
2120 if (self->vmlinux_maps[type] == NULL)
2121 return -1;
2122
2123 self->vmlinux_maps[type]->map_ip =
2124 self->vmlinux_maps[type]->unmap_ip = identity__map_ip;
2125
2126 kmap = map__kmap(self->vmlinux_maps[type]);
2127 kmap->kmaps = &self->kmaps;
2128 map_groups__insert(&self->kmaps, self->vmlinux_maps[type]);
2129 }
2130
2131 return 0;
1661} 2132}
1662 2133
1663static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) 2134void machine__destroy_kernel_maps(struct machine *self)
1664{ 2135{
1665 struct map *functions, *variables; 2136 enum map_type type;
1666 struct dso *kernel = dsos__create_kernel(vmlinux);
1667 2137
1668 if (kernel == NULL) 2138 for (type = 0; type < MAP__NR_TYPES; ++type) {
1669 return -1; 2139 struct kmap *kmap;
1670 2140
1671 functions = map__new2(0, kernel, MAP__FUNCTION); 2141 if (self->vmlinux_maps[type] == NULL)
1672 if (functions == NULL) 2142 continue;
1673 return -1;
1674 2143
1675 variables = map__new2(0, kernel, MAP__VARIABLE); 2144 kmap = map__kmap(self->vmlinux_maps[type]);
1676 if (variables == NULL) { 2145 map_groups__remove(&self->kmaps, self->vmlinux_maps[type]);
1677 map__delete(functions); 2146 if (kmap->ref_reloc_sym) {
1678 return -1; 2147 /*
2148 * ref_reloc_sym is shared among all maps, so free just
2149 * on one of them.
2150 */
2151 if (type == MAP__FUNCTION) {
2152 free((char *)kmap->ref_reloc_sym->name);
2153 kmap->ref_reloc_sym->name = NULL;
2154 free(kmap->ref_reloc_sym);
2155 }
2156 kmap->ref_reloc_sym = NULL;
2157 }
2158
2159 map__delete(self->vmlinux_maps[type]);
2160 self->vmlinux_maps[type] = NULL;
1679 } 2161 }
2162}
1680 2163
1681 functions->map_ip = functions->unmap_ip = 2164int machine__create_kernel_maps(struct machine *self)
1682 variables->map_ip = variables->unmap_ip = identity__map_ip; 2165{
1683 map_groups__insert(self, functions); 2166 struct dso *kernel = machine__create_kernel(self);
1684 map_groups__insert(self, variables); 2167
2168 if (kernel == NULL ||
2169 __machine__create_kernel_maps(self, kernel) < 0)
2170 return -1;
1685 2171
2172 if (symbol_conf.use_modules && machine__create_modules(self) < 0)
2173 pr_debug("Problems creating module maps, continuing anyway...\n");
2174 /*
2175 * Now that we have all the maps created, just set the ->end of them:
2176 */
2177 map_groups__fixup_end(&self->kmaps);
1686 return 0; 2178 return 0;
1687} 2179}
1688 2180
@@ -1741,6 +2233,25 @@ out_fail:
1741 return -1; 2233 return -1;
1742} 2234}
1743 2235
2236size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp)
2237{
2238 int i;
2239 size_t printed = 0;
2240 struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso;
2241
2242 if (kdso->has_build_id) {
2243 char filename[PATH_MAX];
2244 if (dso__build_id_filename(kdso, filename, sizeof(filename)))
2245 printed += fprintf(fp, "[0] %s\n", filename);
2246 }
2247
2248 for (i = 0; i < vmlinux_path__nr_entries; ++i)
2249 printed += fprintf(fp, "[%d] %s\n",
2250 i + kdso->has_build_id, vmlinux_path[i]);
2251
2252 return printed;
2253}
2254
1744static int setup_list(struct strlist **list, const char *list_str, 2255static int setup_list(struct strlist **list, const char *list_str,
1745 const char *list_name) 2256 const char *list_name)
1746{ 2257{
@@ -1757,6 +2268,9 @@ static int setup_list(struct strlist **list, const char *list_str,
1757 2268
1758int symbol__init(void) 2269int symbol__init(void)
1759{ 2270{
2271 if (symbol_conf.initialized)
2272 return 0;
2273
1760 elf_version(EV_CURRENT); 2274 elf_version(EV_CURRENT);
1761 if (symbol_conf.sort_by_name) 2275 if (symbol_conf.sort_by_name)
1762 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 2276 symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
@@ -1782,6 +2296,7 @@ int symbol__init(void)
1782 symbol_conf.sym_list_str, "symbol") < 0) 2296 symbol_conf.sym_list_str, "symbol") < 0)
1783 goto out_free_comm_list; 2297 goto out_free_comm_list;
1784 2298
2299 symbol_conf.initialized = true;
1785 return 0; 2300 return 0;
1786 2301
1787out_free_dso_list: 2302out_free_dso_list:
@@ -1791,19 +2306,154 @@ out_free_comm_list:
1791 return -1; 2306 return -1;
1792} 2307}
1793 2308
1794int perf_session__create_kernel_maps(struct perf_session *self) 2309void symbol__exit(void)
2310{
2311 if (!symbol_conf.initialized)
2312 return;
2313 strlist__delete(symbol_conf.sym_list);
2314 strlist__delete(symbol_conf.dso_list);
2315 strlist__delete(symbol_conf.comm_list);
2316 vmlinux_path__exit();
2317 symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
2318 symbol_conf.initialized = false;
2319}
2320
2321int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
1795{ 2322{
1796 if (map_groups__create_kernel_maps(&self->kmaps, 2323 struct machine *machine = machines__findnew(self, pid);
1797 symbol_conf.vmlinux_name) < 0) 2324
2325 if (machine == NULL)
1798 return -1; 2326 return -1;
1799 2327
1800 if (symbol_conf.use_modules && 2328 return machine__create_kernel_maps(machine);
1801 perf_session__create_module_maps(self) < 0) 2329}
1802 pr_debug("Failed to load list of modules for session %s, " 2330
1803 "continuing...\n", self->filename); 2331static int hex(char ch)
1804 /* 2332{
1805 * Now that we have all the maps created, just set the ->end of them: 2333 if ((ch >= '0') && (ch <= '9'))
1806 */ 2334 return ch - '0';
1807 map_groups__fixup_end(&self->kmaps); 2335 if ((ch >= 'a') && (ch <= 'f'))
1808 return 0; 2336 return ch - 'a' + 10;
2337 if ((ch >= 'A') && (ch <= 'F'))
2338 return ch - 'A' + 10;
2339 return -1;
2340}
2341
2342/*
2343 * While we find nice hex chars, build a long_val.
2344 * Return number of chars processed.
2345 */
2346int hex2u64(const char *ptr, u64 *long_val)
2347{
2348 const char *p = ptr;
2349 *long_val = 0;
2350
2351 while (*p) {
2352 const int hex_val = hex(*p);
2353
2354 if (hex_val < 0)
2355 break;
2356
2357 *long_val = (*long_val << 4) | hex_val;
2358 p++;
2359 }
2360
2361 return p - ptr;
2362}
2363
2364char *strxfrchar(char *s, char from, char to)
2365{
2366 char *p = s;
2367
2368 while ((p = strchr(p, from)) != NULL)
2369 *p++ = to;
2370
2371 return s;
2372}
2373
2374int machines__create_guest_kernel_maps(struct rb_root *self)
2375{
2376 int ret = 0;
2377 struct dirent **namelist = NULL;
2378 int i, items = 0;
2379 char path[PATH_MAX];
2380 pid_t pid;
2381
2382 if (symbol_conf.default_guest_vmlinux_name ||
2383 symbol_conf.default_guest_modules ||
2384 symbol_conf.default_guest_kallsyms) {
2385 machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID);
2386 }
2387
2388 if (symbol_conf.guestmount) {
2389 items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2390 if (items <= 0)
2391 return -ENOENT;
2392 for (i = 0; i < items; i++) {
2393 if (!isdigit(namelist[i]->d_name[0])) {
2394 /* Filter out . and .. */
2395 continue;
2396 }
2397 pid = atoi(namelist[i]->d_name);
2398 sprintf(path, "%s/%s/proc/kallsyms",
2399 symbol_conf.guestmount,
2400 namelist[i]->d_name);
2401 ret = access(path, R_OK);
2402 if (ret) {
2403 pr_debug("Can't access file %s\n", path);
2404 goto failure;
2405 }
2406 machines__create_kernel_maps(self, pid);
2407 }
2408failure:
2409 free(namelist);
2410 }
2411
2412 return ret;
2413}
2414
2415void machines__destroy_guest_kernel_maps(struct rb_root *self)
2416{
2417 struct rb_node *next = rb_first(self);
2418
2419 while (next) {
2420 struct machine *pos = rb_entry(next, struct machine, rb_node);
2421
2422 next = rb_next(&pos->rb_node);
2423 rb_erase(&pos->rb_node, self);
2424 machine__delete(pos);
2425 }
2426}
2427
2428int machine__load_kallsyms(struct machine *self, const char *filename,
2429 enum map_type type, symbol_filter_t filter)
2430{
2431 struct map *map = self->vmlinux_maps[type];
2432 int ret = dso__load_kallsyms(map->dso, filename, map, filter);
2433
2434 if (ret > 0) {
2435 dso__set_loaded(map->dso, type);
2436 /*
2437 * Since /proc/kallsyms will have multiple sessions for the
2438 * kernel, with modules between them, fixup the end of all
2439 * sections.
2440 */
2441 __map_groups__fixup_end(&self->kmaps, type);
2442 }
2443
2444 return ret;
2445}
2446
2447int machine__load_vmlinux_path(struct machine *self, enum map_type type,
2448 symbol_filter_t filter)
2449{
2450 struct map *map = self->vmlinux_maps[type];
2451 int ret = dso__load_vmlinux_path(map->dso, map, filter);
2452
2453 if (ret > 0) {
2454 dso__set_loaded(map->dso, type);
2455 map__reloc_vmlinux(map);
2456 }
2457
2458 return ret;
1809} 2459}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 8aded2356f79..ea95c2756f05 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,10 +68,17 @@ 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 *source_prefix,
63 *field_sep; 76 *field_sep;
64 char *dso_list_str, 77 const char *default_guest_vmlinux_name,
78 *default_guest_kallsyms,
79 *default_guest_modules;
80 const char *guestmount;
81 const char *dso_list_str,
65 *comm_list_str, 82 *comm_list_str,
66 *sym_list_str, 83 *sym_list_str,
67 *col_width_list_str; 84 *col_width_list_str;
@@ -77,6 +94,19 @@ static inline void *symbol__priv(struct symbol *self)
77 return ((void *)self) - symbol_conf.priv_size; 94 return ((void *)self) - symbol_conf.priv_size;
78} 95}
79 96
97struct ref_reloc_sym {
98 const char *name;
99 u64 addr;
100 u64 unrelocated_addr;
101};
102
103struct map_symbol {
104 struct map *map;
105 struct symbol *sym;
106 bool unfolded;
107 bool has_children;
108};
109
80struct addr_location { 110struct addr_location {
81 struct thread *thread; 111 struct thread *thread;
82 struct map *map; 112 struct map *map;
@@ -84,58 +114,118 @@ struct addr_location {
84 u64 addr; 114 u64 addr;
85 char level; 115 char level;
86 bool filtered; 116 bool filtered;
117 u8 cpumode;
118 s32 cpu;
119};
120
121enum dso_kernel_type {
122 DSO_TYPE_USER = 0,
123 DSO_TYPE_KERNEL,
124 DSO_TYPE_GUEST_KERNEL
87}; 125};
88 126
89struct dso { 127struct dso {
90 struct list_head node; 128 struct list_head node;
91 struct rb_root symbols[MAP__NR_TYPES]; 129 struct rb_root symbols[MAP__NR_TYPES];
92 struct rb_root symbol_names[MAP__NR_TYPES]; 130 struct rb_root symbol_names[MAP__NR_TYPES];
131 enum dso_kernel_type kernel;
93 u8 adjust_symbols:1; 132 u8 adjust_symbols:1;
94 u8 slen_calculated:1; 133 u8 slen_calculated:1;
95 u8 has_build_id:1; 134 u8 has_build_id:1;
96 u8 kernel:1; 135 u8 hit:1;
136 u8 annotate_warned:1;
137 u8 sname_alloc:1;
138 u8 lname_alloc:1;
97 unsigned char origin; 139 unsigned char origin;
98 u8 sorted_by_name; 140 u8 sorted_by_name;
99 u8 loaded; 141 u8 loaded;
100 u8 build_id[BUILD_ID_SIZE]; 142 u8 build_id[BUILD_ID_SIZE];
101 u16 long_name_len;
102 const char *short_name; 143 const char *short_name;
103 char *long_name; 144 char *long_name;
145 u16 long_name_len;
146 u16 short_name_len;
104 char name[0]; 147 char name[0];
105}; 148};
106 149
107struct dso *dso__new(const char *name); 150struct dso *dso__new(const char *name);
151struct dso *dso__new_kernel(const char *name);
108void dso__delete(struct dso *self); 152void dso__delete(struct dso *self);
109 153
154int dso__name_len(const struct dso *self);
155
110bool dso__loaded(const struct dso *self, enum map_type type); 156bool dso__loaded(const struct dso *self, enum map_type type);
111bool dso__sorted_by_name(const struct dso *self, enum map_type type); 157bool dso__sorted_by_name(const struct dso *self, enum map_type type);
112 158
159static inline void dso__set_loaded(struct dso *self, enum map_type type)
160{
161 self->loaded |= (1 << type);
162}
163
113void dso__sort_by_name(struct dso *self, enum map_type type); 164void dso__sort_by_name(struct dso *self, enum map_type type);
114 165
115struct perf_session; 166struct dso *__dsos__findnew(struct list_head *head, const char *name);
167
168int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
169int dso__load_vmlinux_path(struct dso *self, struct map *map,
170 symbol_filter_t filter);
171int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
172 symbol_filter_t filter);
173int machine__load_kallsyms(struct machine *self, const char *filename,
174 enum map_type type, symbol_filter_t filter);
175int machine__load_vmlinux_path(struct machine *self, enum map_type type,
176 symbol_filter_t filter);
177
178size_t __dsos__fprintf(struct list_head *head, FILE *fp);
116 179
117struct dso *dsos__findnew(const char *name); 180size_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, 181size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp);
119 symbol_filter_t filter); 182size_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 183
123size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 184size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
124size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 185size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
186
187enum dso_origin {
188 DSO__ORIG_KERNEL = 0,
189 DSO__ORIG_GUEST_KERNEL,
190 DSO__ORIG_JAVA_JIT,
191 DSO__ORIG_BUILD_ID_CACHE,
192 DSO__ORIG_FEDORA,
193 DSO__ORIG_UBUNTU,
194 DSO__ORIG_BUILDID,
195 DSO__ORIG_DSO,
196 DSO__ORIG_GUEST_KMODULE,
197 DSO__ORIG_KMODULE,
198 DSO__ORIG_NOT_FOUND,
199};
200
125char dso__symtab_origin(const struct dso *self); 201char dso__symtab_origin(const struct dso *self);
202void dso__set_long_name(struct dso *self, char *name);
126void dso__set_build_id(struct dso *self, void *build_id); 203void dso__set_build_id(struct dso *self, void *build_id);
204void 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); 205struct 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, 206struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
129 const char *name); 207 const char *name);
130 208
131int filename__read_build_id(const char *filename, void *bf, size_t size); 209int 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); 210int sysfs__read_build_id(const char *filename, void *bf, size_t size);
133bool dsos__read_build_ids(void); 211bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
134int build_id__sprintf(u8 *self, int len, char *bf); 212int build_id__sprintf(const u8 *self, int len, char *bf);
213int kallsyms__parse(const char *filename, void *arg,
214 int (*process_symbol)(void *arg, const char *name,
215 char type, u64 start));
216
217void machine__destroy_kernel_maps(struct machine *self);
218int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);
219int machine__create_kernel_maps(struct machine *self);
220
221int machines__create_kernel_maps(struct rb_root *self, pid_t pid);
222int machines__create_guest_kernel_maps(struct rb_root *self);
223void machines__destroy_guest_kernel_maps(struct rb_root *self);
135 224
136int symbol__init(void); 225int symbol__init(void);
137int perf_session__create_kernel_maps(struct perf_session *self); 226void symbol__exit(void);
227bool symbol_type__is_a(char symbol_type, enum map_type map_type);
228
229size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp);
138 230
139extern struct list_head dsos__user, dsos__kernel;
140extern struct dso *vdso;
141#endif /* __PERF_SYMBOL */ 231#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 4a08dcf50b68..8c72d888e449 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -7,13 +7,44 @@
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
19int find_all_tid(int pid, pid_t ** all_tid)
20{
21 char name[256];
22 int items;
23 struct dirent **namelist = NULL;
24 int ret = 0;
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 -ENOENT;
31 *all_tid = malloc(sizeof(pid_t) * items);
32 if (!*all_tid) {
33 ret = -ENOMEM;
34 goto failure;
16 } 35 }
36
37 for (i = 0; i < items; i++)
38 (*all_tid)[i] = atoi(namelist[i]->d_name);
39
40 ret = items;
41
42failure:
43 for (i=0; i<items; i++)
44 free(namelist[i]);
45 free(namelist);
46
47 return ret;
17} 48}
18 49
19static struct thread *thread__new(pid_t pid) 50static struct thread *thread__new(pid_t pid)
@@ -31,12 +62,26 @@ static struct thread *thread__new(pid_t pid)
31 return self; 62 return self;
32} 63}
33 64
65void thread__delete(struct thread *self)
66{
67 map_groups__exit(&self->mg);
68 free(self->comm);
69 free(self);
70}
71
34int thread__set_comm(struct thread *self, const char *comm) 72int thread__set_comm(struct thread *self, const char *comm)
35{ 73{
74 int err;
75
36 if (self->comm) 76 if (self->comm)
37 free(self->comm); 77 free(self->comm);
38 self->comm = strdup(comm); 78 self->comm = strdup(comm);
39 return self->comm ? 0 : -ENOMEM; 79 err = self->comm == NULL ? -ENOMEM : 0;
80 if (!err) {
81 self->comm_set = true;
82 map_groups__flush(&self->mg);
83 }
84 return err;
40} 85}
41 86
42int thread__comm_len(struct thread *self) 87int thread__comm_len(struct thread *self)
@@ -50,74 +95,10 @@ int thread__comm_len(struct thread *self)
50 return self->comm_len; 95 return self->comm_len;
51} 96}
52 97
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) 98static size_t thread__fprintf(struct thread *self, FILE *fp)
118{ 99{
119 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + 100 return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
120 map_groups__fprintf(&self->mg, fp); 101 map_groups__fprintf(&self->mg, verbose, fp);
121} 102}
122 103
123struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) 104struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
@@ -159,107 +140,24 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)
159 return th; 140 return th;
160} 141}
161 142
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) 143void thread__insert_map(struct thread *self, struct map *map)
232{ 144{
233 map_groups__remove_overlappings(&self->mg, map); 145 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr);
234 map_groups__insert(&self->mg, map); 146 map_groups__insert(&self->mg, map);
235} 147}
236 148
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) 149int thread__fork(struct thread *self, struct thread *parent)
255{ 150{
256 int i; 151 int i;
257 152
258 if (self->comm) 153 if (parent->comm_set) {
259 free(self->comm); 154 if (self->comm)
260 self->comm = strdup(parent->comm); 155 free(self->comm);
261 if (!self->comm) 156 self->comm = strdup(parent->comm);
262 return -ENOMEM; 157 if (!self->comm)
158 return -ENOMEM;
159 self->comm_set = true;
160 }
263 161
264 for (i = 0; i < MAP__NR_TYPES; ++i) 162 for (i = 0; i < MAP__NR_TYPES; ++i)
265 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 163 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
@@ -280,16 +178,3 @@ size_t perf_session__fprintf(struct perf_session *self, FILE *fp)
280 178
281 return ret; 179 return ret;
282} 180}
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..688500ff826f 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -5,66 +5,45 @@
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 perf_session;
22
23void thread__delete(struct thread *self);
24
25int find_all_tid(int pid, pid_t ** all_tid);
23int thread__set_comm(struct thread *self, const char *comm); 26int thread__set_comm(struct thread *self, const char *comm);
24int thread__comm_len(struct thread *self); 27int thread__comm_len(struct thread *self);
25struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 28struct thread *perf_session__findnew(struct perf_session *self, pid_t pid);
26void thread__insert_map(struct thread *self, struct map *map); 29void thread__insert_map(struct thread *self, struct map *map);
27int thread__fork(struct thread *self, struct thread *parent); 30int 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); 31size_t perf_session__fprintf(struct perf_session *self, FILE *fp);
30 32
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, 33static inline struct map *thread__find_map(struct thread *self,
46 enum map_type type, u64 addr) 34 enum map_type type, u64 addr)
47{ 35{
48 return self ? map_groups__find(&self->mg, type, addr) : NULL; 36 return self ? map_groups__find(&self->mg, type, addr) : NULL;
49} 37}
50 38
39void thread__find_addr_map(struct thread *self,
40 struct perf_session *session, u8 cpumode,
41 enum map_type type, pid_t pid, u64 addr,
42 struct addr_location *al);
43
51void thread__find_addr_location(struct thread *self, 44void thread__find_addr_location(struct thread *self,
52 struct perf_session *session, u8 cpumode, 45 struct perf_session *session, u8 cpumode,
53 enum map_type type, u64 addr, 46 enum map_type type, pid_t pid, u64 addr,
54 struct addr_location *al, 47 struct addr_location *al,
55 symbol_filter_t filter); 48 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 */ 49#endif /* __PERF_THREAD_H */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index cace35595530..b1572601286c 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>
@@ -37,6 +38,7 @@
37 38
38#include "../perf.h" 39#include "../perf.h"
39#include "trace-event.h" 40#include "trace-event.h"
41#include "debugfs.h"
40 42
41#define VERSION "0.5" 43#define VERSION "0.5"
42 44
@@ -101,32 +103,12 @@ void *malloc_or_die(unsigned int size)
101 103
102static const char *find_debugfs(void) 104static const char *find_debugfs(void)
103{ 105{
104 static char debugfs[MAX_PATH+1]; 106 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 107
127 debugfs_found = 1; 108 if (!path)
109 die("Your kernel not support debugfs filesystem");
128 110
129 return debugfs; 111 return path;
130} 112}
131 113
132/* 114/*
@@ -172,10 +154,17 @@ static void put_tracing_file(char *file)
172 free(file); 154 free(file);
173} 155}
174 156
157static ssize_t calc_data_size;
158
175static ssize_t write_or_die(const void *buf, size_t len) 159static ssize_t write_or_die(const void *buf, size_t len)
176{ 160{
177 int ret; 161 int ret;
178 162
163 if (calc_data_size) {
164 calc_data_size += len;
165 return len;
166 }
167
179 ret = write(output_fd, buf, len); 168 ret = write(output_fd, buf, len);
180 if (ret < 0) 169 if (ret < 0)
181 die("writing to '%s'", output_file); 170 die("writing to '%s'", output_file);
@@ -271,6 +260,8 @@ static void read_header_files(void)
271 write_or_die("header_page", 12); 260 write_or_die("header_page", 12);
272 write_or_die(&size, 8); 261 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd); 262 check_size = copy_file_fd(fd);
263 close(fd);
264
274 if (size != check_size) 265 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld", 266 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size); 267 path, size, check_size);
@@ -289,6 +280,7 @@ static void read_header_files(void)
289 if (size != check_size) 280 if (size != check_size)
290 die("wrong size for '%s'", path); 281 die("wrong size for '%s'", path);
291 put_tracing_file(path); 282 put_tracing_file(path);
283 close(fd);
292} 284}
293 285
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 286static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
@@ -317,7 +309,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
317 die("can't read directory '%s'", sys); 309 die("can't read directory '%s'", sys);
318 310
319 while ((dent = readdir(dir))) { 311 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 || 312 if (dent->d_type != DT_DIR ||
313 strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 || 314 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps)) 315 !name_in_tp_list(dent->d_name, tps))
323 continue; 316 continue;
@@ -334,7 +327,8 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
334 327
335 rewinddir(dir); 328 rewinddir(dir);
336 while ((dent = readdir(dir))) { 329 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 || 330 if (dent->d_type != DT_DIR ||
331 strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 || 332 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps)) 333 !name_in_tp_list(dent->d_name, tps))
340 continue; 334 continue;
@@ -353,6 +347,7 @@ static void copy_event_system(const char *sys, struct tracepoint_path *tps)
353 347
354 free(format); 348 free(format);
355 } 349 }
350 closedir(dir);
356} 351}
357 352
358static void read_ftrace_files(struct tracepoint_path *tps) 353static void read_ftrace_files(struct tracepoint_path *tps)
@@ -394,26 +389,21 @@ static void read_event_files(struct tracepoint_path *tps)
394 die("can't read directory '%s'", path); 389 die("can't read directory '%s'", path);
395 390
396 while ((dent = readdir(dir))) { 391 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 || 392 if (dent->d_type != DT_DIR ||
393 strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 || 394 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 || 395 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps)) 396 !system_in_tp_list(dent->d_name, tps))
401 continue; 397 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 398 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 } 399 }
411 400
412 write_or_die(&count, 4); 401 write_or_die(&count, 4);
413 402
414 rewinddir(dir); 403 rewinddir(dir);
415 while ((dent = readdir(dir))) { 404 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 || 405 if (dent->d_type != DT_DIR ||
406 strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 || 407 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 || 408 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps)) 409 !system_in_tp_list(dent->d_name, tps))
@@ -422,14 +412,13 @@ static void read_event_files(struct tracepoint_path *tps)
422 sprintf(sys, "%s/%s", path, dent->d_name); 412 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st); 413 ret = stat(sys, &st);
424 if (ret >= 0) { 414 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) { 415 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 416 copy_event_system(sys, tps);
427 copy_event_system(sys, tps);
428 }
429 } 417 }
430 free(sys); 418 free(sys);
431 } 419 }
432 420
421 closedir(dir);
433 put_tracing_file(path); 422 put_tracing_file(path);
434} 423}
435 424
@@ -498,6 +487,17 @@ get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
498 return nr_tracepoints > 0 ? path.next : NULL; 487 return nr_tracepoints > 0 ? path.next : NULL;
499} 488}
500 489
490bool have_tracepoints(struct perf_event_attr *pattrs, int nb_events)
491{
492 int i;
493
494 for (i = 0; i < nb_events; i++)
495 if (pattrs[i].type == PERF_TYPE_TRACEPOINT)
496 return true;
497
498 return false;
499}
500
501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events) 501int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
502{ 502{
503 char buf[BUFSIZ]; 503 char buf[BUFSIZ];
@@ -533,7 +533,7 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
533 write_or_die(buf, 1); 533 write_or_die(buf, 1);
534 534
535 /* save page_size */ 535 /* save page_size */
536 page_size = getpagesize(); 536 page_size = sysconf(_SC_PAGESIZE);
537 write_or_die(&page_size, 4); 537 write_or_die(&page_size, 4);
538 538
539 read_header_files(); 539 read_header_files();
@@ -544,3 +544,20 @@ int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events)
544 544
545 return 0; 545 return 0;
546} 546}
547
548ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
549 int nb_events)
550{
551 ssize_t size;
552 int err = 0;
553
554 calc_data_size = 1;
555 err = read_tracing_data(fd, pattrs, nb_events);
556 size = calc_data_size - 1;
557 calc_data_size = 0;
558
559 if (err < 0)
560 return err;
561
562 return size;
563}
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..b3e86b1e4444 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);
@@ -258,6 +263,8 @@ void *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 perf_event_attr *pattrs, int nb_events);
266ssize_t read_tracing_data_size(int fd, struct perf_event_attr *pattrs,
267 int nb_events);
261 268
262/* taken from kernel/trace/trace.h */ 269/* taken from kernel/trace/trace.h */
263enum trace_flag_type { 270enum trace_flag_type {
@@ -279,7 +286,15 @@ struct scripting_ops {
279 286
280int script_spec_register(const char *spec, struct scripting_ops *ops); 287int script_spec_register(const char *spec, struct scripting_ops *ops);
281 288
282extern struct scripting_ops perl_scripting_ops;
283void setup_perl_scripting(void); 289void setup_perl_scripting(void);
290void setup_python_scripting(void);
291
292struct scripting_context {
293 void *event_data;
294};
295
296int common_pc(struct scripting_context *context);
297int common_flags(struct scripting_context *context);
298int common_lock_depth(struct scripting_context *context);
284 299
285#endif /* __PERF_TRACE_EVENTS_H */ 300#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..66f2d583d8c4
--- /dev/null
+++ b/tools/perf/util/ui/browser.c
@@ -0,0 +1,329 @@
1#define _GNU_SOURCE
2#include <stdio.h>
3#undef _GNU_SOURCE
4/*
5 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
6 * the build if it isn't defined. Use the equivalent one that glibc
7 * has on features.h.
8 */
9#include <features.h>
10#ifndef HAVE_LONG_LONG
11#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
12#endif
13#include <slang.h>
14#include <linux/list.h>
15#include <linux/rbtree.h>
16#include <stdlib.h>
17#include <sys/ttydefaults.h>
18#include "browser.h"
19#include "helpline.h"
20#include "../color.h"
21#include "../util.h"
22
23#if SLANG_VERSION < 20104
24#define sltt_set_color(obj, name, fg, bg) \
25 SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg)
26#else
27#define sltt_set_color SLtt_set_color
28#endif
29
30newtComponent newt_form__new(void);
31
32int ui_browser__percent_color(double percent, bool current)
33{
34 if (current)
35 return HE_COLORSET_SELECTED;
36 if (percent >= MIN_RED)
37 return HE_COLORSET_TOP;
38 if (percent >= MIN_GREEN)
39 return HE_COLORSET_MEDIUM;
40 return HE_COLORSET_NORMAL;
41}
42
43void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
44{
45 struct list_head *head = self->entries;
46 struct list_head *pos;
47
48 switch (whence) {
49 case SEEK_SET:
50 pos = head->next;
51 break;
52 case SEEK_CUR:
53 pos = self->top;
54 break;
55 case SEEK_END:
56 pos = head->prev;
57 break;
58 default:
59 return;
60 }
61
62 if (offset > 0) {
63 while (offset-- != 0)
64 pos = pos->next;
65 } else {
66 while (offset++ != 0)
67 pos = pos->prev;
68 }
69
70 self->top = pos;
71}
72
73void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
74{
75 struct rb_root *root = self->entries;
76 struct rb_node *nd;
77
78 switch (whence) {
79 case SEEK_SET:
80 nd = rb_first(root);
81 break;
82 case SEEK_CUR:
83 nd = self->top;
84 break;
85 case SEEK_END:
86 nd = rb_last(root);
87 break;
88 default:
89 return;
90 }
91
92 if (offset > 0) {
93 while (offset-- != 0)
94 nd = rb_next(nd);
95 } else {
96 while (offset++ != 0)
97 nd = rb_prev(nd);
98 }
99
100 self->top = nd;
101}
102
103unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
104{
105 struct rb_node *nd;
106 int row = 0;
107
108 if (self->top == NULL)
109 self->top = rb_first(self->entries);
110
111 nd = self->top;
112
113 while (nd != NULL) {
114 SLsmg_gotorc(self->y + row, self->x);
115 self->write(self, nd, row);
116 if (++row == self->height)
117 break;
118 nd = rb_next(nd);
119 }
120
121 return row;
122}
123
124bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
125{
126 return self->top_idx + row == self->index;
127}
128
129void ui_browser__refresh_dimensions(struct ui_browser *self)
130{
131 int cols, rows;
132 newtGetScreenSize(&cols, &rows);
133
134 if (self->width > cols - 4)
135 self->width = cols - 4;
136 self->height = rows - 5;
137 if (self->height > self->nr_entries)
138 self->height = self->nr_entries;
139 self->y = (rows - self->height) / 2;
140 self->x = (cols - self->width) / 2;
141}
142
143void ui_browser__reset_index(struct ui_browser *self)
144{
145 self->index = self->top_idx = 0;
146 self->seek(self, 0, SEEK_SET);
147}
148
149int ui_browser__show(struct ui_browser *self, const char *title,
150 const char *helpline, ...)
151{
152 va_list ap;
153
154 if (self->form != NULL) {
155 newtFormDestroy(self->form);
156 newtPopWindow();
157 }
158 ui_browser__refresh_dimensions(self);
159 newtCenteredWindow(self->width, self->height, title);
160 self->form = newt_form__new();
161 if (self->form == NULL)
162 return -1;
163
164 self->sb = newtVerticalScrollbar(self->width, 0, self->height,
165 HE_COLORSET_NORMAL,
166 HE_COLORSET_SELECTED);
167 if (self->sb == NULL)
168 return -1;
169
170 newtFormAddHotKey(self->form, NEWT_KEY_UP);
171 newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
172 newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
173 newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
174 newtFormAddHotKey(self->form, NEWT_KEY_HOME);
175 newtFormAddHotKey(self->form, NEWT_KEY_END);
176 newtFormAddHotKey(self->form, ' ');
177 newtFormAddComponent(self->form, self->sb);
178
179 va_start(ap, helpline);
180 ui_helpline__vpush(helpline, ap);
181 va_end(ap);
182 return 0;
183}
184
185void ui_browser__hide(struct ui_browser *self)
186{
187 newtFormDestroy(self->form);
188 newtPopWindow();
189 self->form = NULL;
190 ui_helpline__pop();
191}
192
193int ui_browser__refresh(struct ui_browser *self)
194{
195 int row;
196
197 newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
198 row = self->refresh(self);
199 SLsmg_set_color(HE_COLORSET_NORMAL);
200 SLsmg_fill_region(self->y + row, self->x,
201 self->height - row, self->width, ' ');
202
203 return 0;
204}
205
206int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
207{
208 if (ui_browser__refresh(self) < 0)
209 return -1;
210
211 while (1) {
212 off_t offset;
213
214 newtFormRun(self->form, es);
215
216 if (es->reason != NEWT_EXIT_HOTKEY)
217 break;
218 if (is_exit_key(es->u.key))
219 return es->u.key;
220 switch (es->u.key) {
221 case NEWT_KEY_DOWN:
222 if (self->index == self->nr_entries - 1)
223 break;
224 ++self->index;
225 if (self->index == self->top_idx + self->height) {
226 ++self->top_idx;
227 self->seek(self, +1, SEEK_CUR);
228 }
229 break;
230 case NEWT_KEY_UP:
231 if (self->index == 0)
232 break;
233 --self->index;
234 if (self->index < self->top_idx) {
235 --self->top_idx;
236 self->seek(self, -1, SEEK_CUR);
237 }
238 break;
239 case NEWT_KEY_PGDN:
240 case ' ':
241 if (self->top_idx + self->height > self->nr_entries - 1)
242 break;
243
244 offset = self->height;
245 if (self->index + offset > self->nr_entries - 1)
246 offset = self->nr_entries - 1 - self->index;
247 self->index += offset;
248 self->top_idx += offset;
249 self->seek(self, +offset, SEEK_CUR);
250 break;
251 case NEWT_KEY_PGUP:
252 if (self->top_idx == 0)
253 break;
254
255 if (self->top_idx < self->height)
256 offset = self->top_idx;
257 else
258 offset = self->height;
259
260 self->index -= offset;
261 self->top_idx -= offset;
262 self->seek(self, -offset, SEEK_CUR);
263 break;
264 case NEWT_KEY_HOME:
265 ui_browser__reset_index(self);
266 break;
267 case NEWT_KEY_END:
268 offset = self->height - 1;
269 if (offset >= self->nr_entries)
270 offset = self->nr_entries - 1;
271
272 self->index = self->nr_entries - 1;
273 self->top_idx = self->index - offset;
274 self->seek(self, -offset, SEEK_END);
275 break;
276 default:
277 return es->u.key;
278 }
279 if (ui_browser__refresh(self) < 0)
280 return -1;
281 }
282 return 0;
283}
284
285unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
286{
287 struct list_head *pos;
288 struct list_head *head = self->entries;
289 int row = 0;
290
291 if (self->top == NULL || self->top == self->entries)
292 self->top = head->next;
293
294 pos = self->top;
295
296 list_for_each_from(pos, head) {
297 SLsmg_gotorc(self->y + row, self->x);
298 self->write(self, pos, row);
299 if (++row == self->height)
300 break;
301 }
302
303 return row;
304}
305
306static struct newtPercentTreeColors {
307 const char *topColorFg, *topColorBg;
308 const char *mediumColorFg, *mediumColorBg;
309 const char *normalColorFg, *normalColorBg;
310 const char *selColorFg, *selColorBg;
311 const char *codeColorFg, *codeColorBg;
312} defaultPercentTreeColors = {
313 "red", "lightgray",
314 "green", "lightgray",
315 "black", "lightgray",
316 "lightgray", "magenta",
317 "blue", "lightgray",
318};
319
320void ui_browser__init(void)
321{
322 struct newtPercentTreeColors *c = &defaultPercentTreeColors;
323
324 sltt_set_color(HE_COLORSET_TOP, NULL, c->topColorFg, c->topColorBg);
325 sltt_set_color(HE_COLORSET_MEDIUM, NULL, c->mediumColorFg, c->mediumColorBg);
326 sltt_set_color(HE_COLORSET_NORMAL, NULL, c->normalColorFg, c->normalColorBg);
327 sltt_set_color(HE_COLORSET_SELECTED, NULL, c->selColorFg, c->selColorBg);
328 sltt_set_color(HE_COLORSET_CODE, NULL, c->codeColorFg, c->codeColorBg);
329}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
new file mode 100644
index 000000000000..0b9f829214f7
--- /dev/null
+++ b/tools/perf/util/ui/browser.h
@@ -0,0 +1,46 @@
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
28int ui_browser__percent_color(double percent, bool current);
29bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
30void ui_browser__refresh_dimensions(struct ui_browser *self);
31void ui_browser__reset_index(struct ui_browser *self);
32
33int ui_browser__show(struct ui_browser *self, const char *title,
34 const char *helpline, ...);
35void ui_browser__hide(struct ui_browser *self);
36int ui_browser__refresh(struct ui_browser *self);
37int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es);
38
39void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
40unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
41
42void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence);
43unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
44
45void ui_browser__init(void);
46#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..a90273e63f4f
--- /dev/null
+++ b/tools/perf/util/ui/browsers/annotate.c
@@ -0,0 +1,241 @@
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 int color = ui_browser__percent_color(olrb->percent, current_entry);
44 SLsmg_set_color(color);
45 slsmg_printf(" %7.2f ", olrb->percent);
46 if (!current_entry)
47 SLsmg_set_color(HE_COLORSET_CODE);
48 } else {
49 int color = ui_browser__percent_color(0, current_entry);
50 SLsmg_set_color(color);
51 slsmg_write_nstring(" ", 9);
52 }
53
54 SLsmg_write_char(':');
55 slsmg_write_nstring(" ", 8);
56 if (!*ol->line)
57 slsmg_write_nstring(" ", width - 18);
58 else
59 slsmg_write_nstring(ol->line, width - 18);
60}
61
62static double objdump_line__calc_percent(struct objdump_line *self,
63 struct list_head *head,
64 struct symbol *sym)
65{
66 double percent = 0.0;
67
68 if (self->offset != -1) {
69 int len = sym->end - sym->start;
70 unsigned int hits = 0;
71 struct sym_priv *priv = symbol__priv(sym);
72 struct sym_ext *sym_ext = priv->ext;
73 struct sym_hist *h = priv->hist;
74 s64 offset = self->offset;
75 struct objdump_line *next = objdump__get_next_ip_line(head, self);
76
77
78 while (offset < (s64)len &&
79 (next == NULL || offset < next->offset)) {
80 if (sym_ext) {
81 percent += sym_ext[offset].percent;
82 } else
83 hits += h->ip[offset];
84
85 ++offset;
86 }
87
88 if (sym_ext == NULL && h->sum)
89 percent = 100.0 * hits / h->sum;
90 }
91
92 return percent;
93}
94
95static void objdump__insert_line(struct rb_root *self,
96 struct objdump_line_rb_node *line)
97{
98 struct rb_node **p = &self->rb_node;
99 struct rb_node *parent = NULL;
100 struct objdump_line_rb_node *l;
101
102 while (*p != NULL) {
103 parent = *p;
104 l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
105 if (line->percent < l->percent)
106 p = &(*p)->rb_left;
107 else
108 p = &(*p)->rb_right;
109 }
110 rb_link_node(&line->rb_node, parent, p);
111 rb_insert_color(&line->rb_node, self);
112}
113
114static void annotate_browser__set_top(struct annotate_browser *self,
115 struct rb_node *nd)
116{
117 struct objdump_line_rb_node *rbpos;
118 struct objdump_line *pos;
119 unsigned back;
120
121 ui_browser__refresh_dimensions(&self->b);
122 back = self->b.height / 2;
123 rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
124 pos = ((struct objdump_line *)rbpos) - 1;
125 self->b.top_idx = self->b.index = rbpos->idx;
126
127 while (self->b.top_idx != 0 && back != 0) {
128 pos = list_entry(pos->node.prev, struct objdump_line, node);
129
130 --self->b.top_idx;
131 --back;
132 }
133
134 self->b.top = pos;
135 self->curr_hot = nd;
136}
137
138static int annotate_browser__run(struct annotate_browser *self,
139 struct newtExitStruct *es)
140{
141 struct rb_node *nd;
142 struct hist_entry *he = self->b.priv;
143
144 if (ui_browser__show(&self->b, he->ms.sym->name,
145 "<- or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0)
146 return -1;
147
148 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
149 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
150
151 nd = self->curr_hot;
152 if (nd) {
153 newtFormAddHotKey(self->b.form, NEWT_KEY_TAB);
154 newtFormAddHotKey(self->b.form, NEWT_KEY_UNTAB);
155 }
156
157 while (1) {
158 ui_browser__run(&self->b, es);
159
160 if (es->reason != NEWT_EXIT_HOTKEY)
161 break;
162
163 switch (es->u.key) {
164 case NEWT_KEY_TAB:
165 nd = rb_prev(nd);
166 if (nd == NULL)
167 nd = rb_last(&self->entries);
168 annotate_browser__set_top(self, nd);
169 break;
170 case NEWT_KEY_UNTAB:
171 nd = rb_next(nd);
172 if (nd == NULL)
173 nd = rb_first(&self->entries);
174 annotate_browser__set_top(self, nd);
175 break;
176 default:
177 goto out;
178 }
179 }
180out:
181 ui_browser__hide(&self->b);
182 return es->u.key;
183}
184
185int hist_entry__tui_annotate(struct hist_entry *self)
186{
187 struct newtExitStruct es;
188 struct objdump_line *pos, *n;
189 struct objdump_line_rb_node *rbpos;
190 LIST_HEAD(head);
191 struct annotate_browser browser = {
192 .b = {
193 .entries = &head,
194 .refresh = ui_browser__list_head_refresh,
195 .seek = ui_browser__list_head_seek,
196 .write = annotate_browser__write,
197 .priv = self,
198 },
199 };
200 int ret;
201
202 if (self->ms.sym == NULL)
203 return -1;
204
205 if (self->ms.map->dso->annotate_warned)
206 return -1;
207
208 if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) {
209 ui__error_window(ui_helpline__last_msg);
210 return -1;
211 }
212
213 ui_helpline__push("Press <- or ESC to exit");
214
215 list_for_each_entry(pos, &head, node) {
216 size_t line_len = strlen(pos->line);
217 if (browser.b.width < line_len)
218 browser.b.width = line_len;
219 rbpos = objdump_line__rb(pos);
220 rbpos->idx = browser.b.nr_entries++;
221 rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym);
222 if (rbpos->percent < 0.01)
223 continue;
224 objdump__insert_line(&browser.entries, rbpos);
225 }
226
227 /*
228 * Position the browser at the hottest line.
229 */
230 browser.curr_hot = rb_last(&browser.entries);
231 if (browser.curr_hot)
232 annotate_browser__set_top(&browser, browser.curr_hot);
233
234 browser.b.width += 18; /* Percentage */
235 ret = annotate_browser__run(&browser, &es);
236 list_for_each_entry_safe(pos, n, &head, node) {
237 list_del(&pos->node);
238 objdump_line__free(pos);
239 }
240 return ret;
241}
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
new file mode 100644
index 000000000000..6866aa4c41e0
--- /dev/null
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -0,0 +1,948 @@
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 int callchain_node__count_rows_rb_tree(struct callchain_node *self)
62{
63 int n = 0;
64 struct rb_node *nd;
65
66 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
67 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
68 struct callchain_list *chain;
69 char folded_sign = ' '; /* No children */
70
71 list_for_each_entry(chain, &child->val, list) {
72 ++n;
73 /* We need this because we may not have children */
74 folded_sign = callchain_list__folded(chain);
75 if (folded_sign == '+')
76 break;
77 }
78
79 if (folded_sign == '-') /* Have children and they're unfolded */
80 n += callchain_node__count_rows_rb_tree(child);
81 }
82
83 return n;
84}
85
86static int callchain_node__count_rows(struct callchain_node *node)
87{
88 struct callchain_list *chain;
89 bool unfolded = false;
90 int n = 0;
91
92 list_for_each_entry(chain, &node->val, list) {
93 ++n;
94 unfolded = chain->ms.unfolded;
95 }
96
97 if (unfolded)
98 n += callchain_node__count_rows_rb_tree(node);
99
100 return n;
101}
102
103static int callchain__count_rows(struct rb_root *chain)
104{
105 struct rb_node *nd;
106 int n = 0;
107
108 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
109 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
110 n += callchain_node__count_rows(node);
111 }
112
113 return n;
114}
115
116static bool map_symbol__toggle_fold(struct map_symbol *self)
117{
118 if (!self->has_children)
119 return false;
120
121 self->unfolded = !self->unfolded;
122 return true;
123}
124
125static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
126{
127 struct rb_node *nd = rb_first(&self->rb_root);
128
129 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
130 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
131 struct callchain_list *chain;
132 int first = true;
133
134 list_for_each_entry(chain, &child->val, list) {
135 if (first) {
136 first = false;
137 chain->ms.has_children = chain->list.next != &child->val ||
138 rb_first(&child->rb_root) != NULL;
139 } else
140 chain->ms.has_children = chain->list.next == &child->val &&
141 rb_first(&child->rb_root) != NULL;
142 }
143
144 callchain_node__init_have_children_rb_tree(child);
145 }
146}
147
148static void callchain_node__init_have_children(struct callchain_node *self)
149{
150 struct callchain_list *chain;
151
152 list_for_each_entry(chain, &self->val, list)
153 chain->ms.has_children = rb_first(&self->rb_root) != NULL;
154
155 callchain_node__init_have_children_rb_tree(self);
156}
157
158static void callchain__init_have_children(struct rb_root *self)
159{
160 struct rb_node *nd;
161
162 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
163 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
164 callchain_node__init_have_children(node);
165 }
166}
167
168static void hist_entry__init_have_children(struct hist_entry *self)
169{
170 if (!self->init_have_children) {
171 callchain__init_have_children(&self->sorted_chain);
172 self->init_have_children = true;
173 }
174}
175
176static bool hist_browser__toggle_fold(struct hist_browser *self)
177{
178 if (map_symbol__toggle_fold(self->selection)) {
179 struct hist_entry *he = self->he_selection;
180
181 hist_entry__init_have_children(he);
182 self->hists->nr_entries -= he->nr_rows;
183
184 if (he->ms.unfolded)
185 he->nr_rows = callchain__count_rows(&he->sorted_chain);
186 else
187 he->nr_rows = 0;
188 self->hists->nr_entries += he->nr_rows;
189 self->b.nr_entries = self->hists->nr_entries;
190
191 return true;
192 }
193
194 /* If it doesn't have children, no toggling performed */
195 return false;
196}
197
198static int hist_browser__run(struct hist_browser *self, const char *title,
199 struct newtExitStruct *es)
200{
201 char str[256], unit;
202 unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE];
203
204 self->b.entries = &self->hists->entries;
205 self->b.nr_entries = self->hists->nr_entries;
206
207 hist_browser__refresh_dimensions(self);
208
209 nr_events = convert_unit(nr_events, &unit);
210 snprintf(str, sizeof(str), "Events: %lu%c ",
211 nr_events, unit);
212 newtDrawRootText(0, 0, str);
213
214 if (ui_browser__show(&self->b, title,
215 "Press '?' for help on key bindings") < 0)
216 return -1;
217
218 newtFormAddHotKey(self->b.form, 'a');
219 newtFormAddHotKey(self->b.form, '?');
220 newtFormAddHotKey(self->b.form, 'h');
221 newtFormAddHotKey(self->b.form, 'd');
222 newtFormAddHotKey(self->b.form, 'D');
223 newtFormAddHotKey(self->b.form, 't');
224
225 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
226 newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
227 newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
228
229 while (1) {
230 ui_browser__run(&self->b, es);
231
232 if (es->reason != NEWT_EXIT_HOTKEY)
233 break;
234 switch (es->u.key) {
235 case 'D': { /* Debug */
236 static int seq;
237 struct hist_entry *h = rb_entry(self->b.top,
238 struct hist_entry, rb_node);
239 ui_helpline__pop();
240 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
241 seq++, self->b.nr_entries,
242 self->hists->nr_entries,
243 self->b.height,
244 self->b.index,
245 self->b.top_idx,
246 h->row_offset, h->nr_rows);
247 }
248 continue;
249 case NEWT_KEY_ENTER:
250 if (hist_browser__toggle_fold(self))
251 break;
252 /* fall thru */
253 default:
254 return 0;
255 }
256 }
257
258 ui_browser__hide(&self->b);
259 return 0;
260}
261
262static char *callchain_list__sym_name(struct callchain_list *self,
263 char *bf, size_t bfsize)
264{
265 if (self->ms.sym)
266 return self->ms.sym->name;
267
268 snprintf(bf, bfsize, "%#Lx", self->ip);
269 return bf;
270}
271
272#define LEVEL_OFFSET_STEP 3
273
274static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
275 struct callchain_node *chain_node,
276 u64 total, int level,
277 unsigned short row,
278 off_t *row_offset,
279 bool *is_current_entry)
280{
281 struct rb_node *node;
282 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
283 u64 new_total, remaining;
284
285 if (callchain_param.mode == CHAIN_GRAPH_REL)
286 new_total = chain_node->children_hit;
287 else
288 new_total = total;
289
290 remaining = new_total;
291 node = rb_first(&chain_node->rb_root);
292 while (node) {
293 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
294 struct rb_node *next = rb_next(node);
295 u64 cumul = cumul_hits(child);
296 struct callchain_list *chain;
297 char folded_sign = ' ';
298 int first = true;
299 int extra_offset = 0;
300
301 remaining -= cumul;
302
303 list_for_each_entry(chain, &child->val, list) {
304 char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
305 const char *str;
306 int color;
307 bool was_first = first;
308
309 if (first) {
310 first = false;
311 chain->ms.has_children = chain->list.next != &child->val ||
312 rb_first(&child->rb_root) != NULL;
313 } else {
314 extra_offset = LEVEL_OFFSET_STEP;
315 chain->ms.has_children = chain->list.next == &child->val &&
316 rb_first(&child->rb_root) != NULL;
317 }
318
319 folded_sign = callchain_list__folded(chain);
320 if (*row_offset != 0) {
321 --*row_offset;
322 goto do_next;
323 }
324
325 alloc_str = NULL;
326 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
327 if (was_first) {
328 double percent = cumul * 100.0 / new_total;
329
330 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
331 str = "Not enough memory!";
332 else
333 str = alloc_str;
334 }
335
336 color = HE_COLORSET_NORMAL;
337 width = self->b.width - (offset + extra_offset + 2);
338 if (ui_browser__is_current_entry(&self->b, row)) {
339 self->selection = &chain->ms;
340 color = HE_COLORSET_SELECTED;
341 *is_current_entry = true;
342 }
343
344 SLsmg_set_color(color);
345 SLsmg_gotorc(self->b.y + row, self->b.x);
346 slsmg_write_nstring(" ", offset + extra_offset);
347 slsmg_printf("%c ", folded_sign);
348 slsmg_write_nstring(str, width);
349 free(alloc_str);
350
351 if (++row == self->b.height)
352 goto out;
353do_next:
354 if (folded_sign == '+')
355 break;
356 }
357
358 if (folded_sign == '-') {
359 const int new_level = level + (extra_offset ? 2 : 1);
360 row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
361 new_level, row, row_offset,
362 is_current_entry);
363 }
364 if (row == self->b.height)
365 goto out;
366 node = next;
367 }
368out:
369 return row - first_row;
370}
371
372static int hist_browser__show_callchain_node(struct hist_browser *self,
373 struct callchain_node *node,
374 int level, unsigned short row,
375 off_t *row_offset,
376 bool *is_current_entry)
377{
378 struct callchain_list *chain;
379 int first_row = row,
380 offset = level * LEVEL_OFFSET_STEP,
381 width = self->b.width - offset;
382 char folded_sign = ' ';
383
384 list_for_each_entry(chain, &node->val, list) {
385 char ipstr[BITS_PER_LONG / 4 + 1], *s;
386 int color;
387 /*
388 * FIXME: This should be moved to somewhere else,
389 * probably when the callchain is created, so as not to
390 * traverse it all over again
391 */
392 chain->ms.has_children = rb_first(&node->rb_root) != NULL;
393 folded_sign = callchain_list__folded(chain);
394
395 if (*row_offset != 0) {
396 --*row_offset;
397 continue;
398 }
399
400 color = HE_COLORSET_NORMAL;
401 if (ui_browser__is_current_entry(&self->b, row)) {
402 self->selection = &chain->ms;
403 color = HE_COLORSET_SELECTED;
404 *is_current_entry = true;
405 }
406
407 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
408 SLsmg_gotorc(self->b.y + row, self->b.x);
409 SLsmg_set_color(color);
410 slsmg_write_nstring(" ", offset);
411 slsmg_printf("%c ", folded_sign);
412 slsmg_write_nstring(s, width - 2);
413
414 if (++row == self->b.height)
415 goto out;
416 }
417
418 if (folded_sign == '-')
419 row += hist_browser__show_callchain_node_rb_tree(self, node,
420 self->hists->stats.total_period,
421 level + 1, row,
422 row_offset,
423 is_current_entry);
424out:
425 return row - first_row;
426}
427
428static int hist_browser__show_callchain(struct hist_browser *self,
429 struct rb_root *chain,
430 int level, unsigned short row,
431 off_t *row_offset,
432 bool *is_current_entry)
433{
434 struct rb_node *nd;
435 int first_row = row;
436
437 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
438 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
439
440 row += hist_browser__show_callchain_node(self, node, level,
441 row, row_offset,
442 is_current_entry);
443 if (row == self->b.height)
444 break;
445 }
446
447 return row - first_row;
448}
449
450static int hist_browser__show_entry(struct hist_browser *self,
451 struct hist_entry *entry,
452 unsigned short row)
453{
454 char s[256];
455 double percent;
456 int printed = 0;
457 int color, width = self->b.width;
458 char folded_sign = ' ';
459 bool current_entry = ui_browser__is_current_entry(&self->b, row);
460 off_t row_offset = entry->row_offset;
461
462 if (current_entry) {
463 self->he_selection = entry;
464 self->selection = &entry->ms;
465 }
466
467 if (symbol_conf.use_callchain) {
468 entry->ms.has_children = !RB_EMPTY_ROOT(&entry->sorted_chain);
469 folded_sign = hist_entry__folded(entry);
470 }
471
472 if (row_offset == 0) {
473 hist_entry__snprintf(entry, s, sizeof(s), self->hists, NULL, false,
474 0, false, self->hists->stats.total_period);
475 percent = (entry->period * 100.0) / self->hists->stats.total_period;
476
477 color = HE_COLORSET_SELECTED;
478 if (!current_entry) {
479 if (percent >= MIN_RED)
480 color = HE_COLORSET_TOP;
481 else if (percent >= MIN_GREEN)
482 color = HE_COLORSET_MEDIUM;
483 else
484 color = HE_COLORSET_NORMAL;
485 }
486
487 SLsmg_set_color(color);
488 SLsmg_gotorc(self->b.y + row, self->b.x);
489 if (symbol_conf.use_callchain) {
490 slsmg_printf("%c ", folded_sign);
491 width -= 2;
492 }
493 slsmg_write_nstring(s, width);
494 ++row;
495 ++printed;
496 } else
497 --row_offset;
498
499 if (folded_sign == '-' && row != self->b.height) {
500 printed += hist_browser__show_callchain(self, &entry->sorted_chain,
501 1, row, &row_offset,
502 &current_entry);
503 if (current_entry)
504 self->he_selection = entry;
505 }
506
507 return printed;
508}
509
510static unsigned int hist_browser__refresh(struct ui_browser *self)
511{
512 unsigned row = 0;
513 struct rb_node *nd;
514 struct hist_browser *hb = container_of(self, struct hist_browser, b);
515
516 if (self->top == NULL)
517 self->top = rb_first(&hb->hists->entries);
518
519 for (nd = self->top; nd; nd = rb_next(nd)) {
520 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
521
522 if (h->filtered)
523 continue;
524
525 row += hist_browser__show_entry(hb, h, row);
526 if (row == self->height)
527 break;
528 }
529
530 return row;
531}
532
533static struct rb_node *hists__filter_entries(struct rb_node *nd)
534{
535 while (nd != NULL) {
536 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
537 if (!h->filtered)
538 return nd;
539
540 nd = rb_next(nd);
541 }
542
543 return NULL;
544}
545
546static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
547{
548 while (nd != NULL) {
549 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
550 if (!h->filtered)
551 return nd;
552
553 nd = rb_prev(nd);
554 }
555
556 return NULL;
557}
558
559static void ui_browser__hists_seek(struct ui_browser *self,
560 off_t offset, int whence)
561{
562 struct hist_entry *h;
563 struct rb_node *nd;
564 bool first = true;
565
566 switch (whence) {
567 case SEEK_SET:
568 nd = hists__filter_entries(rb_first(self->entries));
569 break;
570 case SEEK_CUR:
571 nd = self->top;
572 goto do_offset;
573 case SEEK_END:
574 nd = hists__filter_prev_entries(rb_last(self->entries));
575 first = false;
576 break;
577 default:
578 return;
579 }
580
581 /*
582 * Moves not relative to the first visible entry invalidates its
583 * row_offset:
584 */
585 h = rb_entry(self->top, struct hist_entry, rb_node);
586 h->row_offset = 0;
587
588 /*
589 * Here we have to check if nd is expanded (+), if it is we can't go
590 * the next top level hist_entry, instead we must compute an offset of
591 * what _not_ to show and not change the first visible entry.
592 *
593 * This offset increments when we are going from top to bottom and
594 * decreases when we're going from bottom to top.
595 *
596 * As we don't have backpointers to the top level in the callchains
597 * structure, we need to always print the whole hist_entry callchain,
598 * skipping the first ones that are before the first visible entry
599 * and stop when we printed enough lines to fill the screen.
600 */
601do_offset:
602 if (offset > 0) {
603 do {
604 h = rb_entry(nd, struct hist_entry, rb_node);
605 if (h->ms.unfolded) {
606 u16 remaining = h->nr_rows - h->row_offset;
607 if (offset > remaining) {
608 offset -= remaining;
609 h->row_offset = 0;
610 } else {
611 h->row_offset += offset;
612 offset = 0;
613 self->top = nd;
614 break;
615 }
616 }
617 nd = hists__filter_entries(rb_next(nd));
618 if (nd == NULL)
619 break;
620 --offset;
621 self->top = nd;
622 } while (offset != 0);
623 } else if (offset < 0) {
624 while (1) {
625 h = rb_entry(nd, struct hist_entry, rb_node);
626 if (h->ms.unfolded) {
627 if (first) {
628 if (-offset > h->row_offset) {
629 offset += h->row_offset;
630 h->row_offset = 0;
631 } else {
632 h->row_offset += offset;
633 offset = 0;
634 self->top = nd;
635 break;
636 }
637 } else {
638 if (-offset > h->nr_rows) {
639 offset += h->nr_rows;
640 h->row_offset = 0;
641 } else {
642 h->row_offset = h->nr_rows + offset;
643 offset = 0;
644 self->top = nd;
645 break;
646 }
647 }
648 }
649
650 nd = hists__filter_prev_entries(rb_prev(nd));
651 if (nd == NULL)
652 break;
653 ++offset;
654 self->top = nd;
655 if (offset == 0) {
656 /*
657 * Last unfiltered hist_entry, check if it is
658 * unfolded, if it is then we should have
659 * row_offset at its last entry.
660 */
661 h = rb_entry(nd, struct hist_entry, rb_node);
662 if (h->ms.unfolded)
663 h->row_offset = h->nr_rows;
664 break;
665 }
666 first = false;
667 }
668 } else {
669 self->top = nd;
670 h = rb_entry(nd, struct hist_entry, rb_node);
671 h->row_offset = 0;
672 }
673}
674
675static struct hist_browser *hist_browser__new(struct hists *hists)
676{
677 struct hist_browser *self = zalloc(sizeof(*self));
678
679 if (self) {
680 self->hists = hists;
681 self->b.refresh = hist_browser__refresh;
682 self->b.seek = ui_browser__hists_seek;
683 }
684
685 return self;
686}
687
688static void hist_browser__delete(struct hist_browser *self)
689{
690 newtFormDestroy(self->b.form);
691 newtPopWindow();
692 free(self);
693}
694
695static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
696{
697 return self->he_selection;
698}
699
700static struct thread *hist_browser__selected_thread(struct hist_browser *self)
701{
702 return self->he_selection->thread;
703}
704
705static int hist_browser__title(char *bf, size_t size, const char *ev_name,
706 const struct dso *dso, const struct thread *thread)
707{
708 int printed = 0;
709
710 if (thread)
711 printed += snprintf(bf + printed, size - printed,
712 "Thread: %s(%d)",
713 (thread->comm_set ? thread->comm : ""),
714 thread->pid);
715 if (dso)
716 printed += snprintf(bf + printed, size - printed,
717 "%sDSO: %s", thread ? " " : "",
718 dso->short_name);
719 return printed ?: snprintf(bf, size, "Event: %s", ev_name);
720}
721
722int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
723{
724 struct hist_browser *browser = hist_browser__new(self);
725 struct pstack *fstack;
726 const struct thread *thread_filter = NULL;
727 const struct dso *dso_filter = NULL;
728 struct newtExitStruct es;
729 char msg[160];
730 int key = -1;
731
732 if (browser == NULL)
733 return -1;
734
735 fstack = pstack__new(2);
736 if (fstack == NULL)
737 goto out;
738
739 ui_helpline__push(helpline);
740
741 hist_browser__title(msg, sizeof(msg), ev_name,
742 dso_filter, thread_filter);
743
744 while (1) {
745 const struct thread *thread;
746 const struct dso *dso;
747 char *options[16];
748 int nr_options = 0, choice = 0, i,
749 annotate = -2, zoom_dso = -2, zoom_thread = -2,
750 browse_map = -2;
751
752 if (hist_browser__run(browser, msg, &es))
753 break;
754
755 thread = hist_browser__selected_thread(browser);
756 dso = browser->selection->map ? browser->selection->map->dso : NULL;
757
758 if (es.reason == NEWT_EXIT_HOTKEY) {
759 key = es.u.key;
760
761 switch (key) {
762 case NEWT_KEY_F1:
763 goto do_help;
764 case NEWT_KEY_TAB:
765 case NEWT_KEY_UNTAB:
766 /*
767 * Exit the browser, let hists__browser_tree
768 * go to the next or previous
769 */
770 goto out_free_stack;
771 default:;
772 }
773
774 switch (key) {
775 case 'a':
776 if (browser->selection->map == NULL ||
777 browser->selection->map->dso->annotate_warned)
778 continue;
779 goto do_annotate;
780 case 'd':
781 goto zoom_dso;
782 case 't':
783 goto zoom_thread;
784 case 'h':
785 case '?':
786do_help:
787 ui__help_window("-> Zoom into DSO/Threads & Annotate current symbol\n"
788 "<- Zoom out\n"
789 "a Annotate current symbol\n"
790 "h/?/F1 Show this window\n"
791 "d Zoom into current DSO\n"
792 "t Zoom into current Thread\n"
793 "q/CTRL+C Exit browser");
794 continue;
795 default:;
796 }
797 if (is_exit_key(key)) {
798 if (key == NEWT_KEY_ESCAPE &&
799 !ui__dialog_yesno("Do you really want to exit?"))
800 continue;
801 break;
802 }
803
804 if (es.u.key == NEWT_KEY_LEFT) {
805 const void *top;
806
807 if (pstack__empty(fstack))
808 continue;
809 top = pstack__pop(fstack);
810 if (top == &dso_filter)
811 goto zoom_out_dso;
812 if (top == &thread_filter)
813 goto zoom_out_thread;
814 continue;
815 }
816 }
817
818 if (browser->selection->sym != NULL &&
819 !browser->selection->map->dso->annotate_warned &&
820 asprintf(&options[nr_options], "Annotate %s",
821 browser->selection->sym->name) > 0)
822 annotate = nr_options++;
823
824 if (thread != NULL &&
825 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
826 (thread_filter ? "out of" : "into"),
827 (thread->comm_set ? thread->comm : ""),
828 thread->pid) > 0)
829 zoom_thread = nr_options++;
830
831 if (dso != NULL &&
832 asprintf(&options[nr_options], "Zoom %s %s DSO",
833 (dso_filter ? "out of" : "into"),
834 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
835 zoom_dso = nr_options++;
836
837 if (browser->selection->map != NULL &&
838 asprintf(&options[nr_options], "Browse map details") > 0)
839 browse_map = nr_options++;
840
841 options[nr_options++] = (char *)"Exit";
842
843 choice = ui__popup_menu(nr_options, options);
844
845 for (i = 0; i < nr_options - 1; ++i)
846 free(options[i]);
847
848 if (choice == nr_options - 1)
849 break;
850
851 if (choice == -1)
852 continue;
853
854 if (choice == annotate) {
855 struct hist_entry *he;
856do_annotate:
857 if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) {
858 browser->selection->map->dso->annotate_warned = 1;
859 ui_helpline__puts("No vmlinux file found, can't "
860 "annotate with just a "
861 "kallsyms file");
862 continue;
863 }
864
865 he = hist_browser__selected_entry(browser);
866 if (he == NULL)
867 continue;
868
869 hist_entry__tui_annotate(he);
870 } else if (choice == browse_map)
871 map__browse(browser->selection->map);
872 else if (choice == zoom_dso) {
873zoom_dso:
874 if (dso_filter) {
875 pstack__remove(fstack, &dso_filter);
876zoom_out_dso:
877 ui_helpline__pop();
878 dso_filter = NULL;
879 } else {
880 if (dso == NULL)
881 continue;
882 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
883 dso->kernel ? "the Kernel" : dso->short_name);
884 dso_filter = dso;
885 pstack__push(fstack, &dso_filter);
886 }
887 hists__filter_by_dso(self, dso_filter);
888 hist_browser__title(msg, sizeof(msg), ev_name,
889 dso_filter, thread_filter);
890 hist_browser__reset(browser);
891 } else if (choice == zoom_thread) {
892zoom_thread:
893 if (thread_filter) {
894 pstack__remove(fstack, &thread_filter);
895zoom_out_thread:
896 ui_helpline__pop();
897 thread_filter = NULL;
898 } else {
899 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
900 thread->comm_set ? thread->comm : "",
901 thread->pid);
902 thread_filter = thread;
903 pstack__push(fstack, &thread_filter);
904 }
905 hists__filter_by_thread(self, thread_filter);
906 hist_browser__title(msg, sizeof(msg), ev_name,
907 dso_filter, thread_filter);
908 hist_browser__reset(browser);
909 }
910 }
911out_free_stack:
912 pstack__delete(fstack);
913out:
914 hist_browser__delete(browser);
915 return key;
916}
917
918int hists__tui_browse_tree(struct rb_root *self, const char *help)
919{
920 struct rb_node *first = rb_first(self), *nd = first, *next;
921 int key = 0;
922
923 while (nd) {
924 struct hists *hists = rb_entry(nd, struct hists, rb_node);
925 const char *ev_name = __event_name(hists->type, hists->config);
926
927 key = hists__browse(hists, help, ev_name);
928
929 if (is_exit_key(key))
930 break;
931
932 switch (key) {
933 case NEWT_KEY_TAB:
934 next = rb_next(nd);
935 if (next)
936 nd = next;
937 break;
938 case NEWT_KEY_UNTAB:
939 if (nd == first)
940 continue;
941 nd = rb_prev(nd);
942 default:
943 break;
944 }
945 }
946
947 return key;
948}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
new file mode 100644
index 000000000000..142b825b42bf
--- /dev/null
+++ b/tools/perf/util/ui/browsers/map.c
@@ -0,0 +1,161 @@
1#include "../libslang.h"
2#include <elf.h>
3#include <newt.h>
4#include <sys/ttydefaults.h>
5#include <ctype.h>
6#include <string.h>
7#include <linux/bitops.h>
8#include "../../debug.h"
9#include "../../symbol.h"
10#include "../browser.h"
11#include "../helpline.h"
12#include "map.h"
13
14static int ui_entry__read(const char *title, char *bf, size_t size, int width)
15{
16 struct newtExitStruct es;
17 newtComponent form, entry;
18 const char *result;
19 int err = -1;
20
21 newtCenteredWindow(width, 1, title);
22 form = newtForm(NULL, NULL, 0);
23 if (form == NULL)
24 return -1;
25
26 entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
27 if (entry == NULL)
28 goto out_free_form;
29
30 newtFormAddComponent(form, entry);
31 newtFormAddHotKey(form, NEWT_KEY_ENTER);
32 newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
33 newtFormAddHotKey(form, NEWT_KEY_LEFT);
34 newtFormAddHotKey(form, CTRL('c'));
35 newtFormRun(form, &es);
36
37 if (result != NULL) {
38 strncpy(bf, result, size);
39 err = 0;
40 }
41out_free_form:
42 newtPopWindow();
43 newtFormDestroy(form);
44 return 0;
45}
46
47struct map_browser {
48 struct ui_browser b;
49 struct map *map;
50 u16 namelen;
51 u8 addrlen;
52};
53
54static void map_browser__write(struct ui_browser *self, void *nd, int row)
55{
56 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
57 struct map_browser *mb = container_of(self, struct map_browser, b);
58 bool current_entry = ui_browser__is_current_entry(self, row);
59 int color = ui_browser__percent_color(0, current_entry);
60
61 SLsmg_set_color(color);
62 slsmg_printf("%*llx %*llx %c ",
63 mb->addrlen, sym->start, mb->addrlen, sym->end,
64 sym->binding == STB_GLOBAL ? 'g' :
65 sym->binding == STB_LOCAL ? 'l' : 'w');
66 slsmg_write_nstring(sym->name, mb->namelen);
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, struct newtExitStruct *es)
102{
103 if (ui_browser__show(&self->b, self->map->dso->long_name,
104 "Press <- or ESC to exit, %s / to search",
105 verbose ? "" : "restart with -v to use") < 0)
106 return -1;
107
108 newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
109 newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
110 if (verbose)
111 newtFormAddHotKey(self->b.form, '/');
112
113 while (1) {
114 ui_browser__run(&self->b, es);
115
116 if (es->reason != NEWT_EXIT_HOTKEY)
117 break;
118 if (verbose && es->u.key == '/')
119 map_browser__search(self);
120 else
121 break;
122 }
123
124 ui_browser__hide(&self->b);
125 return 0;
126}
127
128int map__browse(struct map *self)
129{
130 struct map_browser mb = {
131 .b = {
132 .entries = &self->dso->symbols[self->type],
133 .refresh = ui_browser__rb_tree_refresh,
134 .seek = ui_browser__rb_tree_seek,
135 .write = map_browser__write,
136 },
137 .map = self,
138 };
139 struct newtExitStruct es;
140 struct rb_node *nd;
141 char tmp[BITS_PER_LONG / 4];
142 u64 maxaddr = 0;
143
144 for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
145 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
146
147 if (mb.namelen < pos->namelen)
148 mb.namelen = pos->namelen;
149 if (maxaddr < pos->end)
150 maxaddr = pos->end;
151 if (verbose) {
152 u32 *idx = symbol__browser_index(pos);
153 *idx = mb.b.nr_entries;
154 }
155 ++mb.b.nr_entries;
156 }
157
158 mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr);
159 mb.b.width += mb.addrlen * 2 + 4 + mb.namelen;
160 return map_browser__run(&mb, &es);
161}
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..04600e26ceea
--- /dev/null
+++ b/tools/perf/util/ui/util.c
@@ -0,0 +1,114 @@
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
14newtComponent newt_form__new(void);
15
16static void newt_form__set_exit_keys(newtComponent self)
17{
18 newtFormAddHotKey(self, NEWT_KEY_LEFT);
19 newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
20 newtFormAddHotKey(self, 'Q');
21 newtFormAddHotKey(self, 'q');
22 newtFormAddHotKey(self, CTRL('c'));
23}
24
25newtComponent newt_form__new(void)
26{
27 newtComponent self = newtForm(NULL, NULL, 0);
28 if (self)
29 newt_form__set_exit_keys(self);
30 return self;
31}
32
33int ui__popup_menu(int argc, char * const argv[])
34{
35 struct newtExitStruct es;
36 int i, rc = -1, max_len = 5;
37 newtComponent listbox, form = newt_form__new();
38
39 if (form == NULL)
40 return -1;
41
42 listbox = newtListbox(0, 0, argc, NEWT_FLAG_RETURNEXIT);
43 if (listbox == NULL)
44 goto out_destroy_form;
45
46 newtFormAddComponent(form, listbox);
47
48 for (i = 0; i < argc; ++i) {
49 int len = strlen(argv[i]);
50 if (len > max_len)
51 max_len = len;
52 if (newtListboxAddEntry(listbox, argv[i], (void *)(long)i))
53 goto out_destroy_form;
54 }
55
56 newtCenteredWindow(max_len, argc, NULL);
57 newtFormRun(form, &es);
58 rc = newtListboxGetCurrent(listbox) - NULL;
59 if (es.reason == NEWT_EXIT_HOTKEY)
60 rc = -1;
61 newtPopWindow();
62out_destroy_form:
63 newtFormDestroy(form);
64 return rc;
65}
66
67int ui__help_window(const char *text)
68{
69 struct newtExitStruct es;
70 newtComponent tb, form = newt_form__new();
71 int rc = -1;
72 int max_len = 0, nr_lines = 0;
73 const char *t;
74
75 if (form == NULL)
76 return -1;
77
78 t = text;
79 while (1) {
80 const char *sep = strchr(t, '\n');
81 int len;
82
83 if (sep == NULL)
84 sep = strchr(t, '\0');
85 len = sep - t;
86 if (max_len < len)
87 max_len = len;
88 ++nr_lines;
89 if (*sep == '\0')
90 break;
91 t = sep + 1;
92 }
93
94 tb = newtTextbox(0, 0, max_len, nr_lines, 0);
95 if (tb == NULL)
96 goto out_destroy_form;
97
98 newtTextboxSetText(tb, text);
99 newtFormAddComponent(form, tb);
100 newtCenteredWindow(max_len, nr_lines, NULL);
101 newtFormRun(form, &es);
102 newtPopWindow();
103 rc = 0;
104out_destroy_form:
105 newtFormDestroy(form);
106 return rc;
107}
108
109bool ui__dialog_yesno(const char *msg)
110{
111 /* newtWinChoice should really be accepting const char pointers... */
112 char yes[] = "Yes", no[] = "No";
113 return newtWinChoice(NULL, yes, no, (char *)msg) == 1;
114}
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..214265674ddd
--- /dev/null
+++ b/tools/perf/util/util.c
@@ -0,0 +1,116 @@
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}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c673d8825883..f380fed74359 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,30 @@ 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);
268
269#ifndef ESC
270#define ESC 27
271#endif
272
273static inline bool is_exit_key(int key)
274{
275 char up;
276 if (key == CTRL('c') || key == ESC)
277 return true;
278 up = toupper(key);
279 return up == 'Q';
280}
281
282#define _STR(x) #x
283#define STR(x) _STR(x)
284
406#endif 285#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/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}