xref: /developtools/hiperf/src/spe_decoder.cpp (revision 48f512ce)
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