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 29namespace OHOS { 30namespace Developtools { 31namespace HiPerf { 32constexpr const int UN_PRMT = -1; 33 34const 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 52static unsigned int SpePayloadLen(unsigned char hdr) 53{ 54 return 1U << PERF_SPE_HDR_GET_BYTES_5_4(hdr); 55} 56 57static 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 78static 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 85static 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 98static 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 105static 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 113static 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 122static 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 130static 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 139static 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 148static 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 162static 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 176static 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 235int 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 251static 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 294static 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 348static 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 444static 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 490static 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 518int 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 571static 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 630struct 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 645void SpeDecoderFree(struct SpeDecoder *decoder) 646{ 647 CHECK_TRUE(decoder == nullptr, NO_RETVAL, 1, "Invalid pointer!"); 648 free(decoder); 649} 650 651static 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 679static 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 805int SpeDecode(struct SpeDecoder *decoder) 806{ 807 CHECK_TRUE(decoder == nullptr, -1, 1, "Invalid pointer!"); 808 return SpeReadRecord(decoder); 809} 810 811struct 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 828bool SpeDumpRawData(unsigned char *buf, size_t len, int indent, FILE *outputDump) 829{ 830 CHECK_TRUE(buf == nullptr, false, 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 return true; 874} 875 876std::map<u32, std::map<u64, ReportItemAuxRawData>> AuxRawDataMap_; 877std::map<u32, u64> typeCount; 878 879const std::vector<u32> DEFAULT_SPE_EVENT_TYPE = { 880 PERF_SPE_L1D_ACCESS, 881 PERF_SPE_L1D_MISS, 882 PERF_SPE_LLC_ACCESS, 883 PERF_SPE_LLC_MISS, 884 PERF_SPE_TLB_ACCESS, 885 PERF_SPE_TLB_MISS, 886 PERF_SPE_BRANCH_MISS, 887 PERF_SPE_REMOTE_ACCESS, 888 PERF_SPE_SVE_PARTIAL_PRED, 889 PERF_SPE_SVE_EMPTY_PRED, 890}; 891 892constexpr const int SPE_PERCENTAGE_COMM_LEN = 40; 893constexpr const int SPE_PERCENTAGE_PC_LEN = 18; 894constexpr const int SPE_PERCENTAGE_DSO_LEN = 50; 895constexpr const int SPE_PERCENTAGE_FUNC_LEN = 60; 896constexpr const int SPE_PERCENTAGE_OFFSET_LEN = 20; 897 898void AddReportItems(const std::vector<ReportItemAuxRawData>& auxRawData) 899{ 900 for (const auto& data : auxRawData) { 901 for (auto type : DEFAULT_SPE_EVENT_TYPE) { 902 if (data.type & type) { 903 if (typeCount.count(type) == 0) { 904 typeCount[type] = 1; 905 } else { 906 typeCount[type]++; 907 } 908 std::map<u64, ReportItemAuxRawData>& map = AuxRawDataMap_[type]; 909 910 auto data1 = map.find(data.pc); 911 if (data1 == map.end()) { 912 HLOGV("add %llx", data.pc); 913 map[data.pc] = {type, 0.0f, 1, data.comm, data.pc, data.SharedObject, data.Symbol, data.offset}; 914 } else { 915 HLOGV("add pc: %llx", data.pc); 916 data1->second.count++; 917 HLOGV("add pc: %llx count: %llu", data.pc, data1->second.count); 918 } 919 } 920 } 921 } 922} 923 924void UpdateHeating() 925{ 926 for (auto it = AuxRawDataMap_.begin(); it != AuxRawDataMap_.end(); it++) { 927 u64 cc = typeCount[it->first]; 928 for (auto& it2 : it->second) { 929 float heating = (float)it2.second.count / cc * FULL_PERCENTAGE; 930 HLOGV("heating %llu/%llu %f", it2.second.count, cc, heating); 931 it2.second.heating = heating; 932 } 933 } 934} 935 936void GetSpeEventNameByType(uint32_t type, std::string& eventName) 937{ 938 switch (type) { 939 case PERF_SPE_L1D_ACCESS: 940 eventName = "l1d-access"; 941 break; 942 case PERF_SPE_L1D_MISS: 943 eventName = "l1d-miss"; 944 break; 945 case PERF_SPE_LLC_ACCESS: 946 eventName = "llc-access"; 947 break; 948 case PERF_SPE_LLC_MISS: 949 eventName = "llc-miss"; 950 break; 951 case PERF_SPE_TLB_ACCESS: 952 eventName = "tlb-access"; 953 break; 954 case PERF_SPE_TLB_MISS: 955 eventName = "tlb-miss"; 956 break; 957 case PERF_SPE_BRANCH_MISS: 958 eventName = "branch-miss"; 959 break; 960 case PERF_SPE_REMOTE_ACCESS: 961 eventName = "remote-access"; 962 break; 963 case PERF_SPE_SVE_PARTIAL_PRED: 964 eventName = "paritial_read"; 965 break; 966 case PERF_SPE_SVE_EMPTY_PRED: 967 eventName = "empty_read"; 968 break; 969 default: 970 eventName = "unknow"; 971 return; 972 } 973} 974 975void DumpSpeReportHead(int indent, uint32_t type, uint64_t count) 976{ 977 std::string eventName = ""; 978 GetSpeEventNameByType(type, eventName); 979 PRINT_INDENT(indent, "\nEvent :%s\n", eventName.c_str()); 980 PRINT_INDENT(indent, "Samples Count: %" PRIu64 "\n", count); 981 982 // head print 983 const std::string head = "Heating"; 984 PRINT_INDENT(indent, "%-*s ", FULL_PERCENTAGE_LEN, head.c_str()); 985 const std::string eventCount = " count"; 986 PRINT_INDENT(indent, "%-*s ", FULL_PERCENTAGE_LEN, eventCount.c_str()); 987 const std::string comm = " comm"; 988 PRINT_INDENT(indent, "%-*s ", SPE_PERCENTAGE_COMM_LEN, comm.c_str()); 989 const std::string pc = " PC"; 990 PRINT_INDENT(indent, "%-*s ", SPE_PERCENTAGE_PC_LEN, pc.c_str()); 991 const std::string dso = " dso"; 992 PRINT_INDENT(indent, "%-*s ", SPE_PERCENTAGE_DSO_LEN, dso.c_str()); 993 const std::string func = " func"; 994 PRINT_INDENT(indent, "%-*s", SPE_PERCENTAGE_FUNC_LEN, func.c_str()); 995 const std::string offset = " offset"; 996 PRINT_INDENT(indent, "%-*s\n", SPE_PERCENTAGE_OFFSET_LEN, offset.c_str()); 997 return; 998} 999 1000void DumpSpeReportData(int indent, FILE *outputDump) 1001{ 1002 if (outputDump != nullptr) { 1003 g_outputDump = outputDump; 1004 } 1005 if (AuxRawDataMap_.empty()) { 1006 return; 1007 } 1008 PRINT_INDENT(indent, "\n ==== Spe Report Data ====\n"); 1009 for (auto it = AuxRawDataMap_.begin(); it != AuxRawDataMap_.end(); it++) { 1010 u64 count = typeCount[it->first]; 1011 DumpSpeReportHead(indent, it->first, count); 1012 for (auto& it2 : it->second) { 1013 PRINT_INDENT(indent + 1, "%*.2f%% ", FULL_PERCENTAGE_LEN, it2.second.heating); 1014 PRINT_INDENT(indent + 1, "%-*llu ", FULL_PERCENTAGE_LEN, it2.second.count); 1015 PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_COMM_LEN, it2.second.comm.c_str()); 1016 PRINT_INDENT(indent + 1, "0x%-*llx ", SPE_PERCENTAGE_PC_LEN, it2.second.pc); 1017 PRINT_INDENT(indent + 1, "%-*s ", SPE_PERCENTAGE_DSO_LEN, it2.second.SharedObject.c_str()); 1018 PRINT_INDENT(indent + 1, "%-*s", SPE_PERCENTAGE_FUNC_LEN, it2.second.Symbol.c_str()); 1019 PRINT_INDENT(indent + 1, "0x%llx\n", it2.second.offset); 1020 } 1021 } 1022} 1023} // namespace HiPerf 1024} // namespace Developtools 1025} // namespace OHOS 1026