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