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