1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "spe_decoder.h"
17 #include "hiperf_hilog.h"
18
19 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20 #define LE16_TO_CPU bswap_16
21 #define LE32_TO_CPU bswap_32
22 #define LE64_TO_CPU bswap_64
23 #else
24 #define LE16_TO_CPU
25 #define LE32_TO_CPU
26 #define LE64_TO_CPU
27 #endif
28
29 namespace OHOS {
30 namespace Developtools {
31 namespace HiPerf {
32 constexpr const int UN_PRMT = -1;
33
SpePktName(enum SpePktType type)34 const char *SpePktName(enum SpePktType type)
35 {
36 const char* spePacketName;
37 switch (type) {
38 case PERF_SPE_PAD: spePacketName = "PAD"; break;
39 case PERF_SPE_END: spePacketName = "END"; break;
40 case PERF_SPE_TIMESTAMP: spePacketName = "TS"; break;
41 case PERF_SPE_ADDRESS: spePacketName = "ADDR"; break;
42 case PERF_SPE_COUNTER: spePacketName = "LAT"; break;
43 case PERF_SPE_CONTEXT: spePacketName = "CONTEXT"; break;
44 case PERF_SPE_OP_TYPE: spePacketName = "OP-TYPE"; break;
45 case PERF_SPE_EVENTS: spePacketName = "EVENTS"; break;
46 case PERF_SPE_DATA_SOURCE: spePacketName = "DATA-SOURCE"; break;
47 default: spePacketName = "INVALID"; break;
48 }
49 return spePacketName;
50 }
51
SpePayloadLen(unsigned char hdr)52 static unsigned int SpePayloadLen(unsigned char hdr)
53 {
54 return 1U << PERF_SPE_HDR_GET_BYTES_5_4(hdr);
55 }
56
SpeGetPayload(const unsigned char * buf,size_t len,unsigned char extHdr,struct SpePkt * packet)57 static int SpeGetPayload(const unsigned char *buf, size_t len,
58 unsigned char extHdr, struct SpePkt *packet)
59 {
60 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
61 size_t payloadLen = SpePayloadLen(buf[extHdr]);
62 if (len < 1 + extHdr + payloadLen) {
63 return PERF_SPE_NEED_MORE_BYTES;
64 }
65 buf += 1 + extHdr;
66
67 switch (payloadLen) {
68 case LEN_TYPE_BYTE: packet->payload = *(reinterpret_cast<const uint8_t *>(buf)); break;
69 case LEN_TYPE_HLFWRD: packet->payload = LE16_TO_CPU(*reinterpret_cast<const uint16_t *>(buf)); break;
70 case LEN_TYPE_WORD: packet->payload = LE32_TO_CPU(*reinterpret_cast<const uint32_t *>(buf)); break;
71 case LEN_TYPE_DBLEWRD: packet->payload = LE64_TO_CPU(*reinterpret_cast<const uint64_t *>(buf)); break;
72 default: return PERF_SPE_BAD_PACKET;
73 }
74
75 return 1 + extHdr + payloadLen;
76 }
77
SpeGetPad(struct SpePkt * packet)78 static int SpeGetPad(struct SpePkt *packet)
79 {
80 CHECK_TRUE(packet == nullptr, -1, 1, "Invalid pointer!");
81 packet->type = PERF_SPE_PAD;
82 return 1;
83 }
84
SpeGetAlignment(const unsigned char * buf,size_t len,struct SpePkt * packet)85 static int SpeGetAlignment(const unsigned char *buf, size_t len,
86 struct SpePkt *packet)
87 {
88 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
89 unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
90
91 if (len < alignment)
92 return PERF_SPE_NEED_MORE_BYTES;
93
94 packet->type = PERF_SPE_PAD;
95 return alignment - (((uintptr_t)buf) & (alignment - 1));
96 }
97
SpeGetEnd(struct SpePkt * packet)98 static int SpeGetEnd(struct SpePkt *packet)
99 {
100 CHECK_TRUE(packet == nullptr, -1, 1, "Invalid pointer!");
101 packet->type = PERF_SPE_END;
102 return 1;
103 }
104
SpeGetTimestamp(const unsigned char * buf,size_t len,struct SpePkt * packet)105 static int SpeGetTimestamp(const unsigned char *buf, size_t len,
106 struct SpePkt *packet)
107 {
108 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
109 packet->type = PERF_SPE_TIMESTAMP;
110 return SpeGetPayload(buf, len, 0, packet);
111 }
112
SpeGetEvents(const unsigned char * buf,size_t len,struct SpePkt * packet)113 static int SpeGetEvents(const unsigned char *buf, size_t len,
114 struct SpePkt *packet)
115 {
116 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
117 packet->type = PERF_SPE_EVENTS;
118 packet->index = SpePayloadLen(buf[0]);
119 return SpeGetPayload(buf, len, 0, packet);
120 }
121
SpeGetDataSource(const unsigned char * buf,size_t len,struct SpePkt * packet)122 static int SpeGetDataSource(const unsigned char *buf, size_t len,
123 struct SpePkt *packet)
124 {
125 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
126 packet->type = PERF_SPE_DATA_SOURCE;
127 return SpeGetPayload(buf, len, 0, packet);
128 }
129
SpeGetContext(const unsigned char * buf,size_t len,struct SpePkt * packet)130 static int SpeGetContext(const unsigned char *buf, size_t len,
131 struct SpePkt *packet)
132 {
133 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
134 packet->type = PERF_SPE_CONTEXT;
135 packet->index = PERF_SPE_CTX_PKT_HDR_INDEX(buf[0]);
136 return SpeGetPayload(buf, len, 0, packet);
137 }
138
SpeGetOpType(const unsigned char * buf,size_t len,struct SpePkt * packet)139 static int SpeGetOpType(const unsigned char *buf, size_t len,
140 struct SpePkt *packet)
141 {
142 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
143 packet->type = PERF_SPE_OP_TYPE;
144 packet->index = PERF_SPE_OP_PKT_HDR_CLASS(buf[0]);
145 return SpeGetPayload(buf, len, 0, packet);
146 }
147
SpeGetCounter(const unsigned char * buf,size_t len,const unsigned char extHdr,struct SpePkt * packet)148 static int SpeGetCounter(const unsigned char *buf, size_t len,
149 const unsigned char extHdr, struct SpePkt *packet)
150 {
151 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
152 packet->type = PERF_SPE_COUNTER;
153 if (extHdr) {
154 packet->index = PERF_SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
155 } else {
156 packet->index = PERF_SPE_HDR_SHORT_INDEX(buf[0]);
157 }
158
159 return SpeGetPayload(buf, len, extHdr, packet);
160 }
161
SpeGetAddr(const unsigned char * buf,size_t len,const unsigned char extHdr,struct SpePkt * packet)162 static int SpeGetAddr(const unsigned char *buf, size_t len,
163 const unsigned char extHdr, struct SpePkt *packet)
164 {
165 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
166 packet->type = PERF_SPE_ADDRESS;
167 if (extHdr) {
168 packet->index = PERF_SPE_HDR_EXTENDED_INDEX(buf[0], buf[1]);
169 } else {
170 packet->index = PERF_SPE_HDR_SHORT_INDEX(buf[0]);
171 }
172
173 return SpeGetPayload(buf, len, extHdr, packet);
174 }
175
SpeDoGetPacket(const unsigned char * buf,size_t len,struct SpePkt * packet)176 static int SpeDoGetPacket(const unsigned char *buf, size_t len,
177 struct SpePkt *packet)
178 {
179 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
180 unsigned int hdr;
181 unsigned char extHdr = 0;
182
183 memset_s(packet, sizeof(struct SpePkt), 0, sizeof(struct SpePkt));
184
185 if (!len) {
186 return PERF_SPE_NEED_MORE_BYTES;
187 }
188
189 hdr = buf[0];
190 if (hdr == PERF_SPE_HEADER0_PAD) {
191 return SpeGetPad(packet);
192 } else if (hdr == PERF_SPE_HEADER0_END) { /* no timestamp at end of record */
193 return SpeGetEnd(packet);
194 }
195 if (hdr == PERF_SPE_HEADER0_TIMESTAMP) {
196 return SpeGetTimestamp(buf, len, packet);
197 } else if ((hdr & PERF_SPE_HEADER0_MASK1) == PERF_SPE_HEADER0_EVENTS) {
198 return SpeGetEvents(buf, len, packet);
199 } else if ((hdr & PERF_SPE_HEADER0_MASK1) == PERF_SPE_HEADER0_SOURCE) {
200 return SpeGetDataSource(buf, len, packet);
201 } else if ((hdr & PERF_SPE_HEADER0_MASK2) == PERF_SPE_HEADER0_CONTEXT) {
202 return SpeGetContext(buf, len, packet);
203 } else if ((hdr & PERF_SPE_HEADER0_MASK2) == PERF_SPE_HEADER0_OP_TYPE) {
204 return SpeGetOpType(buf, len, packet);
205 }
206 if ((hdr & PERF_SPE_HEADER0_MASK2) == PERF_SPE_HEADER0_EXTENDED) {
207 /* 16-bit extended format header */
208 if (len == 1) {
209 return PERF_SPE_BAD_PACKET;
210 }
211
212 extHdr = 1;
213 hdr = buf[1];
214 if (hdr == PERF_SPE_HEADER1_ALIGNMENT) {
215 return SpeGetAlignment(buf, len, packet);
216 }
217 }
218
219 /*
220 * The short format header's byte 0 or the extended format header's
221 * byte 1 has been assigned to 'hdr', which uses the same encoding for
222 * address packet and counter packet, so don't need to distinguish if
223 * it's short format or extended format and handle in once.
224 */
225 if ((hdr & PERF_SPE_HEADER0_MASK3) == PERF_SPE_HEADER0_ADDRESS) {
226 return SpeGetAddr(buf, len, extHdr, packet);
227 }
228
229 if ((hdr & PERF_SPE_HEADER0_MASK3) == PERF_SPE_HEADER0_COUNTER) {
230 return SpeGetCounter(buf, len, extHdr, packet);
231 }
232 return PERF_SPE_BAD_PACKET;
233 }
234
SpeGetPacket(const unsigned char * buf,size_t len,struct SpePkt * packet)235 int SpeGetPacket(const unsigned char *buf, size_t len,
236 struct SpePkt *packet)
237 {
238 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
239 int ret = SpeDoGetPacket(buf, len, packet);
240 /* put multiple consecutive PADs on the same line, up to
241 * the fixed-width output format of 16 bytes per line.
242 */
243 if (ret > 0 && packet->type == PERF_SPE_PAD) {
244 while (ret < BYTE_WIDTH && len > (size_t)ret && !buf[ret]) {
245 ret += 1;
246 }
247 }
248 return ret;
249 }
250
SpePktOutString(int * err,char ** bufPtr,size_t * bufLen,const char * fmt,...)251 static int SpePktOutString(int *err, char **bufPtr, size_t *bufLen,
252 const char *fmt, ...)
253 {
254 CHECK_TRUE(*bufPtr == nullptr || bufLen == nullptr || fmt == nullptr, -1, 1, "Invalid pointer!");
255 va_list args;
256 int ret = 0;
257
258 /* If any errors occur, exit */
259 if (err && *err) {
260 return *err;
261 }
262
263 va_start(args, fmt);
264 ret = vsnprintf_s(*bufPtr, *bufLen, *bufLen - 1, fmt, args);
265 va_end(args);
266
267 if (ret < 0) {
268 if (err && !*err) {
269 *err = ret;
270 }
271
272 /*
273 * If the return value is *bufLen or greater, the output was
274 * truncated and the buffer overflowed.
275 */
276 } else if ((size_t)ret >= *bufLen) {
277 (*bufPtr)[*bufLen - 1] = '\0';
278
279 /*
280 * Set *err to 'ret' to avoid overflow if tries to
281 * fill this buffer sequentially.
282 */
283 if (err && !*err) {
284 *err = ret;
285 }
286 } else {
287 *bufPtr += ret;
288 *bufLen -= ret;
289 }
290
291 return ret;
292 }
293
SpePktDescEvent(const struct SpePkt * packet,char * buf,size_t bufLen)294 static int SpePktDescEvent(const struct SpePkt *packet,
295 char *buf, size_t bufLen)
296 {
297 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
298 u64 payload = packet->payload;
299 int err = 0;
300
301 SpePktOutString(&err, &buf, &bufLen, "EV");
302 if (payload & BIT(EVENT_EXCEPTION_GEN)) {
303 SpePktOutString(&err, &buf, &bufLen, " EXCEPTION-GEN");
304 }
305 if (payload & BIT(EVENT_RETIRED)) {
306 SpePktOutString(&err, &buf, &bufLen, " RETIRED");
307 }
308 if (payload & BIT(EVENT_L1D_ACCESS)) {
309 SpePktOutString(&err, &buf, &bufLen, " L1D-ACCESS");
310 }
311 if (payload & BIT(EVENT_L1D_REFILL)) {
312 SpePktOutString(&err, &buf, &bufLen, " L1D-REFILL");
313 }
314 if (payload & BIT(EVENT_TLB_ACCESS)) {
315 SpePktOutString(&err, &buf, &bufLen, " TLB-ACCESS");
316 }
317 if (payload & BIT(EVENT_TLB_WALK)) {
318 SpePktOutString(&err, &buf, &bufLen, " TLB-REFILL");
319 }
320 if (payload & BIT(EVENT_NOT_TAKEN)) {
321 SpePktOutString(&err, &buf, &bufLen, " NOT-TAKEN");
322 }
323 if (payload & BIT(EVENT_MISPRED)) {
324 SpePktOutString(&err, &buf, &bufLen, " MISPRED");
325 }
326 if (payload & BIT(EVENT_LLC_ACCESS)) {
327 SpePktOutString(&err, &buf, &bufLen, " LLC-ACCESS");
328 }
329 if (payload & BIT(EVENT_LLC_MISS)) {
330 SpePktOutString(&err, &buf, &bufLen, " LLC-REFILL");
331 }
332 if (payload & BIT(EVENT_REMOTE_ACCESS)) {
333 SpePktOutString(&err, &buf, &bufLen, " REMOTE-ACCESS");
334 }
335 if (payload & BIT(EVENT_ALIGNMENT)) {
336 SpePktOutString(&err, &buf, &bufLen, " ALIGNMENT");
337 }
338 if (payload & BIT(EVENT_PARTIAL_PREDICATE)) {
339 SpePktOutString(&err, &buf, &bufLen, " SVE-PARTIAL-PRED");
340 }
341 if (payload & BIT(EVENT_EMPTY_PREDICATE)) {
342 SpePktOutString(&err, &buf, &bufLen, " SVE-EMPTY-PRED");
343 }
344
345 return err;
346 }
347
SpePktDescOpType(const struct SpePkt * packet,char * buf,size_t bufLen)348 static int SpePktDescOpType(const struct SpePkt *packet,
349 char *buf, size_t bufLen)
350 {
351 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
352 u64 payload = packet->payload;
353 int err = 0;
354
355 switch (packet->index) {
356 case PERF_SPE_OP_PKT_HDR_CLASS_OTHER:
357 if (PERF_SPE_OP_PKT_IS_OTHER_SVE_OP(payload)) {
358 SpePktOutString(&err, &buf, &bufLen, "SVE-OTHER");
359
360 /* SVE effective vector length */
361 SpePktOutString(&err, &buf, &bufLen, " EVLEN %d",
362 PERF_SPE_OP_PKG_SVE_EVL(payload));
363
364 if (payload & PERF_SPE_OP_PKT_SVE_FP)
365 SpePktOutString(&err, &buf, &bufLen, " FP");
366 if (payload & PERF_SPE_OP_PKT_SVE_PRED)
367 SpePktOutString(&err, &buf, &bufLen, " PRED");
368 } else {
369 SpePktOutString(&err, &buf, &bufLen, "OTHER");
370 SpePktOutString(&err, &buf, &bufLen, " %s",
371 payload & PERF_SPE_OP_PKT_COND ?
372 "COND-SELECT" : "INSN-OTHER");
373 }
374 break;
375 case PERF_SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC:
376 SpePktOutString(&err, &buf, &bufLen,
377 payload & 0x1 ? "ST" : "LD");
378
379 if (PERF_SPE_OP_PKT_IS_LDST_ATOMIC(payload)) {
380 if (payload & PERF_SPE_OP_PKT_AT)
381 SpePktOutString(&err, &buf, &bufLen, " AT");
382 if (payload & PERF_SPE_OP_PKT_EXCL)
383 SpePktOutString(&err, &buf, &bufLen, " EXCL");
384 if (payload & PERF_SPE_OP_PKT_AR)
385 SpePktOutString(&err, &buf, &bufLen, " AR");
386 }
387
388 switch (PERF_SPE_OP_PKT_LDST_SUBCLASS_GET(payload)) {
389 case PERF_SPE_OP_PKT_LDST_SUBCLASS_SIMD_FP:
390 SpePktOutString(&err, &buf, &bufLen, " SIMD-FP");
391 break;
392 case PERF_SPE_OP_PKT_LDST_SUBCLASS_GP_REG:
393 SpePktOutString(&err, &buf, &bufLen, " GP-REG");
394 break;
395 case PERF_SPE_OP_PKT_LDST_SUBCLASS_UNSPEC_REG:
396 SpePktOutString(&err, &buf, &bufLen, " UNSPEC-REG");
397 break;
398 case PERF_SPE_OP_PKT_LDST_SUBCLASS_NV_SYSREG:
399 SpePktOutString(&err, &buf, &bufLen, " NV-SYSREG");
400 break;
401 case PERF_SPE_OP_PKT_LDST_SUBCLASS_MTE_TAG:
402 SpePktOutString(&err, &buf, &bufLen, " MTE-TAG");
403 break;
404 case PERF_SPE_OP_PKT_LDST_SUBCLASS_MEMCPY:
405 SpePktOutString(&err, &buf, &bufLen, " MEMCPY");
406 break;
407 case PERF_SPE_OP_PKT_LDST_SUBCLASS_MEMSET:
408 SpePktOutString(&err, &buf, &bufLen, " MEMSET");
409 break;
410 default:
411 break;
412 }
413
414 if (PERF_SPE_OP_PKT_IS_LDST_SVE(payload)) {
415 /* SVE effective vector length */
416 SpePktOutString(&err, &buf, &bufLen, " EVLEN %d",
417 PERF_SPE_OP_PKG_SVE_EVL(payload));
418
419 if (payload & PERF_SPE_OP_PKT_SVE_PRED)
420 SpePktOutString(&err, &buf, &bufLen, " PRED");
421 if (payload & PERF_SPE_OP_PKT_SVE_SG)
422 SpePktOutString(&err, &buf, &bufLen, " SG");
423 }
424 break;
425 case PERF_SPE_OP_PKT_HDR_CLASS_BR_ERET:
426 SpePktOutString(&err, &buf, &bufLen, "B");
427
428 if (payload & PERF_SPE_OP_PKT_COND)
429 SpePktOutString(&err, &buf, &bufLen, " COND");
430
431 if (PERF_SPE_OP_PKT_IS_INDIRECT_BRANCH(payload))
432 SpePktOutString(&err, &buf, &bufLen, " IND");
433
434 break;
435 default:
436 /* Unknown packet index */
437 err = UN_PRMT;
438 break;
439 }
440
441 return err;
442 }
443
SpePktDescAddr(const struct SpePkt * packet,char * buf,size_t bufLen)444 static int SpePktDescAddr(const struct SpePkt *packet,
445 char *buf, size_t bufLen)
446 {
447 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
448 int ns;
449 int el;
450 int idx = packet->index;
451 int ch;
452 int pat;
453 u64 payload = packet->payload;
454 int err = 0;
455 static const char *idxName[] = {"PC", "TGT", "VA", "PA", "PBT"};
456
457 switch (idx) {
458 case PERF_SPE_ADDR_PKT_HDR_INDEX_INS:
459 case PERF_SPE_ADDR_PKT_HDR_INDEX_BRANCH:
460 case PERF_SPE_ADDR_PKT_HDR_INDEX_PREV_BRANCH:
461 ns = !!PERF_SPE_ADDR_PKT_GET_NS(payload);
462 el = PERF_SPE_ADDR_PKT_GET_EL(payload);
463 payload = PERF_SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
464 SpePktOutString(&err, &buf, &bufLen,
465 "%s 0x%llx el%d ns=%d",
466 idxName[idx], payload, el, ns);
467 break;
468 case PERF_SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT:
469 SpePktOutString(&err, &buf, &bufLen,
470 "VA 0x%llx", payload);
471 break;
472 case PERF_SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS:
473 ns = !!PERF_SPE_ADDR_PKT_GET_NS(payload);
474 ch = !!PERF_SPE_ADDR_PKT_GET_CH(payload);
475 pat = PERF_SPE_ADDR_PKT_GET_PAT(payload);
476 payload = PERF_SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
477 SpePktOutString(&err, &buf, &bufLen,
478 "PA 0x%llx ns=%d ch=%d pat=%x",
479 payload, ns, ch, pat);
480 break;
481 default:
482 /* Unknown packet index */
483 err = UN_PRMT;
484 break;
485 }
486
487 return err;
488 }
489
SpePktDesCont(const struct SpePkt * packet,char * buf,size_t bufLen)490 static int SpePktDesCont(const struct SpePkt *packet,
491 char *buf, size_t bufLen)
492 {
493 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
494 u64 payload = packet->payload;
495 const char *name = SpePktName(packet->type);
496 int err = 0;
497
498 SpePktOutString(&err, &buf, &bufLen, "%s %d ", name,
499 (unsigned short)payload);
500
501 switch (packet->index) {
502 case PERF_SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT:
503 SpePktOutString(&err, &buf, &bufLen, "TOT");
504 break;
505 case PERF_SPE_CNT_PKT_HDR_INDEX_ISSUE_LAT:
506 SpePktOutString(&err, &buf, &bufLen, "ISSUE");
507 break;
508 case PERF_SPE_CNT_PKT_HDR_INDEX_TRANS_LAT:
509 SpePktOutString(&err, &buf, &bufLen, "XLAT");
510 break;
511 default:
512 break;
513 }
514
515 return err;
516 }
517
SpePktDesc(const struct SpePkt * packet,char * buf,size_t bufLen)518 int SpePktDesc(const struct SpePkt *packet, char *buf,
519 size_t bufLen)
520 {
521 CHECK_TRUE(buf == nullptr || packet == nullptr, -1, 1, "Invalid pointer!");
522 int idx = packet->index;
523 unsigned long long payload = packet->payload;
524 const char *name = SpePktName(packet->type);
525 char *bufOrig = buf;
526 size_t blen = bufLen;
527 int err = 0;
528
529 switch (packet->type) {
530 case PERF_SPE_BAD:
531 case PERF_SPE_PAD:
532 case PERF_SPE_END:
533 SpePktOutString(&err, &buf, &blen, "%s", name);
534 break;
535 case PERF_SPE_EVENTS:
536 err = SpePktDescEvent(packet, buf, bufLen);
537 break;
538 case PERF_SPE_OP_TYPE:
539 err = SpePktDescOpType(packet, buf, bufLen);
540 break;
541 case PERF_SPE_DATA_SOURCE:
542 case PERF_SPE_TIMESTAMP:
543 SpePktOutString(&err, &buf, &blen, "%s %lld", name, payload);
544 break;
545 case PERF_SPE_ADDRESS:
546 err = SpePktDescAddr(packet, buf, bufLen);
547 break;
548 case PERF_SPE_CONTEXT:
549 SpePktOutString(&err, &buf, &blen, "%s 0x%lx el%d",
550 name, (unsigned long)payload, idx + 1);
551 break;
552 case PERF_SPE_COUNTER:
553 err = SpePktDesCont(packet, buf, bufLen);
554 break;
555 default:
556 /* Unknown packet type */
557 err = UN_PRMT;
558 break;
559 }
560
561 /* If any errors are detected, the raw data is output*/
562 if (err) {
563 err = 0;
564 SpePktOutString(&err, &bufOrig, &bufLen, "%s 0x%llx (%d)",
565 name, payload, packet->index);
566 }
567
568 return err;
569 }
570
SpeCalcIp(int index,u64 payload)571 static u64 SpeCalcIp(int index, u64 payload)
572 {
573 u64 ns;
574 u64 el;
575 u64 val;
576
577 /* Instruction virtual address or Branch target address */
578 if (index == PERF_SPE_ADDR_PKT_HDR_INDEX_INS ||
579 index == PERF_SPE_ADDR_PKT_HDR_INDEX_BRANCH) {
580 ns = PERF_SPE_ADDR_PKT_GET_NS(payload);
581 el = PERF_SPE_ADDR_PKT_GET_EL(payload);
582
583 /* Clean highest byte */
584 payload = PERF_SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
585
586 /* Fill highest byte for EL1 or EL2 (VHE) mode */
587 if (ns && (el == PERF_SPE_ADDR_PKT_EL1 || el == PERF_SPE_ADDR_PKT_EL2)) {
588 payload |= 0xffULL << PERF_SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
589 }
590
591 /* Data access virtual address */
592 } else if (index == PERF_SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT) {
593 /* Clean tags */
594 payload = PERF_SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
595
596 /*
597 * Armv8 ARM (ARM DDI 0487F.c), chapter "D10.2.1 Address packet"
598 * defines the data virtual address payload format, the top byte
599 * (bits [63:56]) is assigned as top-byte tag; so we only can
600 * retrieve address value from bits [55:0].
601 *
602 * According to Documentation/arch/arm64/memory.rst, if detects the
603 * specific pattern in bits [55:52] of payload which falls in
604 * the kernel space, should fixup the top byte and this allows
605 * perf tool to parse DSO symbol for data address correctly.
606 *
607 * For this reason, if detects the bits [55:52] is 0xf, will
608 * fill 0xff into the top byte.
609 */
610 val = PERF_SPE_ADDR_PKT_ADDR_GET_BYTE_6(payload);
611 if ((val & 0xf0ULL) == 0xf0ULL) {
612 payload |= 0xffULL << PERF_SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
613 }
614
615 /* Data access physical address */
616 } else if (index == PERF_SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS) {
617 /* Clean highest byte */
618 payload = PERF_SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
619 } else {
620 static u32 seen_idx = 0;
621 if (!(seen_idx & BIT(index))) {
622 seen_idx |= BIT(index);
623 HLOGV("ignoring address packet index: 0x%x\n", index);
624 }
625 }
626
627 return payload;
628 }
629
SpeDecoderNew(struct SpeParams * params)630 struct SpeDecoder *SpeDecoderNew(struct SpeParams *params)
631 {
632 CHECK_TRUE(params == nullptr, nullptr, 1, "Invalid pointer!");
633 struct SpeDecoder *decoder;
634
635 decoder = static_cast<struct SpeDecoder*>(malloc(sizeof(struct SpeDecoder)));
636 if (!decoder) {
637 return NULL;
638 }
639
640 decoder->data = params->data;
641
642 return decoder;
643 }
644
SpeDecoderFree(struct SpeDecoder * decoder)645 void SpeDecoderFree(struct SpeDecoder *decoder)
646 {
647 CHECK_TRUE(decoder == nullptr, NO_RETVAL, 1, "Invalid pointer!");
648 free(decoder);
649 }
650
SpeGetNextPacket(struct SpeDecoder * decoder)651 static int SpeGetNextPacket(struct SpeDecoder *decoder)
652 {
653 CHECK_TRUE(decoder == nullptr, -1, 1, "Invalid pointer!");
654 int ret = 1;
655
656 do {
657 if (!decoder->len) {
658 /* Failed to read out trace data */
659 if (ret <= 0) {
660 return ret;
661 }
662 }
663
664 ret = SpeGetPacket(decoder->buf, decoder->len,
665 &decoder->packet);
666 if (ret <= 0) {
667 /* Move forward for 1 byte */
668 decoder->buf += 1;
669 decoder->len -= 1;
670 return -EBADMSG;
671 }
672
673 decoder->buf += ret;
674 decoder->len -= static_cast<size_t>(ret);
675 } while (decoder->packet.type == PERF_SPE_PAD);
676 return 1;
677 }
678
SpeReadRecord(struct SpeDecoder * decoder)679 static int SpeReadRecord(struct SpeDecoder *decoder)
680 {
681 u64 payload;
682 u64 ip;
683 CHECK_TRUE(decoder == nullptr, -1, 1, "Invalid pointer!");
684 memset_s(&decoder->record, sizeof(decoder->record), 0, sizeof(decoder->record));
685 decoder->record.context_id = (u64)-1;
686
687 while (true) {
688 int err = SpeGetNextPacket(decoder);
689 if (err <= 0) {
690 return err;
691 }
692
693 int idx = decoder->packet.index;
694 payload = decoder->packet.payload;
695
696 switch (decoder->packet.type) {
697 case PERF_SPE_TIMESTAMP:
698 decoder->record.timestamp = payload;
699 return 1;
700 case PERF_SPE_END:
701 return 1;
702 case PERF_SPE_ADDRESS:
703 ip = SpeCalcIp(idx, payload);
704 if (idx == PERF_SPE_ADDR_PKT_HDR_INDEX_INS) {
705 decoder->record.from_ip = ip;
706 } else if (idx == PERF_SPE_ADDR_PKT_HDR_INDEX_BRANCH) {
707 decoder->record.to_ip = ip;
708 } else if (idx == PERF_SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT) {
709 decoder->record.virt_addr = ip;
710 } else if (idx == PERF_SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS) {
711 decoder->record.phys_addr = ip;
712 }
713 break;
714 case PERF_SPE_COUNTER:
715 if (idx == PERF_SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT) {
716 decoder->record.latency = payload;
717 }
718 break;
719 case PERF_SPE_CONTEXT:
720 decoder->record.context_id = payload;
721 break;
722 case PERF_SPE_OP_TYPE:
723 switch (idx) {
724 case PERF_SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC:
725 decoder->record.op |= PERF_SPE_OP_LDST;
726 if (payload & PERF_SPE_OP_PKT_ST) {
727 decoder->record.op |= PERF_SPE_OP_ST;
728 } else {
729 decoder->record.op |= PERF_SPE_OP_LD;
730 }
731
732 if (PERF_SPE_OP_PKT_IS_LDST_SVE(payload)) {
733 decoder->record.op |= PERF_SPE_OP_SVE_LDST;
734 }
735 break;
736 case PERF_SPE_OP_PKT_HDR_CLASS_OTHER:
737 decoder->record.op |= PERF_SPE_OP_OTHER;
738 if (PERF_SPE_OP_PKT_IS_OTHER_SVE_OP(payload)) {
739 decoder->record.op |= PERF_SPE_OP_SVE_OTHER;
740 }
741 break;
742 case PERF_SPE_OP_PKT_HDR_CLASS_BR_ERET:
743 decoder->record.op |= PERF_SPE_OP_BRANCH_ERET;
744 break;
745 default:
746 HLOGV("Get packet error!");
747 }
748 break;
749 case PERF_SPE_EVENTS:
750 if (payload & BIT(EVENT_L1D_REFILL)) {
751 decoder->record.type |= PERF_SPE_L1D_MISS;
752 }
753
754 if (payload & BIT(EVENT_L1D_ACCESS)) {
755 decoder->record.type |= PERF_SPE_L1D_ACCESS;
756 }
757
758 if (payload & BIT(EVENT_TLB_WALK)) {
759 decoder->record.type |= PERF_SPE_TLB_MISS;
760 }
761
762 if (payload & BIT(EVENT_TLB_ACCESS)) {
763 decoder->record.type |= PERF_SPE_TLB_ACCESS;
764 }
765
766 if (payload & BIT(EVENT_LLC_MISS)) {
767 decoder->record.type |= PERF_SPE_LLC_MISS;
768 }
769
770 if (payload & BIT(EVENT_LLC_ACCESS)) {
771 decoder->record.type |= PERF_SPE_LLC_ACCESS;
772 }
773
774 if (payload & BIT(EVENT_REMOTE_ACCESS)) {
775 decoder->record.type |= PERF_SPE_REMOTE_ACCESS;
776 }
777
778 if (payload & BIT(EVENT_MISPRED)) {
779 decoder->record.type |= PERF_SPE_BRANCH_MISS;
780 }
781
782 if (payload & BIT(EVENT_PARTIAL_PREDICATE)) {
783 decoder->record.type |= PERF_SPE_SVE_PARTIAL_PRED;
784 }
785
786 if (payload & BIT(EVENT_EMPTY_PREDICATE)) {
787 decoder->record.type |= PERF_SPE_SVE_EMPTY_PRED;
788 }
789 break;
790 case PERF_SPE_DATA_SOURCE:
791 decoder->record.source = payload;
792 break;
793 case PERF_SPE_BAD:
794 break;
795 case PERF_SPE_PAD:
796 break;
797 default:
798 printf("Get packet error!\n");
799 return -1;
800 }
801 }
802 return 0;
803 }
804
SpeDecode(struct SpeDecoder * decoder)805 int SpeDecode(struct SpeDecoder *decoder)
806 {
807 CHECK_TRUE(decoder == nullptr, -1, 1, "Invalid pointer!");
808 return SpeReadRecord(decoder);
809 }
810
SpeDecoderDataNew(const unsigned char * speBuf,size_t speLen)811 struct SpeDecoder *SpeDecoderDataNew(const unsigned char *speBuf, size_t speLen)
812 {
813 CHECK_TRUE(speBuf == nullptr, nullptr, 1, "Invalid pointer!");
814 struct SpeDecoder *decoder;
815
816 decoder = reinterpret_cast<SpeDecoder *>(malloc(sizeof(struct SpeDecoder)));
817 if (!decoder) {
818 return NULL;
819 }
820 memset_s(decoder, sizeof(struct SpeDecoder), 0, sizeof(struct SpeDecoder));
821
822 decoder->buf = speBuf;
823 decoder->len = speLen;
824
825 return decoder;
826 }
827
SpeDumpRawData(unsigned char * buf,size_t len,int indent,FILE * outputDump)828 void SpeDumpRawData(unsigned char *buf, size_t len, int indent, FILE *outputDump)
829 {
830 CHECK_TRUE(buf == nullptr, NO_RETVAL, 1, "Invalid pointer!");
831 if (outputDump != nullptr) {
832 g_outputDump = outputDump;
833 }
834 struct SpePkt packet;
835 size_t pos = 0;
836 int pktLen;
837 int i;
838 char desc[PERF_SPE_PKT_DESC_MAX];
839
840 PRINT_INDENT(indent, ". ... ARM SPE data: size %#zx bytes\n", len);
841 while (len) {
842 int ret = SpeGetPacket(buf, len, &packet);
843 if (ret > 0) {
844 pktLen = ret;
845 } else {
846 pktLen = 1;
847 }
848 PRINT_INDENT(indent, ".");
849 PRINT_INDENT(indent, " %08zx: ", pos);
850 for (i = 0; i < pktLen; i++) {
851 PRINT_INDENT(indent, " %02x", buf[i]);
852 }
853 for (; i < 16; i++) { // 16 : space
854 PRINT_INDENT(indent, " ");
855 }
856 if (ret > 0) {
857 ret = SpePktDesc(&packet, desc,
858 PERF_SPE_PKT_DESC_MAX);
859 if (!ret) {
860 PRINT_INDENT(indent, " %s\n", desc);
861 }
862 } else {
863 PRINT_INDENT(indent, " Bad packet!\n");
864 }
865 pos += static_cast<size_t>(pktLen);
866 buf += pktLen;
867 if (len >= static_cast<size_t>(pktLen)) {
868 len -= static_cast<size_t>(pktLen);
869 } else {
870 break;
871 }
872 }
873 }
874
875 std::map<u32, std::map<u64, ReportItemAuxRawData>> AuxRawDataMap_;
876 std::map<u32, u64> typeCount;
877
878 const std::vector<u32> DEFAULT_SPE_EVENT_TYPE = {
879 PERF_SPE_L1D_ACCESS,
880 PERF_SPE_L1D_MISS,
881 PERF_SPE_LLC_ACCESS,
882 PERF_SPE_LLC_MISS,
883 PERF_SPE_TLB_ACCESS,
884 PERF_SPE_TLB_MISS,
885 PERF_SPE_BRANCH_MISS,
886 PERF_SPE_REMOTE_ACCESS,
887 PERF_SPE_SVE_PARTIAL_PRED,
888 PERF_SPE_SVE_EMPTY_PRED,
889 };
890
891 constexpr const int SPE_PERCENTAGE_COMM_LEN = 40;
892 constexpr const int SPE_PERCENTAGE_PC_LEN = 18;
893 constexpr const int SPE_PERCENTAGE_DSO_LEN = 50;
894 constexpr const int SPE_PERCENTAGE_FUNC_LEN = 60;
895 constexpr const int SPE_PERCENTAGE_OFFSET_LEN = 20;
896
AddReportItems(const std::vector<ReportItemAuxRawData> & auxRawData)897 void AddReportItems(const std::vector<ReportItemAuxRawData>& auxRawData)
898 {
899 for (const auto& data : auxRawData) {
900 for (auto type : DEFAULT_SPE_EVENT_TYPE) {
901 if (data.type & type) {
902 if (typeCount.count(type) == 0) {
903 typeCount[type] = 1;
904 } else {
905 typeCount[type]++;
906 }
907 std::map<u64, ReportItemAuxRawData>& map = AuxRawDataMap_[type];
908
909 auto data1 = map.find(data.pc);
910 if (data1 == map.end()) {
911 HLOGV("add %llx", data.pc);
912 map[data.pc] = {type, 0.0f, 1, data.comm, data.pc, data.SharedObject, data.Symbol, data.offset};
913 } else {
914 HLOGV("add pc: %llx", data.pc);
915 data1->second.count++;
916 HLOGV("add pc: %llx count: %llu", data.pc, data1->second.count);
917 }
918 }
919 }
920 }
921 }
922
UpdateHeating()923 void UpdateHeating()
924 {
925 for (auto it = AuxRawDataMap_.begin(); it != AuxRawDataMap_.end(); it++) {
926 u64 cc = typeCount[it->first];
927 for (auto& it2 : it->second) {
928 float heating = (float)it2.second.count / cc * FULL_PERCENTAGE;
929 HLOGV("heating %llu/%llu %f", it2.second.count, cc, heating);
930 it2.second.heating = heating;
931 }
932 }
933 }
934
GetSpeEventNameByType(uint32_t type,std::string & eventName)935 void GetSpeEventNameByType(uint32_t type, std::string& eventName)
936 {
937 switch (type) {
938 case PERF_SPE_L1D_ACCESS:
939 eventName = "l1d-access";
940 break;
941 case PERF_SPE_L1D_MISS:
942 eventName = "l1d-miss";
943 break;
944 case PERF_SPE_LLC_ACCESS:
945 eventName = "llc-access";
946 break;
947 case PERF_SPE_LLC_MISS:
948 eventName = "llc-miss";
949 break;
950 case PERF_SPE_TLB_ACCESS:
951 eventName = "tlb-access";
952 break;
953 case PERF_SPE_TLB_MISS:
954 eventName = "tlb-miss";
955 break;
956 case PERF_SPE_BRANCH_MISS:
957 eventName = "branch-miss";
958 break;
959 case PERF_SPE_REMOTE_ACCESS:
960 eventName = "remote-access";
961 break;
962 case PERF_SPE_SVE_PARTIAL_PRED:
963 eventName = "paritial_read";
964 break;
965 case PERF_SPE_SVE_EMPTY_PRED:
966 eventName = "empty_read";
967 break;
968 default:
969 eventName = "unknow";
970 return;
971 }
972 }
973
DumpSpeReportHead(int indent,uint32_t type,uint64_t count)974 void DumpSpeReportHead(int indent, uint32_t type, uint64_t count)
975 {
976 std::string eventName = "";
977 GetSpeEventNameByType(type, eventName);
978 PRINT_INDENT(indent, "\nEvent :%s\n", eventName.c_str());
979 PRINT_INDENT(indent, "Samples Count: %" PRIu64 "\n", count);
980
981 // head print
982 const std::string head = "Heating";
983 PRINT_INDENT(indent, "%-*s ", FULL_PERCENTAGE_LEN, head.c_str());
984 const std::string eventCount = " count";
985 PRINT_INDENT(indent, "%-*s ", FULL_PERCENTAGE_LEN, eventCount.c_str());
986 const std::string comm = " comm";
987 PRINT_INDENT(indent, "%-*s ", SPE_PERCENTAGE_COMM_LEN, comm.c_str());
988 const std::string pc = " PC";
989 PRINT_INDENT(indent, "%-*s ", SPE_PERCENTAGE_PC_LEN, pc.c_str());
990 const std::string dso = " dso";
991 PRINT_INDENT(indent, "%-*s ", SPE_PERCENTAGE_DSO_LEN, dso.c_str());
992 const std::string func = " func";
993 PRINT_INDENT(indent, "%-*s", SPE_PERCENTAGE_FUNC_LEN, func.c_str());
994 const std::string offset = " offset";
995 PRINT_INDENT(indent, "%-*s\n", SPE_PERCENTAGE_OFFSET_LEN, offset.c_str());
996 return;
997 }
998
DumpSpeReportData(int indent,FILE * outputDump)999 void DumpSpeReportData(int indent, FILE *outputDump)
1000 {
1001 if (outputDump != nullptr) {
1002 g_outputDump = outputDump;
1003 }
1004 if (AuxRawDataMap_.empty()) {
1005 return;
1006 }
1007 PRINT_INDENT(indent, "\n ==== Spe Report Data ====\n");
1008 for (auto it = AuxRawDataMap_.begin(); it != AuxRawDataMap_.end(); it++) {
1009 u64 count = typeCount[it->first];
1010 DumpSpeReportHead(indent, it->first, count);
1011 for (auto& it2 : it->second) {
1012 PRINT_INDENT(indent + 1, "%*.2f%% ", FULL_PERCENTAGE_LEN, it2.second.heating);
1013 PRINT_INDENT(indent + 1, "%-*llu ", FULL_PERCENTAGE_LEN, it2.second.count);
1014 PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_COMM_LEN, it2.second.comm.c_str());
1015 PRINT_INDENT(indent + 1, "0x%-*llx ", SPE_PERCENTAGE_PC_LEN, it2.second.pc);
1016 PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_DSO_LEN, it2.second.SharedObject.c_str());
1017 PRINT_INDENT(indent + 1, "%-*s", SPE_PERCENTAGE_FUNC_LEN, it2.second.Symbol.c_str());
1018 PRINT_INDENT(indent + 1, "0x%llx\n", it2.second.offset);
1019 }
1020 }
1021 }
1022 } // namespace HiPerf
1023 } // namespace Developtools
1024 } // namespace OHOS
1025