• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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