• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #ifndef ECMASCRIPT_PGO_PROFILER_INFO_H
17 #define ECMASCRIPT_PGO_PROFILER_INFO_H
18 
19 #include <cstdint>
20 #include <memory>
21 #include <sstream>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <string.h>
25 
26 #include "ecmascript/base/file_header.h"
27 #include "ecmascript/jspandafile/method_literal.h"
28 #include "ecmascript/log_wrapper.h"
29 #include "ecmascript/mem/c_containers.h"
30 #include "ecmascript/mem/c_string.h"
31 #include "ecmascript/mem/chunk_containers.h"
32 #include "ecmascript/mem/native_area_allocator.h"
33 #include "ecmascript/mem/slots.h"
34 #include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
35 #include "ecmascript/property_attributes.h"
36 
37 
38 namespace panda::ecmascript {
39 class SaveTask;
40 
41 enum class SampleMode : uint8_t {
42     HOTNESS_MODE,
43     CALL_MODE,
44 };
45 
46 struct SectionInfo {
47     uint32_t offset_ {0};
48     // reserve
49     uint32_t size_ {0};
50     uint32_t number_ {0};
51 };
52 static constexpr size_t ALIGN_SIZE = 4;
53 using PGOMethodId = EntityId;
54 
55 /**
56   |----PGOProfilerHeader
57   |--------MAGIC(8)
58   |------------{ 'P', 'A', 'N', 'D', 'A', '\0', '\0', '\0' }
59   |--------VERSION(4)
60   |------------{ '0', '0', '0', '0' }
61   |--------CHECKSUM(4)
62   |------------{ checksum }
63   |--------FILE_SIZE(4)
64   |------------{ fileSize }
65   |--------HEADER_SIZE(4)
66   |------------{ headerSize, from MAGIC to SECTION_NUMBER }
67   |--------ENDIAN_TAG(4)
68   |------------{ ENDIAN_TAG }
69   |--------SECTION_NUMBER(4)
70   |------------{ 3 }
71   |--------PANDA_FILE_INFO_SECTION_INFO(12)
72   |------------{ offset, size (reserve), number1 }
73   |--------RECORD_INFO_SECTION_INFO(12)
74   |------------{ offset, size (reserve), number2 }
75   |--------LAYOUT_DESC_SECTION_INFO(12)
76   |------------{ offset, size (reserve), number3 }
77   |
78   |----Section1: PGOPandaFileInfos(number1)
79   |--------[{ size, CHECK_SUM }, { size, CHECK_SUM }, ...]
80   |
81   |----Section2: PGORecordDetailInfos(number2)
82   |--------[ PGOMethodInfoMap(number4)
83   |------------{ offset, size, number4 }
84   |------------[ PGOMethodInfo(size1)
85   |----------------{ size1, entityId, count, mode, methodName, [{ size, offset, type }, { size, offset, type }, ...]},
86   |------------  PGOMethodInfo(size1)
87   |----------------{ size1, entityId, count, mode, methodName, [{ size, offset, type }, { size, offset, type }, ...]},
88   |--------------... ]
89   |--------  PGOMethodInfoMap()
90   |--------... ]
91   |
92   |----Section3: PGHClassLayoutDescs(number3)
93   |--------{ offset, size, number5 }
94   |--------[ PGOHClassLayoutDescInner(size)
95   |------------{ size, type, superType, count, ptCount, ctorCount, [{ size, handle, key }, { size, heandle, key }, ...]}
96   |--------  PGOHClassLayoutDescInner(size)
97   |------------{ size, type, superType, count, ptCount, ctorCount, [{ size, handle, key }, { size, heandle, key }, ...]}
98  */
99 class PGOProfilerHeader : public base::FileHeaderElastic {
100 public:
101     static constexpr VersionType TYPE_MINI_VERSION = {0, 0, 0, 2};
102     static constexpr VersionType METHOD_CHECKSUM_MINI_VERSION = {0, 0, 0, 4};
103     static constexpr VersionType USE_HCLASS_TYPE_MINI_VERSION = {0, 0, 0, 5};
104     static constexpr VersionType FILE_CONSISTENCY_MINI_VERSION = {0, 0, 0, 6};
105     static constexpr VersionType TRACK_FIELD_MINI_VERSION = {0, 0, 0, 7};
106     static constexpr VersionType ELEMENTS_KIND_MINI_VERSION = {0, 0, 0, 8};
107     static constexpr VersionType FILE_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
108     static constexpr VersionType HEADER_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
109     static constexpr VersionType ELASTIC_HEADER_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
110     static constexpr VersionType LAST_VERSION = {0, 0, 0, 8};
111     static constexpr size_t SECTION_SIZE = 3;
112     static constexpr size_t PANDA_FILE_SECTION_INDEX = 0;
113     static constexpr size_t RECORD_INFO_SECTION_INDEX = 1;
114     static constexpr size_t LAYOUT_DESC_SECTION_INDEX = 2;
115 
PGOProfilerHeader()116     PGOProfilerHeader() : base::FileHeaderElastic(LAST_VERSION), sectionNumber_(SECTION_SIZE)
117     {
118         GetPandaInfoSection()->offset_ = Size();
119         SetHeaderSize(Size());
120     }
121 
LastSize()122     static size_t LastSize()
123     {
124         return sizeof(PGOProfilerHeader) + (SECTION_SIZE - 1) * sizeof(SectionInfo);
125     }
126 
Size(uint32_t sectionNumber)127     static size_t Size(uint32_t sectionNumber)
128     {
129         return sizeof(PGOProfilerHeader) + (sectionNumber - 1) * sizeof(SectionInfo);
130     }
131 
Size()132     size_t Size() const
133     {
134         return Size(sectionNumber_);
135     }
136 
Verify()137     bool Verify() const
138     {
139         return VerifyVersion("apPath file", LAST_VERSION, false);
140     }
141 
Verify(void * buffer,size_t bufferSize)142     bool Verify(void *buffer, size_t bufferSize) const
143     {
144         if (!Verify()) {
145             return false;
146         }
147         if (!VerifyConsistency(buffer, bufferSize)) {
148             return false;
149         }
150         if (!VerifyFileSize(bufferSize)) {
151             return false;
152         }
153         return true;
154     }
155 
156     bool VerifyFileSize(size_t bufferSize) const;
157 
158     bool VerifyConsistency(void *buffer, size_t bufferSize) const;
159 
Build(PGOProfilerHeader ** header,size_t size)160     static void Build(PGOProfilerHeader **header, size_t size)
161     {
162         *header = reinterpret_cast<PGOProfilerHeader *>(malloc(size));
163         new (*header) PGOProfilerHeader();
164     }
165 
Destroy(PGOProfilerHeader ** header)166     static void Destroy(PGOProfilerHeader **header)
167     {
168         if (*header != nullptr) {
169             free(*header);
170             *header = nullptr;
171         }
172     }
173 
174     // Copy Header.
175     static bool ParseFromBinary(void *buffer, size_t bufferSize, PGOProfilerHeader **header);
176     void ProcessToBinary(std::fstream &fileStream) const;
177 
178     bool ParseFromText(std::ifstream &stream);
179     bool ProcessToText(std::ofstream &stream) const;
180 
GetPandaInfoSection()181     SectionInfo *GetPandaInfoSection() const
182     {
183         return GetSectionInfo(PANDA_FILE_SECTION_INDEX);
184     }
185 
GetRecordInfoSection()186     SectionInfo *GetRecordInfoSection() const
187     {
188         return GetSectionInfo(RECORD_INFO_SECTION_INDEX);
189     }
190 
GetLayoutDescSection()191     SectionInfo *GetLayoutDescSection() const
192     {
193         return GetSectionInfo(LAYOUT_DESC_SECTION_INDEX);
194     }
195 
SupportType()196     bool SupportType() const
197     {
198         return CompatibleVerify(TYPE_MINI_VERSION);
199     }
200 
SupportMethodChecksum()201     bool SupportMethodChecksum() const
202     {
203         return CompatibleVerify(METHOD_CHECKSUM_MINI_VERSION);
204     }
205 
SupportUseHClassType()206     bool SupportUseHClassType() const
207     {
208         return CompatibleVerify(USE_HCLASS_TYPE_MINI_VERSION);
209     }
210 
SupportFileConsistency()211     bool SupportFileConsistency() const
212     {
213         return CompatibleVerify(FILE_CONSISTENCY_MINI_VERSION);
214     }
215 
SupportFileSize()216     bool SupportFileSize() const
217     {
218         return CompatibleVerify(FILE_SIZE_MINI_VERSION);
219     }
220 
SupportHeaderSize()221     bool SupportHeaderSize() const
222     {
223         return CompatibleVerify(HEADER_SIZE_MINI_VERSION);
224     }
225 
SupportTrackField()226     bool SupportTrackField() const
227     {
228         return CompatibleVerify(TRACK_FIELD_MINI_VERSION);
229     }
230 
SupportElementsKind()231     bool SupportElementsKind() const
232     {
233         return CompatibleVerify(ELEMENTS_KIND_MINI_VERSION);
234     }
235 
236     NO_COPY_SEMANTIC(PGOProfilerHeader);
237     NO_MOVE_SEMANTIC(PGOProfilerHeader);
238 
239 private:
240     static bool BuildFromLegacy(void *buffer, PGOProfilerHeader **header);
241     static bool BuildFromElastic(void *buffer, size_t bufferSize, PGOProfilerHeader **header);
242 
GetSectionInfo(size_t index)243     SectionInfo *GetSectionInfo(size_t index) const
244     {
245         if (index >= sectionNumber_) {
246             return nullptr;
247         }
248         return const_cast<SectionInfo *>(&sectionInfos_) + index;
249     }
250 
251     uint32_t sectionNumber_ {SECTION_SIZE};
252     SectionInfo sectionInfos_;
253 };
254 
255 class PGOProfilerHeaderLegacy : public base::FileHeaderBase {
256 public:
257     static constexpr size_t SECTION_SIZE = 3;
258     static constexpr VersionType LAST_VERSION = {0, 0, 0, 5};
PGOProfilerHeaderLegacy()259     PGOProfilerHeaderLegacy() : base::FileHeaderBase(LAST_VERSION), sectionNumber_(SECTION_SIZE) {};
260 
GetSectionNumber()261     const uint32_t& GetSectionNumber () const
262     {
263         return sectionNumber_;
264     }
265 
266 private:
267     uint32_t sectionNumber_ {SECTION_SIZE};
268     SectionInfo sectionInfos_;
269 };
270 
271 class PGOPandaFileInfos {
272 public:
Sample(uint32_t checksum)273     void Sample(uint32_t checksum)
274     {
275         fileInfos_.emplace(checksum);
276     }
277 
Clear()278     void Clear()
279     {
280         fileInfos_.clear();
281     }
282 
283     void ParseFromBinary(void *buffer, SectionInfo *const info);
284     void ProcessToBinary(std::fstream &fileStream, SectionInfo *info) const;
285     void Merge(const PGOPandaFileInfos &pandaFileInfos);
286     bool VerifyChecksum(const PGOPandaFileInfos &pandaFileInfos, const std::string &base,
287                         const std::string &incoming) const;
288 
289     void ProcessToText(std::ofstream &stream) const;
290     bool ParseFromText(std::ifstream &stream);
291 
292     bool Checksum(uint32_t checksum) const;
293 
294 private:
295     class FileInfo {
296     public:
297         FileInfo() = default;
FileInfo(uint32_t checksum)298         FileInfo(uint32_t checksum) : size_(LastSize()), checksum_(checksum) {}
299 
LastSize()300         static size_t LastSize()
301         {
302             return sizeof(FileInfo);
303         }
304 
Size()305         size_t Size() const
306         {
307             return static_cast<size_t>(size_);
308         }
309 
310         bool operator<(const FileInfo &right) const
311         {
312             return checksum_ < right.checksum_;
313         }
314 
GetChecksum()315         uint32_t GetChecksum() const
316         {
317             return checksum_;
318         }
319 
320     private:
321         // Support extended fields
322         uint32_t size_;
323         uint32_t checksum_;
324     };
325 
326     std::set<FileInfo> fileInfos_;
327 };
328 
329 class PGOMethodInfo {
330 public:
331     static constexpr int METHOD_INFO_COUNT = 4;
332     static constexpr int METHOD_ID_INDEX = 0;
333     static constexpr int METHOD_COUNT_INDEX = 1;
334     static constexpr int METHOD_MODE_INDEX = 2;
335     static constexpr int METHOD_NAME_INDEX = 3;
336     static constexpr uint32_t METHOD_MAX_HIT_COUNT = 10000U;
337 
PGOMethodInfo(PGOMethodId id)338     explicit PGOMethodInfo(PGOMethodId id) : id_(id) {}
339 
PGOMethodInfo(PGOMethodId id,uint32_t count,SampleMode mode,const char * methodName)340     PGOMethodInfo(PGOMethodId id, uint32_t count, SampleMode mode, const char *methodName)
341         : id_(id), count_(count), mode_(mode)
342     {
343         size_t len = strlen(methodName);
344         size_ = static_cast<uint32_t>(Size(len));
345         if (len > 0 && memcpy_s(&methodName_, len, methodName, len) != EOK) {
346             LOG_ECMA(ERROR) << "SetMethodName memcpy_s failed" << methodName << ", len = " << len;
347             UNREACHABLE();
348         }
349         *(&methodName_ + len) = '\0';
350     }
351 
352     static uint32_t CalcChecksum(const char *name, const uint8_t *byteCodeArray, uint32_t byteCodeLength);
353 
354     static uint32_t CalcOpCodeChecksum(const uint8_t *byteCodeArray, uint32_t byteCodeLength);
355 
Size(uint32_t length)356     static int32_t Size(uint32_t length)
357     {
358         return sizeof(PGOMethodInfo) + AlignUp(length, ALIGN_SIZE);
359     }
360 
Size()361     int32_t Size() const
362     {
363         return size_;
364     }
365 
GetSampleMode(std::string content,SampleMode & mode)366     static bool GetSampleMode(std::string content, SampleMode &mode)
367     {
368         if (content == "HOTNESS_MODE") {
369             mode = SampleMode::HOTNESS_MODE;
370         } else if (content == "CALL_MODE") {
371             mode = SampleMode::CALL_MODE;
372         } else {
373             return false;
374         }
375         return true;
376     }
377 
IncreaseCount(int32_t inc)378     void IncreaseCount(int32_t inc)
379     {
380         count_ += static_cast<uint32_t>(inc);
381     }
382 
ClearCount()383     void ClearCount()
384     {
385         count_ = 0;
386     }
387 
Merge(const PGOMethodInfo * info)388     void Merge(const PGOMethodInfo *info)
389     {
390         if (!(id_ == info->GetMethodId())) {
391             LOG_ECMA(ERROR) << "The method id must same for merging";
392             return;
393         }
394         count_ = std::min(count_ + info->GetCount(), METHOD_MAX_HIT_COUNT);
395         SetSampleMode(info->GetSampleMode());
396     }
397 
GetMethodId()398     PGOMethodId GetMethodId() const
399     {
400         return id_;
401     }
402 
GetCount()403     uint32_t GetCount() const
404     {
405         return count_;
406     }
407 
GetMethodName()408     const char *GetMethodName() const
409     {
410         return &methodName_;
411     }
412 
SetSampleMode(SampleMode mode)413     void SetSampleMode(SampleMode mode)
414     {
415         if (mode_ == SampleMode::HOTNESS_MODE) {
416             return;
417         }
418         mode_ = mode;
419     }
420 
GetSampleMode()421     SampleMode GetSampleMode() const
422     {
423         return mode_;
424     }
425 
GetSampleModeToString()426     std::string GetSampleModeToString() const
427     {
428         std::string result;
429         switch (mode_) {
430             case SampleMode::HOTNESS_MODE:
431                 result = "HOTNESS_MODE";
432                 break;
433             case SampleMode::CALL_MODE:
434                 result = "CALL_MODE";
435                 break;
436             default:
437                 LOG_ECMA(ERROR) << "mode error";
438         }
439         return result;
440     }
441 
IsFilter(uint32_t threshold)442     bool IsFilter(uint32_t threshold) const
443     {
444         if (count_ < threshold && mode_ == SampleMode::CALL_MODE) {
445             return true;
446         }
447         return false;
448     }
449 
450     void ParseFromBinary(void **buffer);
451     void ProcessToBinary(std::ofstream &fileStream) const;
452 
453     static std::vector<std::string> ParseFromText(const std::string &infoString);
454     void ProcessToText(std::string &text) const;
455 
456     NO_COPY_SEMANTIC(PGOMethodInfo);
457     NO_MOVE_SEMANTIC(PGOMethodInfo);
458 
459 private:
460     uint32_t size_ {0};
461     PGOMethodId id_;
462     uint32_t count_ {0};
463     SampleMode mode_ {SampleMode::CALL_MODE};
464     char methodName_ {0};
465 };
466 
467 class PGOMethodTypeSet {
468 public:
469     static constexpr int METHOD_TYPE_INFO_INDEX = 4;
470     static constexpr int METHOD_TYPE_INFO_COUNT = 2;
471     static constexpr int METHOD_OFFSET_INDEX = 0;
472     static constexpr int METHOD_TYPE_INDEX = 1;
473 
474     PGOMethodTypeSet() = default;
475 
AddType(uint32_t offset,PGOSampleType type)476     void AddType(uint32_t offset, PGOSampleType type)
477     {
478         auto result = scalarOpTypeInfos_.find(ScalarOpTypeInfo(offset, type));
479         if (result != scalarOpTypeInfos_.end()) {
480             auto combineType = result->GetType().CombineType(type);
481             const_cast<ScalarOpTypeInfo &>(*result).SetType(combineType);
482         } else {
483             scalarOpTypeInfos_.emplace(offset, type);
484         }
485     }
486 
AddCallTargetType(uint32_t offset,PGOSampleType type)487     void AddCallTargetType(uint32_t offset, PGOSampleType type)
488     {
489         auto result = scalarOpTypeInfos_.find(ScalarOpTypeInfo(offset, type));
490         if (result != scalarOpTypeInfos_.end()) {
491             auto combineType = result->GetType().CombineCallTargetType(type);
492             const_cast<ScalarOpTypeInfo &>(*result).SetType(combineType);
493         } else {
494             scalarOpTypeInfos_.emplace(offset, type);
495         }
496     }
497 
AddObjectInfo(uint32_t offset,const PGOObjectInfo & info)498     void AddObjectInfo(uint32_t offset, const PGOObjectInfo &info)
499     {
500         auto result = rwScalarOpTypeInfos_.find(RWScalarOpTypeInfo(offset));
501         if (result != rwScalarOpTypeInfos_.end()) {
502             const_cast<RWScalarOpTypeInfo &>(*result).AddObjectInfo(info);
503         } else {
504             rwScalarOpTypeInfos_.emplace(offset, info);
505         }
506     }
507 
AddDefine(uint32_t offset,PGOSampleType type,PGOSampleType superType)508     void AddDefine(uint32_t offset, PGOSampleType type, PGOSampleType superType)
509     {
510         auto result = objDefOpTypeInfos_.find(ObjDefOpTypeInfo(offset, type, superType));
511         if (result != objDefOpTypeInfos_.end()) {
512             return;
513         }
514         objDefOpTypeInfos_.emplace(offset, type, superType);
515     }
516 
517     template <typename Callback>
GetTypeInfo(Callback callback)518     void GetTypeInfo(Callback callback)
519     {
520         for (const auto &typeInfo : scalarOpTypeInfos_) {
521             auto type = typeInfo.GetType();
522             callback(typeInfo.GetOffset(), &type);
523         }
524         for (const auto &typeInfo : rwScalarOpTypeInfos_) {
525             auto type = typeInfo.GetType();
526             callback(typeInfo.GetOffset(), &type);
527         }
528         for (const auto &typeInfo : objDefOpTypeInfos_) {
529             auto classType = typeInfo.GetType();
530             callback(typeInfo.GetOffset(), &classType);
531         }
532     }
533 
534     void Merge(const PGOMethodTypeSet *info);
535     static void SkipFromBinary(void **buffer);
536 
537     bool ParseFromBinary(void **buffer, PGOProfilerHeader *const header);
538     bool ProcessToBinary(std::stringstream &stream) const;
539 
540     bool ParseFromText(const std::string &typeString);
541     void ProcessToText(std::string &text) const;
542 
543     NO_COPY_SEMANTIC(PGOMethodTypeSet);
544     NO_MOVE_SEMANTIC(PGOMethodTypeSet);
545 
546 private:
547     enum class InfoType : uint8_t { NONE, OP_TYPE, DEFINE_CLASS_TYPE = 3, USE_HCLASS_TYPE };
548 
549     class TypeInfoHeader {
550     public:
TypeInfoHeader(InfoType type,uint32_t offset)551         TypeInfoHeader(InfoType type, uint32_t offset) : infoType_(type), offset_(offset) {}
TypeInfoHeader(uint32_t size,InfoType type,uint32_t offset)552         TypeInfoHeader(uint32_t size, InfoType type, uint32_t offset)
553             : size_(size), infoType_(type), offset_(offset) {}
554 
GetInfoType()555         InfoType GetInfoType()
556         {
557             return infoType_;
558         }
559 
Size()560         int32_t Size() const
561         {
562             return size_;
563         }
564 
GetOffset()565         uint32_t GetOffset() const
566         {
567             return offset_;
568         }
569 
570     protected:
571         uint32_t size_ {0};
572         InfoType infoType_ {InfoType::NONE};
573         uint32_t offset_ {0};
574     };
575 
576     class RWScalarOpTypeInfo : public TypeInfoHeader {
577     public:
RWScalarOpTypeInfo(uint32_t offset)578         explicit RWScalarOpTypeInfo(uint32_t offset)
579             : TypeInfoHeader(InfoType::USE_HCLASS_TYPE, offset) {};
RWScalarOpTypeInfo(uint32_t offset,PGOObjectInfo info)580         RWScalarOpTypeInfo(uint32_t offset, PGOObjectInfo info)
581             : TypeInfoHeader(sizeof(RWScalarOpTypeInfo), InfoType::USE_HCLASS_TYPE, offset)
582         {
583             type_.AddObjectInfo(info);
584         }
585 
586         bool operator<(const RWScalarOpTypeInfo &right) const
587         {
588             return offset_ < right.offset_;
589         }
590 
GetCount()591         int32_t GetCount()
592         {
593             return type_.GetCount();
594         }
595 
Merge(const RWScalarOpTypeInfo & type)596         void Merge(const RWScalarOpTypeInfo &type)
597         {
598             type_.Merge(type.type_);
599         }
600 
AddObjectInfo(const PGOObjectInfo & info)601         void AddObjectInfo(const PGOObjectInfo &info)
602         {
603             type_.AddObjectInfo(info);
604         }
605 
GetType()606         PGORWOpType GetType() const
607         {
608             return type_;
609         }
610 
611         void ProcessToText(std::string &text) const;
612 
613     private:
614         PGORWOpType type_;
615     };
616 
617     class ScalarOpTypeInfo : public TypeInfoHeader {
618     public:
ScalarOpTypeInfo(uint32_t offset,PGOSampleType type)619         ScalarOpTypeInfo(uint32_t offset, PGOSampleType type)
620             : TypeInfoHeader(sizeof(ScalarOpTypeInfo), InfoType::OP_TYPE, offset), type_(type) {}
621 
622         bool operator<(const ScalarOpTypeInfo &right) const
623         {
624             return offset_ < right.offset_;
625         }
626 
SetType(PGOSampleType type)627         void SetType(PGOSampleType type)
628         {
629             if (type_ != type) {
630                 type_ = type;
631             }
632         }
633 
Merge(const ScalarOpTypeInfo & typeInfo)634         void Merge(const ScalarOpTypeInfo &typeInfo)
635         {
636             PGOSampleType combineType = GetType().CombineType(typeInfo.GetType());
637             SetType(combineType);
638         }
639 
GetType()640         PGOSampleType GetType() const
641         {
642             return type_;
643         }
644 
645     protected:
ScalarOpTypeInfo(uint32_t size,InfoType infoType,uint32_t offset,PGOSampleType type)646         ScalarOpTypeInfo(uint32_t size, InfoType infoType, uint32_t offset, PGOSampleType type)
647             : TypeInfoHeader(size, infoType, offset), type_(type) {}
648 
649     private:
650         PGOSampleType type_;
651     };
652 
653     class ObjDefOpTypeInfo : public ScalarOpTypeInfo {
654     public:
ObjDefOpTypeInfo(uint32_t offset,PGOSampleType type,PGOSampleType superType)655         ObjDefOpTypeInfo(uint32_t offset, PGOSampleType type, PGOSampleType superType)
656             : ScalarOpTypeInfo(sizeof(ObjDefOpTypeInfo), InfoType::DEFINE_CLASS_TYPE, offset, type),
657             superType_(superType) {}
658 
GetSuperType()659         PGOSampleType GetSuperType() const
660         {
661             return superType_;
662         }
663 
664         bool operator<(const ObjDefOpTypeInfo &right) const
665         {
666             return offset_ < right.GetOffset() || GetType() < right.GetType() || superType_ < right.superType_;
667         }
668 
669         void ProcessToText(std::string &text) const;
670 
671     protected:
ObjDefOpTypeInfo(uint32_t size,InfoType infoType,uint32_t offset,PGOSampleType type,PGOSampleType superType)672         ObjDefOpTypeInfo(
673             uint32_t size, InfoType infoType, uint32_t offset, PGOSampleType type, PGOSampleType superType)
674             : ScalarOpTypeInfo(size, infoType, offset, type), superType_(superType) {}
675 
676     private:
677         PGOSampleType superType_;
678     };
679 
680     std::set<ScalarOpTypeInfo> scalarOpTypeInfos_;
681     std::set<RWScalarOpTypeInfo> rwScalarOpTypeInfos_;
682     std::set<ObjDefOpTypeInfo> objDefOpTypeInfos_;
683 };
684 
685 class PGODecodeMethodInfo {
686 public:
PGODecodeMethodInfo(PGOMethodId id)687     explicit PGODecodeMethodInfo(PGOMethodId id) : methodId_(id) {}
688 
GetMethodId()689     PGOMethodId GetMethodId() const
690     {
691         return methodId_;
692     }
693 
GetPGOMethodTypeSet()694     PGOMethodTypeSet &GetPGOMethodTypeSet()
695     {
696         return pgoMethodTypeSet_;
697     }
698 
699     void Merge(const PGODecodeMethodInfo &from);
700 
701 private:
702     PGOMethodId methodId_ {0};
703     PGOMethodTypeSet pgoMethodTypeSet_ {};
704 };
705 
706 class PGOHClassLayoutDescInner {
707 public:
PGOHClassLayoutDescInner(size_t size,PGOSampleType type,PGOSampleType superType,ElementsKind kind)708     PGOHClassLayoutDescInner(size_t size, PGOSampleType type, PGOSampleType superType, ElementsKind kind)
709         : size_(size), type_(type), superType_(superType)
710     {
711         SetElementsKind(kind);
712     }
713 
714     static size_t CaculateSize(const PGOHClassLayoutDesc &desc);
715     static std::string GetTypeString(const PGOHClassLayoutDesc &desc);
716 
717     void Merge(const PGOHClassLayoutDesc &desc);
718 
Size()719     int32_t Size() const
720     {
721         return size_;
722     }
723 
GetType()724     PGOSampleType GetType() const
725     {
726         return type_;
727     }
728 
Convert(PGOProfilerHeader * const header)729     PGOHClassLayoutDesc Convert(PGOProfilerHeader *const header)
730     {
731         PGOHClassLayoutDesc desc(GetType().GetClassType());
732         desc.SetSuperClassType(superType_.GetClassType());
733         auto descInfo = GetFirst();
734         for (int32_t i = 0; i < count_; i++) {
735             desc.AddKeyAndDesc(descInfo->GetKey(), descInfo->GetHandler());
736             descInfo = GetNext(descInfo);
737         }
738         for (int32_t i = 0; i < ptCount_; i++) {
739             desc.AddPtKeyAndDesc(descInfo->GetKey(), descInfo->GetHandler());
740             descInfo = GetNext(descInfo);
741         }
742         for (int32_t i = 0; i < ctorCount_; i++) {
743             desc.AddCtorKeyAndDesc(descInfo->GetKey(), descInfo->GetHandler());
744             descInfo = GetNext(descInfo);
745         }
746         if (header->SupportElementsKind()) {
747             desc.SetElementsKind(GetElementsKind());
748         }
749         return desc;
750     }
751 
752     class PGOLayoutDescInfo {
753     public:
754         PGOLayoutDescInfo() = default;
PGOLayoutDescInfo(const CString & key,PGOHandler handler)755         PGOLayoutDescInfo(const CString &key, PGOHandler handler) : handler_(handler)
756         {
757             size_t len = key.size();
758             size_ = Size(len);
759             if (len > 0 && memcpy_s(&key_, len, key.c_str(), len) != EOK) {
760                 LOG_ECMA(ERROR) << "SetMethodName memcpy_s failed" << key << ", len = " << len;
761                 UNREACHABLE();
762             }
763             *(&key_ + len) = '\0';
764         }
765 
Size(size_t len)766         static int32_t Size(size_t len)
767         {
768             return sizeof(PGOLayoutDescInfo) + AlignUp(len, ALIGN_SIZE);
769         }
770 
Size()771         int32_t Size() const
772         {
773             return size_;
774         }
775 
GetKey()776         const char *GetKey() const
777         {
778             return &key_;
779         }
780 
GetHandler()781         PGOHandler GetHandler() const
782         {
783             return handler_;
784         }
785 
786     private:
787         int32_t size_ {0};
788         PGOHandler handler_;
789         char key_ {'\0'};
790     };
791 
792 private:
GetFirst()793     const PGOLayoutDescInfo *GetFirst() const
794     {
795         return &descInfos_;
796     }
797 
GetNext(const PGOLayoutDescInfo * current)798     const PGOLayoutDescInfo *GetNext(const PGOLayoutDescInfo *current) const
799     {
800         return reinterpret_cast<PGOLayoutDescInfo *>(reinterpret_cast<uintptr_t>(current) + current->Size());
801     }
802 
SetElementsKind(ElementsKind kind)803     void SetElementsKind(ElementsKind kind)
804     {
805         *reinterpret_cast<ElementsKind *>(GetEnd() - sizeof(ElementsKind)) = kind;
806     }
807 
GetElementsKind()808     ElementsKind GetElementsKind() const
809     {
810         return *reinterpret_cast<const ElementsKind *>(GetEnd() - sizeof(ElementsKind));
811     }
812 
GetEnd()813     uintptr_t GetEnd() const
814     {
815         return reinterpret_cast<uintptr_t>(this) + Size();
816     }
817 
818     int32_t size_;
819     PGOSampleType type_;
820     PGOSampleType superType_;
821     int32_t count_ {0};
822     int32_t ptCount_ {0};
823     int32_t ctorCount_ {0};
824     PGOLayoutDescInfo descInfos_;
825 };
826 
827 class PGOMethodInfoMap {
828 public:
829     PGOMethodInfoMap() = default;
830 
Clear()831     void Clear()
832     {
833         // PGOMethodInfo release by chunk
834         methodInfos_.clear();
835         methodTypeInfos_.clear();
836     }
837 
838     bool AddMethod(Chunk *chunk, Method *jsMethod, SampleMode mode, int32_t incCount);
839     bool AddType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type);
840     bool AddCallTargetType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type);
841     bool AddObjectInfo(Chunk *chunk, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info);
842     bool AddDefine(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType);
843     void Merge(Chunk *chunk, PGOMethodInfoMap *methodInfos);
844 
845     bool ParseFromBinary(Chunk *chunk, uint32_t threshold, void **buffer, PGOProfilerHeader *const header);
846     bool ProcessToBinary(uint32_t threshold, const CString &recordName, const SaveTask *task, std::fstream &fileStream,
847         PGOProfilerHeader *const header) const;
848 
849     bool ParseFromText(Chunk *chunk, uint32_t threshold, const std::vector<std::string> &content);
850     void ProcessToText(uint32_t threshold, const CString &recordName, std::ofstream &stream) const;
851 
GetMethodInfos()852     const CMap<PGOMethodId, PGOMethodInfo *> &GetMethodInfos() const
853     {
854         return methodInfos_;
855     }
856 
857     NO_COPY_SEMANTIC(PGOMethodInfoMap);
858     NO_MOVE_SEMANTIC(PGOMethodInfoMap);
859 
860 private:
861     PGOMethodTypeSet *GetOrInsertMethodTypeSet(Chunk *chunk, PGOMethodId methodId);
862 
863     CMap<PGOMethodId, PGOMethodInfo *> methodInfos_;
864     CMap<PGOMethodId, PGOMethodTypeSet *> methodTypeInfos_;
865     CMap<PGOMethodId, uint32_t> methodsChecksum_;
866     CMap<PGOSampleType, CMap<CString, TrackType>> globalLayoutDescInfos_;
867 };
868 
869 class PGOMethodIdSet {
870 public:
PGOMethodIdSet(Chunk * chunk)871     explicit PGOMethodIdSet(Chunk* chunk): chunk_(chunk), methodInfoMap_(chunk) {};
872     ~PGOMethodIdSet() = default;
873 
Clear()874     void Clear()
875     {
876         candidateSet_.clear();
877         for (auto &methodNameSet : methodInfoMap_) {
878             methodNameSet.second.Clear();
879         }
880         methodInfoMap_.clear();
881     }
882 
Match(EntityId methodId)883     bool Match(EntityId methodId)
884     {
885         return candidateSet_.find(methodId) != candidateSet_.end();
886     }
887 
888     template <typename Callback>
Update(const CString & recordName,Callback callback)889     bool Update(const CString &recordName, Callback callback)
890     {
891         std::unordered_set<EntityId> newIds = callback(recordName, candidateSet_);
892         if (!newIds.empty()) {
893             candidateSet_.insert(newIds.begin(), newIds.end());
894             return true;
895         }
896         return false;
897     }
898 
899     template <typename Callback>
GetTypeInfo(const char * methodName,Callback callback)900     void GetTypeInfo(const char *methodName, Callback callback)
901     {
902         // for no function checksum in ap file
903         auto iter = methodInfoMap_.find(methodName);
904         if ((iter != methodInfoMap_.end()) && (iter->second.GetFirstMethodInfo() != nullptr)) {
905             iter->second.GetFirstMethodInfo()->GetPGOMethodTypeSet().GetTypeInfo(callback);
906         }
907     }
908 
909     template <typename Callback>
GetTypeInfo(const char * methodName,uint32_t checksum,Callback callback)910     void GetTypeInfo(const char *methodName, uint32_t checksum, Callback callback)
911     {
912         auto iter = methodInfoMap_.find(methodName);
913         if ((iter != methodInfoMap_.end()) && (iter->second.GetMethodInfo(checksum) != nullptr)) {
914             return iter->second.GetMethodInfo(checksum)->GetPGOMethodTypeSet().GetTypeInfo(callback);
915         }
916         LOG_ECMA(DEBUG) << "Method checksum mismatched, name: " << methodName;
917     }
918 
MatchAndMarkMethod(const char * methodName,EntityId methodId)919     void MatchAndMarkMethod(const char *methodName, EntityId methodId)
920     {
921         const auto &iter = methodInfoMap_.find(methodName);
922         if (iter == methodInfoMap_.end()) {
923             // no matching method in PGO file.
924             return;
925         }
926         candidateSet_.emplace(methodId);
927         iter->second.SetMatch();
928     }
929 
930     bool ParseFromBinary(uint32_t threshold, void **buffer, PGOProfilerHeader *const header);
931 
932     void GetMismatchResult(const CString &recordName, uint32_t &totalMethodCount, uint32_t &mismatchMethodCount,
933                            std::set<std::pair<std::string, CString>> &mismatchMethodSet) const;
934 
935     void Merge(const PGOMethodIdSet &from);
936 
937     class PGOMethodNameSet {
938     public:
PGOMethodNameSet(Chunk * chunk)939         explicit PGOMethodNameSet(Chunk* chunk): methodMap_(chunk) {};
SetMatch()940         void SetMatch()
941         {
942             methodNameMatch_ = true;
943         }
944 
IsMatch()945         bool IsMatch() const
946         {
947             return methodNameMatch_;
948         }
949 
GetOrCreateMethodInfo(uint32_t checksum,PGOMethodId methodId)950         PGODecodeMethodInfo& GetOrCreateMethodInfo(uint32_t checksum, PGOMethodId methodId)
951         {
952             auto methodIter = methodMap_.find(checksum);
953             if (methodIter == methodMap_.end()) {
954                 auto ret = methodMap_.emplace(checksum, methodId);
955                 ASSERT(ret.second);
956                 methodIter = ret.first;
957             }
958             return methodIter->second;
959         }
960 
Merge(const PGOMethodNameSet & from)961         void Merge(const PGOMethodNameSet &from)
962         {
963             for (const auto &method : from.methodMap_) {
964                 uint32_t checksum = method.first;
965                 auto methodInfo = methodMap_.find(checksum);
966                 if (methodInfo == methodMap_.end()) {
967                     auto ret = methodMap_.emplace(checksum, method.second.GetMethodId());
968                     ASSERT(ret.second);
969                     methodInfo = ret.first;
970                 }
971                 methodInfo->second.Merge(method.second);
972             }
973         }
974 
GetFirstMethodInfo()975         PGODecodeMethodInfo *GetFirstMethodInfo()
976         {
977             if (methodMap_.empty()) {
978                 return nullptr;
979             }
980             return &(methodMap_.begin()->second);
981         }
982 
GetMethodInfo(uint32_t checksum)983         PGODecodeMethodInfo *GetMethodInfo(uint32_t checksum)
984         {
985             auto methodInfo = methodMap_.find(checksum);
986             if (methodInfo == methodMap_.end()) {
987                 return nullptr;
988             }
989             return &(methodInfo->second);
990         }
991 
Clear()992         void Clear()
993         {
994             methodMap_.clear();
995         }
996 
997     private:
998         bool methodNameMatch_ {false};
999         ChunkUnorderedMap<uint32_t, PGODecodeMethodInfo> methodMap_;
1000     };
1001 
1002     NO_COPY_SEMANTIC(PGOMethodIdSet);
1003     NO_MOVE_SEMANTIC(PGOMethodIdSet);
1004 
1005 private:
1006     Chunk* chunk_;
1007     std::unordered_set<EntityId> candidateSet_; // methodId in abc file, DO NOT for pgo internal use
1008     ChunkUnorderedMap<CString, PGOMethodNameSet> methodInfoMap_;
1009 };
1010 
1011 class PGORecordDetailInfos {
1012 public:
PGORecordDetailInfos(uint32_t hotnessThreshold)1013     explicit PGORecordDetailInfos(uint32_t hotnessThreshold) : hotnessThreshold_(hotnessThreshold)
1014     {
1015         chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1016     };
1017 
~PGORecordDetailInfos()1018     ~PGORecordDetailInfos()
1019     {
1020         Clear();
1021     }
1022 
Clear()1023     void Clear()
1024     {
1025         for (auto iter : recordInfos_) {
1026             iter.second->Clear();
1027             nativeAreaAllocator_.Delete(iter.second);
1028         }
1029         recordInfos_.clear();
1030         chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1031     }
1032 
1033     // If it is a new method, return true.
1034     bool AddMethod(const CString &recordName, Method *jsMethod, SampleMode mode, int32_t incCount);
1035     bool AddType(const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type);
1036     bool AddCallTargetType(const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type);
1037     bool AddObjectInfo(const CString &recordName, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info);
1038     bool AddDefine(
1039         const CString &recordName, PGOMethodId methodId, int32_t offset, PGOSampleType type, PGOSampleType superType);
1040     bool AddLayout(PGOSampleType type, JSTaggedType hclass, PGOObjKind kind);
1041     void Merge(const PGORecordDetailInfos &recordInfos);
1042 
1043     void ParseFromBinary(void *buffer, PGOProfilerHeader *const header);
1044     void ProcessToBinary(const SaveTask *task, std::fstream &fileStream, PGOProfilerHeader *const header) const;
1045 
1046     bool ParseFromText(std::ifstream &stream);
1047     void ProcessToText(std::ofstream &stream) const;
1048 
GetRecordInfos()1049     const CMap<CString, PGOMethodInfoMap *> &GetRecordInfos() const
1050     {
1051         return recordInfos_;
1052     }
1053 
1054     NO_COPY_SEMANTIC(PGORecordDetailInfos);
1055     NO_MOVE_SEMANTIC(PGORecordDetailInfos);
1056 
1057 private:
1058     PGOMethodInfoMap *GetMethodInfoMap(const CString &recordName);
1059     bool ParseFromBinaryForLayout(void **buffer, PGOProfilerHeader *const header);
1060     bool ProcessToBinaryForLayout(NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream) const;
1061 
1062     uint32_t hotnessThreshold_ {2};
1063     NativeAreaAllocator nativeAreaAllocator_;
1064     std::unique_ptr<Chunk> chunk_;
1065     CMap<CString, PGOMethodInfoMap *> recordInfos_;
1066     std::set<PGOHClassLayoutDesc> moduleLayoutDescInfos_;
1067 };
1068 
1069 class PGORecordSimpleInfos {
1070 public:
PGORecordSimpleInfos(uint32_t threshold)1071     explicit PGORecordSimpleInfos(uint32_t threshold) : hotnessThreshold_(threshold)
1072     {
1073         chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1074     }
1075 
~PGORecordSimpleInfos()1076     ~PGORecordSimpleInfos()
1077     {
1078         Clear();
1079     }
1080 
Clear()1081     void Clear()
1082     {
1083         for (const auto &iter : methodIds_) {
1084             iter.second->Clear();
1085             nativeAreaAllocator_.Delete(iter.second);
1086         }
1087         methodIds_.clear();
1088         chunk_ = std::make_unique<Chunk>(&nativeAreaAllocator_);
1089     }
1090 
1091     bool Match(const CString &recordName, EntityId methodId);
1092 
1093     template <typename Callback>
Update(Callback callback)1094     void Update(Callback callback)
1095     {
1096         for (auto iter = methodIds_.begin(); iter != methodIds_.end(); iter++) {
1097             auto recordName = iter->first;
1098             auto methodIds = iter->second;
1099             methodIds->Update(recordName, callback);
1100         }
1101     }
1102 
1103     template <typename Callback>
Update(const CString & recordName,Callback callback)1104     void Update(const CString &recordName, Callback callback)
1105     {
1106         auto iter = methodIds_.find(recordName);
1107         if (iter != methodIds_.end()) {
1108             iter->second->Update(recordName, callback);
1109         } else {
1110             PGOMethodIdSet *methodIds = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get());
1111             if (methodIds->Update(recordName, callback)) {
1112                 methodIds_.emplace(recordName, methodIds);
1113             } else {
1114                 nativeAreaAllocator_.Delete(methodIds);
1115             }
1116         }
1117     }
1118 
1119     template <typename Callback>
GetTypeInfo(const CString & recordName,const char * methodName,Callback callback)1120     void GetTypeInfo(const CString &recordName, const char *methodName, Callback callback)
1121     {
1122         auto iter = methodIds_.find(recordName);
1123         if (iter != methodIds_.end()) {
1124             iter->second->GetTypeInfo(methodName, callback);
1125         }
1126     }
1127 
1128     template <typename Callback>
GetTypeInfo(const CString & recordName,const char * methodName,uint32_t checksum,Callback callback)1129     void GetTypeInfo(const CString &recordName, const char *methodName, uint32_t checksum, Callback callback)
1130     {
1131         auto iter = methodIds_.find(recordName);
1132         if (iter != methodIds_.end()) {
1133             iter->second->GetTypeInfo(methodName, checksum, callback);
1134         }
1135     }
1136 
GetHClassLayoutDesc(PGOSampleType classType,PGOHClassLayoutDesc ** desc)1137     bool GetHClassLayoutDesc(PGOSampleType classType, PGOHClassLayoutDesc **desc) const
1138     {
1139         auto iter = moduleLayoutDescInfos_.find(PGOHClassLayoutDesc(classType.GetClassType()));
1140         if (iter != moduleLayoutDescInfos_.end()) {
1141             *desc = &(const_cast<PGOHClassLayoutDesc &>(*iter));
1142             return true;
1143         }
1144         return false;
1145     }
1146 
MatchAndMarkMethod(const CString & recordName,const char * methodName,EntityId methodId)1147     void MatchAndMarkMethod(const CString &recordName, const char *methodName, EntityId methodId)
1148     {
1149         auto iter = methodIds_.find(recordName);
1150         if (iter != methodIds_.end()) {
1151             return iter->second->MatchAndMarkMethod(methodName, methodId);
1152         }
1153     }
1154 
GetMismatchResult(uint32_t & totalMethodCount,uint32_t & mismatchMethodCount,std::set<std::pair<std::string,CString>> & mismatchMethodSet)1155     void GetMismatchResult(uint32_t &totalMethodCount, uint32_t &mismatchMethodCount,
1156                            std::set<std::pair<std::string, CString>> &mismatchMethodSet) const
1157     {
1158         for (const auto &methodId : methodIds_) {
1159             methodId.second->GetMismatchResult(methodId.first, totalMethodCount, mismatchMethodCount,
1160                                                mismatchMethodSet);
1161         }
1162     }
1163 
1164     void ParseFromBinary(void *buffer, PGOProfilerHeader *const header);
1165 
1166     void Merge(const PGORecordSimpleInfos &simpleInfos);
1167 
1168     NO_COPY_SEMANTIC(PGORecordSimpleInfos);
1169     NO_MOVE_SEMANTIC(PGORecordSimpleInfos);
1170 
1171 private:
1172     bool ParseFromBinaryForLayout(void **buffer, PGOProfilerHeader *const header);
1173 
1174     uint32_t hotnessThreshold_ {2};
1175     NativeAreaAllocator nativeAreaAllocator_;
1176     std::unique_ptr<Chunk> chunk_;
1177     CUnorderedMap<CString, PGOMethodIdSet *> methodIds_;
1178     std::set<PGOHClassLayoutDesc> moduleLayoutDescInfos_;
1179 };
1180 } // namespace panda::ecmascript
1181 #endif // ECMASCRIPT_PGO_PROFILER_INFO_H
1182