aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorKim Phillips <kim.phillips@arm.com>2018-01-14 14:28:50 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2018-01-17 08:23:31 -0500
commitffd3d18c20b8df281a18940ee80a99b28114d4b7 (patch)
tree34dc21f7af0fe43bbe16a04aeff46c59fb668593 /tools/perf/util
parentd777f8de99b05d399c0e4e51cdce016f26bd971b (diff)
perf tools: Add ARM Statistical Profiling Extensions (SPE) support
'perf record' and 'perf report --dump-raw-trace' supported in this release. Example usage: # perf record -e arm_spe/ts_enable=1,pa_enable=1/ dd if=/dev/zero of=/dev/null count=10000 # perf report --dump-raw-trace Note that the perf.data file is portable, so the report can be run on another architecture host if necessary. Output will contain raw SPE data and its textual representation, such as: 0x5c8 [0x30]: PERF_RECORD_AUXTRACE size: 0x200000 offset: 0 ref: 0x1891ad0e idx: 1 tid: 2227 cpu: 1 . . ... ARM SPE data: size 2097152 bytes . 00000000: 49 00 LD . 00000002: b2 c0 3b 29 0f 00 00 ff ff VA 0xffff00000f293bc0 . 0000000b: b3 c0 eb 24 fb 00 00 00 80 PA 0xfb24ebc0 ns=1 . 00000014: 9a 00 00 LAT 0 XLAT . 00000017: 42 16 EV RETIRED L1D-ACCESS TLB-ACCESS . 00000019: b0 00 c4 15 08 00 00 ff ff PC 0xff00000815c400 el3 ns=1 . 00000022: 98 00 00 LAT 0 TOT . 00000025: 71 36 6c 21 2c 09 00 00 00 TS 39395093558 . 0000002e: 49 00 LD . 00000030: b2 80 3c 29 0f 00 00 ff ff VA 0xffff00000f293c80 . 00000039: b3 80 ec 24 fb 00 00 00 80 PA 0xfb24ec80 ns=1 . 00000042: 9a 00 00 LAT 0 XLAT . 00000045: 42 16 EV RETIRED L1D-ACCESS TLB-ACCESS . 00000047: b0 f4 11 16 08 00 00 ff ff PC 0xff0000081611f4 el3 ns=1 . 00000050: 98 00 00 LAT 0 TOT . 00000053: 71 36 6c 21 2c 09 00 00 00 TS 39395093558 . 0000005c: 48 00 INSN-OTHER . 0000005e: 42 02 EV RETIRED . 00000060: b0 2c ef 7f 08 00 00 ff ff PC 0xff0000087fef2c el3 ns=1 . 00000069: 98 00 00 LAT 0 TOT . 0000006c: 71 d1 6f 21 2c 09 00 00 00 TS 39395094481 ... Other release notes: - applies to acme's perf/{core,urgent} branches, likely elsewhere - Report is self-contained within the tool. Record requires enabling the kernel SPE driver by setting CONFIG_ARM_SPE_PMU. - The intel-bts implementation was used as a starting point; its min/default/max buffer sizes and power of 2 pages granularity need to be revisited for ARM SPE - Recording across multiple SPE clusters/domains not supported - Snapshot support (record -S), and conversion to native perf events (e.g., via 'perf inject --itrace'), are also not supported - Technically both cs-etm and spe can be used simultaneously, however disabled for simplicity in this release Signed-off-by: Kim Phillips <kim.phillips@arm.com> Reviewed-by: Dongjiu Geng <gengdongjiu@huawei.com> Acked-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: linux-arm-kernel@lists.infradead.org Cc: Marc Zyngier <marc.zyngier@arm.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mathieu Poirier <mathieu.poirier@linaro.org> Cc: Pawel Moll <pawel.moll@arm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rob Herring <robh@kernel.org> Cc: Suzuki Poulouse <suzuki.poulose@arm.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Wang Nan <wangnan0@huawei.com> Cc: Will Deacon <will.deacon@arm.com> Link: http://lkml.kernel.org/r/20180114132850.0b127434b704a26bad13268f@arm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/Build2
-rw-r--r--tools/perf/util/arm-spe-pkt-decoder.c462
-rw-r--r--tools/perf/util/arm-spe-pkt-decoder.h43
-rw-r--r--tools/perf/util/arm-spe.c231
-rw-r--r--tools/perf/util/arm-spe.h31
-rw-r--r--tools/perf/util/auxtrace.c3
-rw-r--r--tools/perf/util/auxtrace.h1
7 files changed, 773 insertions, 0 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index a3de7916fe63..7c6a8b461e24 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -86,6 +86,8 @@ libperf-$(CONFIG_AUXTRACE) += auxtrace.o
86libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ 86libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
87libperf-$(CONFIG_AUXTRACE) += intel-pt.o 87libperf-$(CONFIG_AUXTRACE) += intel-pt.o
88libperf-$(CONFIG_AUXTRACE) += intel-bts.o 88libperf-$(CONFIG_AUXTRACE) += intel-bts.o
89libperf-$(CONFIG_AUXTRACE) += arm-spe.o
90libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
89libperf-y += parse-branch-options.o 91libperf-y += parse-branch-options.o
90libperf-y += dump-insn.o 92libperf-y += dump-insn.o
91libperf-y += parse-regs-options.o 93libperf-y += parse-regs-options.o
diff --git a/tools/perf/util/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-pkt-decoder.c
new file mode 100644
index 000000000000..b94001b756c7
--- /dev/null
+++ b/tools/perf/util/arm-spe-pkt-decoder.c
@@ -0,0 +1,462 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#include <stdio.h>
8#include <string.h>
9#include <endian.h>
10#include <byteswap.h>
11
12#include "arm-spe-pkt-decoder.h"
13
14#define BIT(n) (1ULL << (n))
15
16#define NS_FLAG BIT(63)
17#define EL_FLAG (BIT(62) | BIT(61))
18
19#define SPE_HEADER0_PAD 0x0
20#define SPE_HEADER0_END 0x1
21#define SPE_HEADER0_ADDRESS 0x30 /* address packet (short) */
22#define SPE_HEADER0_ADDRESS_MASK 0x38
23#define SPE_HEADER0_COUNTER 0x18 /* counter packet (short) */
24#define SPE_HEADER0_COUNTER_MASK 0x38
25#define SPE_HEADER0_TIMESTAMP 0x71
26#define SPE_HEADER0_TIMESTAMP 0x71
27#define SPE_HEADER0_EVENTS 0x2
28#define SPE_HEADER0_EVENTS_MASK 0xf
29#define SPE_HEADER0_SOURCE 0x3
30#define SPE_HEADER0_SOURCE_MASK 0xf
31#define SPE_HEADER0_CONTEXT 0x24
32#define SPE_HEADER0_CONTEXT_MASK 0x3c
33#define SPE_HEADER0_OP_TYPE 0x8
34#define SPE_HEADER0_OP_TYPE_MASK 0x3c
35#define SPE_HEADER1_ALIGNMENT 0x0
36#define SPE_HEADER1_ADDRESS 0xb0 /* address packet (extended) */
37#define SPE_HEADER1_ADDRESS_MASK 0xf8
38#define SPE_HEADER1_COUNTER 0x98 /* counter packet (extended) */
39#define SPE_HEADER1_COUNTER_MASK 0xf8
40
41#if __BYTE_ORDER == __BIG_ENDIAN
42#define le16_to_cpu bswap_16
43#define le32_to_cpu bswap_32
44#define le64_to_cpu bswap_64
45#define memcpy_le64(d, s, n) do { \
46 memcpy((d), (s), (n)); \
47 *(d) = le64_to_cpu(*(d)); \
48} while (0)
49#else
50#define le16_to_cpu
51#define le32_to_cpu
52#define le64_to_cpu
53#define memcpy_le64 memcpy
54#endif
55
56static const char * const arm_spe_packet_name[] = {
57 [ARM_SPE_PAD] = "PAD",
58 [ARM_SPE_END] = "END",
59 [ARM_SPE_TIMESTAMP] = "TS",
60 [ARM_SPE_ADDRESS] = "ADDR",
61 [ARM_SPE_COUNTER] = "LAT",
62 [ARM_SPE_CONTEXT] = "CONTEXT",
63 [ARM_SPE_OP_TYPE] = "OP-TYPE",
64 [ARM_SPE_EVENTS] = "EVENTS",
65 [ARM_SPE_DATA_SOURCE] = "DATA-SOURCE",
66};
67
68const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
69{
70 return arm_spe_packet_name[type];
71}
72
73/* return ARM SPE payload size from its encoding,
74 * which is in bits 5:4 of the byte.
75 * 00 : byte
76 * 01 : halfword (2)
77 * 10 : word (4)
78 * 11 : doubleword (8)
79 */
80static int payloadlen(unsigned char byte)
81{
82 return 1 << ((byte & 0x30) >> 4);
83}
84
85static int arm_spe_get_payload(const unsigned char *buf, size_t len,
86 struct arm_spe_pkt *packet)
87{
88 size_t payload_len = payloadlen(buf[0]);
89
90 if (len < 1 + payload_len)
91 return ARM_SPE_NEED_MORE_BYTES;
92
93 buf++;
94
95 switch (payload_len) {
96 case 1: packet->payload = *(uint8_t *)buf; break;
97 case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
98 case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
99 case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
100 default: return ARM_SPE_BAD_PACKET;
101 }
102
103 return 1 + payload_len;
104}
105
106static int arm_spe_get_pad(struct arm_spe_pkt *packet)
107{
108 packet->type = ARM_SPE_PAD;
109 return 1;
110}
111
112static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
113 struct arm_spe_pkt *packet)
114{
115 unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
116
117 if (len < alignment)
118 return ARM_SPE_NEED_MORE_BYTES;
119
120 packet->type = ARM_SPE_PAD;
121 return alignment - (((uintptr_t)buf) & (alignment - 1));
122}
123
124static int arm_spe_get_end(struct arm_spe_pkt *packet)
125{
126 packet->type = ARM_SPE_END;
127 return 1;
128}
129
130static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
131 struct arm_spe_pkt *packet)
132{
133 packet->type = ARM_SPE_TIMESTAMP;
134 return arm_spe_get_payload(buf, len, packet);
135}
136
137static int arm_spe_get_events(const unsigned char *buf, size_t len,
138 struct arm_spe_pkt *packet)
139{
140 int ret = arm_spe_get_payload(buf, len, packet);
141
142 packet->type = ARM_SPE_EVENTS;
143
144 /* we use index to identify Events with a less number of
145 * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
146 * LLC-REFILL, and REMOTE-ACCESS events are identified iff
147 * index > 1.
148 */
149 packet->index = ret - 1;
150
151 return ret;
152}
153
154static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
155 struct arm_spe_pkt *packet)
156{
157 packet->type = ARM_SPE_DATA_SOURCE;
158 return arm_spe_get_payload(buf, len, packet);
159}
160
161static int arm_spe_get_context(const unsigned char *buf, size_t len,
162 struct arm_spe_pkt *packet)
163{
164 packet->type = ARM_SPE_CONTEXT;
165 packet->index = buf[0] & 0x3;
166
167 return arm_spe_get_payload(buf, len, packet);
168}
169
170static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
171 struct arm_spe_pkt *packet)
172{
173 packet->type = ARM_SPE_OP_TYPE;
174 packet->index = buf[0] & 0x3;
175 return arm_spe_get_payload(buf, len, packet);
176}
177
178static int arm_spe_get_counter(const unsigned char *buf, size_t len,
179 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
180{
181 if (len < 2)
182 return ARM_SPE_NEED_MORE_BYTES;
183
184 packet->type = ARM_SPE_COUNTER;
185 if (ext_hdr)
186 packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
187 else
188 packet->index = buf[0] & 0x7;
189
190 packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1));
191
192 return 1 + ext_hdr + 2;
193}
194
195static int arm_spe_get_addr(const unsigned char *buf, size_t len,
196 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
197{
198 if (len < 8)
199 return ARM_SPE_NEED_MORE_BYTES;
200
201 packet->type = ARM_SPE_ADDRESS;
202 if (ext_hdr)
203 packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
204 else
205 packet->index = buf[0] & 0x7;
206
207 memcpy_le64(&packet->payload, buf + 1, 8);
208
209 return 1 + ext_hdr + 8;
210}
211
212static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
213 struct arm_spe_pkt *packet)
214{
215 unsigned int byte;
216
217 memset(packet, 0, sizeof(struct arm_spe_pkt));
218
219 if (!len)
220 return ARM_SPE_NEED_MORE_BYTES;
221
222 byte = buf[0];
223 if (byte == SPE_HEADER0_PAD)
224 return arm_spe_get_pad(packet);
225 else if (byte == SPE_HEADER0_END) /* no timestamp at end of record */
226 return arm_spe_get_end(packet);
227 else if (byte & 0xc0 /* 0y11xxxxxx */) {
228 if (byte & 0x80) {
229 if ((byte & SPE_HEADER0_ADDRESS_MASK) == SPE_HEADER0_ADDRESS)
230 return arm_spe_get_addr(buf, len, 0, packet);
231 if ((byte & SPE_HEADER0_COUNTER_MASK) == SPE_HEADER0_COUNTER)
232 return arm_spe_get_counter(buf, len, 0, packet);
233 } else
234 if (byte == SPE_HEADER0_TIMESTAMP)
235 return arm_spe_get_timestamp(buf, len, packet);
236 else if ((byte & SPE_HEADER0_EVENTS_MASK) == SPE_HEADER0_EVENTS)
237 return arm_spe_get_events(buf, len, packet);
238 else if ((byte & SPE_HEADER0_SOURCE_MASK) == SPE_HEADER0_SOURCE)
239 return arm_spe_get_data_source(buf, len, packet);
240 else if ((byte & SPE_HEADER0_CONTEXT_MASK) == SPE_HEADER0_CONTEXT)
241 return arm_spe_get_context(buf, len, packet);
242 else if ((byte & SPE_HEADER0_OP_TYPE_MASK) == SPE_HEADER0_OP_TYPE)
243 return arm_spe_get_op_type(buf, len, packet);
244 } else if ((byte & 0xe0) == 0x20 /* 0y001xxxxx */) {
245 /* 16-bit header */
246 byte = buf[1];
247 if (byte == SPE_HEADER1_ALIGNMENT)
248 return arm_spe_get_alignment(buf, len, packet);
249 else if ((byte & SPE_HEADER1_ADDRESS_MASK) == SPE_HEADER1_ADDRESS)
250 return arm_spe_get_addr(buf, len, 1, packet);
251 else if ((byte & SPE_HEADER1_COUNTER_MASK) == SPE_HEADER1_COUNTER)
252 return arm_spe_get_counter(buf, len, 1, packet);
253 }
254
255 return ARM_SPE_BAD_PACKET;
256}
257
258int arm_spe_get_packet(const unsigned char *buf, size_t len,
259 struct arm_spe_pkt *packet)
260{
261 int ret;
262
263 ret = arm_spe_do_get_packet(buf, len, packet);
264 /* put multiple consecutive PADs on the same line, up to
265 * the fixed-width output format of 16 bytes per line.
266 */
267 if (ret > 0 && packet->type == ARM_SPE_PAD) {
268 while (ret < 16 && len > (size_t)ret && !buf[ret])
269 ret += 1;
270 }
271 return ret;
272}
273
274int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
275 size_t buf_len)
276{
277 int ret, ns, el, idx = packet->index;
278 unsigned long long payload = packet->payload;
279 const char *name = arm_spe_pkt_name(packet->type);
280
281 switch (packet->type) {
282 case ARM_SPE_BAD:
283 case ARM_SPE_PAD:
284 case ARM_SPE_END:
285 return snprintf(buf, buf_len, "%s", name);
286 case ARM_SPE_EVENTS: {
287 size_t blen = buf_len;
288
289 ret = 0;
290 ret = snprintf(buf, buf_len, "EV");
291 buf += ret;
292 blen -= ret;
293 if (payload & 0x1) {
294 ret = snprintf(buf, buf_len, " EXCEPTION-GEN");
295 buf += ret;
296 blen -= ret;
297 }
298 if (payload & 0x2) {
299 ret = snprintf(buf, buf_len, " RETIRED");
300 buf += ret;
301 blen -= ret;
302 }
303 if (payload & 0x4) {
304 ret = snprintf(buf, buf_len, " L1D-ACCESS");
305 buf += ret;
306 blen -= ret;
307 }
308 if (payload & 0x8) {
309 ret = snprintf(buf, buf_len, " L1D-REFILL");
310 buf += ret;
311 blen -= ret;
312 }
313 if (payload & 0x10) {
314 ret = snprintf(buf, buf_len, " TLB-ACCESS");
315 buf += ret;
316 blen -= ret;
317 }
318 if (payload & 0x20) {
319 ret = snprintf(buf, buf_len, " TLB-REFILL");
320 buf += ret;
321 blen -= ret;
322 }
323 if (payload & 0x40) {
324 ret = snprintf(buf, buf_len, " NOT-TAKEN");
325 buf += ret;
326 blen -= ret;
327 }
328 if (payload & 0x80) {
329 ret = snprintf(buf, buf_len, " MISPRED");
330 buf += ret;
331 blen -= ret;
332 }
333 if (idx > 1) {
334 if (payload & 0x100) {
335 ret = snprintf(buf, buf_len, " LLC-ACCESS");
336 buf += ret;
337 blen -= ret;
338 }
339 if (payload & 0x200) {
340 ret = snprintf(buf, buf_len, " LLC-REFILL");
341 buf += ret;
342 blen -= ret;
343 }
344 if (payload & 0x400) {
345 ret = snprintf(buf, buf_len, " REMOTE-ACCESS");
346 buf += ret;
347 blen -= ret;
348 }
349 }
350 if (ret < 0)
351 return ret;
352 blen -= ret;
353 return buf_len - blen;
354 }
355 case ARM_SPE_OP_TYPE:
356 switch (idx) {
357 case 0: return snprintf(buf, buf_len, "%s", payload & 0x1 ?
358 "COND-SELECT" : "INSN-OTHER");
359 case 1: {
360 size_t blen = buf_len;
361
362 if (payload & 0x1)
363 ret = snprintf(buf, buf_len, "ST");
364 else
365 ret = snprintf(buf, buf_len, "LD");
366 buf += ret;
367 blen -= ret;
368 if (payload & 0x2) {
369 if (payload & 0x4) {
370 ret = snprintf(buf, buf_len, " AT");
371 buf += ret;
372 blen -= ret;
373 }
374 if (payload & 0x8) {
375 ret = snprintf(buf, buf_len, " EXCL");
376 buf += ret;
377 blen -= ret;
378 }
379 if (payload & 0x10) {
380 ret = snprintf(buf, buf_len, " AR");
381 buf += ret;
382 blen -= ret;
383 }
384 } else if (payload & 0x4) {
385 ret = snprintf(buf, buf_len, " SIMD-FP");
386 buf += ret;
387 blen -= ret;
388 }
389 if (ret < 0)
390 return ret;
391 blen -= ret;
392 return buf_len - blen;
393 }
394 case 2: {
395 size_t blen = buf_len;
396
397 ret = snprintf(buf, buf_len, "B");
398 buf += ret;
399 blen -= ret;
400 if (payload & 0x1) {
401 ret = snprintf(buf, buf_len, " COND");
402 buf += ret;
403 blen -= ret;
404 }
405 if (payload & 0x2) {
406 ret = snprintf(buf, buf_len, " IND");
407 buf += ret;
408 blen -= ret;
409 }
410 if (ret < 0)
411 return ret;
412 blen -= ret;
413 return buf_len - blen;
414 }
415 default: return 0;
416 }
417 case ARM_SPE_DATA_SOURCE:
418 case ARM_SPE_TIMESTAMP:
419 return snprintf(buf, buf_len, "%s %lld", name, payload);
420 case ARM_SPE_ADDRESS:
421 switch (idx) {
422 case 0:
423 case 1: ns = !!(packet->payload & NS_FLAG);
424 el = (packet->payload & EL_FLAG) >> 61;
425 payload &= ~(0xffULL << 56);
426 return snprintf(buf, buf_len, "%s 0x%llx el%d ns=%d",
427 (idx == 1) ? "TGT" : "PC", payload, el, ns);
428 case 2: return snprintf(buf, buf_len, "VA 0x%llx", payload);
429 case 3: ns = !!(packet->payload & NS_FLAG);
430 payload &= ~(0xffULL << 56);
431 return snprintf(buf, buf_len, "PA 0x%llx ns=%d",
432 payload, ns);
433 default: return 0;
434 }
435 case ARM_SPE_CONTEXT:
436 return snprintf(buf, buf_len, "%s 0x%lx el%d", name,
437 (unsigned long)payload, idx + 1);
438 case ARM_SPE_COUNTER: {
439 size_t blen = buf_len;
440
441 ret = snprintf(buf, buf_len, "%s %d ", name,
442 (unsigned short)payload);
443 buf += ret;
444 blen -= ret;
445 switch (idx) {
446 case 0: ret = snprintf(buf, buf_len, "TOT"); break;
447 case 1: ret = snprintf(buf, buf_len, "ISSUE"); break;
448 case 2: ret = snprintf(buf, buf_len, "XLAT"); break;
449 default: ret = 0;
450 }
451 if (ret < 0)
452 return ret;
453 blen -= ret;
454 return buf_len - blen;
455 }
456 default:
457 break;
458 }
459
460 return snprintf(buf, buf_len, "%s 0x%llx (%d)",
461 name, payload, packet->index);
462}
diff --git a/tools/perf/util/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-pkt-decoder.h
new file mode 100644
index 000000000000..d786ef65113f
--- /dev/null
+++ b/tools/perf/util/arm-spe-pkt-decoder.h
@@ -0,0 +1,43 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#ifndef INCLUDE__ARM_SPE_PKT_DECODER_H__
8#define INCLUDE__ARM_SPE_PKT_DECODER_H__
9
10#include <stddef.h>
11#include <stdint.h>
12
13#define ARM_SPE_PKT_DESC_MAX 256
14
15#define ARM_SPE_NEED_MORE_BYTES -1
16#define ARM_SPE_BAD_PACKET -2
17
18enum arm_spe_pkt_type {
19 ARM_SPE_BAD,
20 ARM_SPE_PAD,
21 ARM_SPE_END,
22 ARM_SPE_TIMESTAMP,
23 ARM_SPE_ADDRESS,
24 ARM_SPE_COUNTER,
25 ARM_SPE_CONTEXT,
26 ARM_SPE_OP_TYPE,
27 ARM_SPE_EVENTS,
28 ARM_SPE_DATA_SOURCE,
29};
30
31struct arm_spe_pkt {
32 enum arm_spe_pkt_type type;
33 unsigned char index;
34 uint64_t payload;
35};
36
37const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
38
39int arm_spe_get_packet(const unsigned char *buf, size_t len,
40 struct arm_spe_pkt *packet);
41
42int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, size_t len);
43#endif
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
new file mode 100644
index 000000000000..6067267cc76c
--- /dev/null
+++ b/tools/perf/util/arm-spe.c
@@ -0,0 +1,231 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#include <endian.h>
8#include <errno.h>
9#include <byteswap.h>
10#include <inttypes.h>
11#include <linux/kernel.h>
12#include <linux/types.h>
13#include <linux/bitops.h>
14#include <linux/log2.h>
15
16#include "cpumap.h"
17#include "color.h"
18#include "evsel.h"
19#include "evlist.h"
20#include "machine.h"
21#include "session.h"
22#include "util.h"
23#include "thread.h"
24#include "debug.h"
25#include "auxtrace.h"
26#include "arm-spe.h"
27#include "arm-spe-pkt-decoder.h"
28
29struct arm_spe {
30 struct auxtrace auxtrace;
31 struct auxtrace_queues queues;
32 struct auxtrace_heap heap;
33 u32 auxtrace_type;
34 struct perf_session *session;
35 struct machine *machine;
36 u32 pmu_type;
37};
38
39struct arm_spe_queue {
40 struct arm_spe *spe;
41 unsigned int queue_nr;
42 struct auxtrace_buffer *buffer;
43 bool on_heap;
44 bool done;
45 pid_t pid;
46 pid_t tid;
47 int cpu;
48};
49
50static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
51 unsigned char *buf, size_t len)
52{
53 struct arm_spe_pkt packet;
54 size_t pos = 0;
55 int ret, pkt_len, i;
56 char desc[ARM_SPE_PKT_DESC_MAX];
57 const char *color = PERF_COLOR_BLUE;
58
59 color_fprintf(stdout, color,
60 ". ... ARM SPE data: size %zu bytes\n",
61 len);
62
63 while (len) {
64 ret = arm_spe_get_packet(buf, len, &packet);
65 if (ret > 0)
66 pkt_len = ret;
67 else
68 pkt_len = 1;
69 printf(".");
70 color_fprintf(stdout, color, " %08x: ", pos);
71 for (i = 0; i < pkt_len; i++)
72 color_fprintf(stdout, color, " %02x", buf[i]);
73 for (; i < 16; i++)
74 color_fprintf(stdout, color, " ");
75 if (ret > 0) {
76 ret = arm_spe_pkt_desc(&packet, desc,
77 ARM_SPE_PKT_DESC_MAX);
78 if (ret > 0)
79 color_fprintf(stdout, color, " %s\n", desc);
80 } else {
81 color_fprintf(stdout, color, " Bad packet!\n");
82 }
83 pos += pkt_len;
84 buf += pkt_len;
85 len -= pkt_len;
86 }
87}
88
89static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
90 size_t len)
91{
92 printf(".\n");
93 arm_spe_dump(spe, buf, len);
94}
95
96static int arm_spe_process_event(struct perf_session *session __maybe_unused,
97 union perf_event *event __maybe_unused,
98 struct perf_sample *sample __maybe_unused,
99 struct perf_tool *tool __maybe_unused)
100{
101 return 0;
102}
103
104static int arm_spe_process_auxtrace_event(struct perf_session *session,
105 union perf_event *event,
106 struct perf_tool *tool __maybe_unused)
107{
108 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
109 auxtrace);
110 struct auxtrace_buffer *buffer;
111 off_t data_offset;
112 int fd = perf_data__fd(session->data);
113 int err;
114
115 if (perf_data__is_pipe(session->data)) {
116 data_offset = 0;
117 } else {
118 data_offset = lseek(fd, 0, SEEK_CUR);
119 if (data_offset == -1)
120 return -errno;
121 }
122
123 err = auxtrace_queues__add_event(&spe->queues, session, event,
124 data_offset, &buffer);
125 if (err)
126 return err;
127
128 /* Dump here now we have copied a piped trace out of the pipe */
129 if (dump_trace) {
130 if (auxtrace_buffer__get_data(buffer, fd)) {
131 arm_spe_dump_event(spe, buffer->data,
132 buffer->size);
133 auxtrace_buffer__put_data(buffer);
134 }
135 }
136
137 return 0;
138}
139
140static int arm_spe_flush(struct perf_session *session __maybe_unused,
141 struct perf_tool *tool __maybe_unused)
142{
143 return 0;
144}
145
146static void arm_spe_free_queue(void *priv)
147{
148 struct arm_spe_queue *speq = priv;
149
150 if (!speq)
151 return;
152 free(speq);
153}
154
155static void arm_spe_free_events(struct perf_session *session)
156{
157 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
158 auxtrace);
159 struct auxtrace_queues *queues = &spe->queues;
160 unsigned int i;
161
162 for (i = 0; i < queues->nr_queues; i++) {
163 arm_spe_free_queue(queues->queue_array[i].priv);
164 queues->queue_array[i].priv = NULL;
165 }
166 auxtrace_queues__free(queues);
167}
168
169static void arm_spe_free(struct perf_session *session)
170{
171 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
172 auxtrace);
173
174 auxtrace_heap__free(&spe->heap);
175 arm_spe_free_events(session);
176 session->auxtrace = NULL;
177 free(spe);
178}
179
180static const char * const arm_spe_info_fmts[] = {
181 [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n",
182};
183
184static void arm_spe_print_info(u64 *arr)
185{
186 if (!dump_trace)
187 return;
188
189 fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
190}
191
192int arm_spe_process_auxtrace_info(union perf_event *event,
193 struct perf_session *session)
194{
195 struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
196 size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE;
197 struct arm_spe *spe;
198 int err;
199
200 if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) +
201 min_sz)
202 return -EINVAL;
203
204 spe = zalloc(sizeof(struct arm_spe));
205 if (!spe)
206 return -ENOMEM;
207
208 err = auxtrace_queues__init(&spe->queues);
209 if (err)
210 goto err_free;
211
212 spe->session = session;
213 spe->machine = &session->machines.host; /* No kvm support */
214 spe->auxtrace_type = auxtrace_info->type;
215 spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
216
217 spe->auxtrace.process_event = arm_spe_process_event;
218 spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event;
219 spe->auxtrace.flush_events = arm_spe_flush;
220 spe->auxtrace.free_events = arm_spe_free_events;
221 spe->auxtrace.free = arm_spe_free;
222 session->auxtrace = &spe->auxtrace;
223
224 arm_spe_print_info(&auxtrace_info->priv[0]);
225
226 return 0;
227
228err_free:
229 free(spe);
230 return err;
231}
diff --git a/tools/perf/util/arm-spe.h b/tools/perf/util/arm-spe.h
new file mode 100644
index 000000000000..98d3235781c3
--- /dev/null
+++ b/tools/perf/util/arm-spe.h
@@ -0,0 +1,31 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#ifndef INCLUDE__PERF_ARM_SPE_H__
8#define INCLUDE__PERF_ARM_SPE_H__
9
10#define ARM_SPE_PMU_NAME "arm_spe_"
11
12enum {
13 ARM_SPE_PMU_TYPE,
14 ARM_SPE_PER_CPU_MMAPS,
15 ARM_SPE_AUXTRACE_PRIV_MAX,
16};
17
18#define ARM_SPE_AUXTRACE_PRIV_SIZE (ARM_SPE_AUXTRACE_PRIV_MAX * sizeof(u64))
19
20union perf_event;
21struct perf_session;
22struct perf_pmu;
23
24struct auxtrace_record *arm_spe_recording_init(int *err,
25 struct perf_pmu *arm_spe_pmu);
26
27int arm_spe_process_auxtrace_info(union perf_event *event,
28 struct perf_session *session);
29
30struct perf_event_attr *arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu);
31#endif
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index c76687e42344..3bba9947ab7f 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -54,6 +54,7 @@
54 54
55#include "intel-pt.h" 55#include "intel-pt.h"
56#include "intel-bts.h" 56#include "intel-bts.h"
57#include "arm-spe.h"
57 58
58#include "sane_ctype.h" 59#include "sane_ctype.h"
59#include "symbol/kallsyms.h" 60#include "symbol/kallsyms.h"
@@ -910,6 +911,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
910 return intel_pt_process_auxtrace_info(event, session); 911 return intel_pt_process_auxtrace_info(event, session);
911 case PERF_AUXTRACE_INTEL_BTS: 912 case PERF_AUXTRACE_INTEL_BTS:
912 return intel_bts_process_auxtrace_info(event, session); 913 return intel_bts_process_auxtrace_info(event, session);
914 case PERF_AUXTRACE_ARM_SPE:
915 return arm_spe_process_auxtrace_info(event, session);
913 case PERF_AUXTRACE_CS_ETM: 916 case PERF_AUXTRACE_CS_ETM:
914 case PERF_AUXTRACE_UNKNOWN: 917 case PERF_AUXTRACE_UNKNOWN:
915 default: 918 default:
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index d19e11b68de7..453c148d2158 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -43,6 +43,7 @@ enum auxtrace_type {
43 PERF_AUXTRACE_INTEL_PT, 43 PERF_AUXTRACE_INTEL_PT,
44 PERF_AUXTRACE_INTEL_BTS, 44 PERF_AUXTRACE_INTEL_BTS,
45 PERF_AUXTRACE_CS_ETM, 45 PERF_AUXTRACE_CS_ETM,
46 PERF_AUXTRACE_ARM_SPE,
46}; 47};
47 48
48enum itrace_period_type { 49enum itrace_period_type {