1 /* 2 * Copyright (c) 2023-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 #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 <utility> 25 #include <string.h> 26 27 #include "ecmascript/common.h" 28 #include "ecmascript/jspandafile/method_literal.h" 29 #include "ecmascript/log_wrapper.h" 30 #include "ecmascript/mem/c_containers.h" 31 #include "ecmascript/mem/c_string.h" 32 #include "ecmascript/mem/chunk_containers.h" 33 #include "ecmascript/mem/native_area_allocator.h" 34 #include "ecmascript/mem/slots.h" 35 #include "ecmascript/pgo_profiler/ap_file/pgo_file_info.h" 36 #include "ecmascript/pgo_profiler/ap_file/pgo_method_type_set.h" 37 #include "ecmascript/pgo_profiler/ap_file/pgo_profile_type_pool.h" 38 #include "ecmascript/pgo_profiler/ap_file/pgo_proto_transition_type_pool.h" 39 #include "ecmascript/pgo_profiler/ap_file/pgo_record_pool.h" 40 #include "ecmascript/pgo_profiler/pgo_context.h" 41 #include "ecmascript/pgo_profiler/pgo_profiler.h" 42 #include "ecmascript/pgo_profiler/pgo_profiler_layout.h" 43 #include "ecmascript/pgo_profiler/pgo_utils.h" 44 #include "ecmascript/pgo_profiler/types/pgo_profiler_type.h" 45 #include "ecmascript/property_attributes.h" 46 #include "ecmascript/ts_types/global_type_info.h" 47 #include "macros.h" 48 49 namespace panda::ecmascript::pgo { 50 class SaveTask; 51 class PGOContext; 52 53 class PGOPandaFileInfos { 54 public: Sample(uint32_t checksum)55 void Sample(uint32_t checksum) 56 { 57 fileInfos_.emplace(checksum); 58 } 59 Clear()60 void Clear() 61 { 62 fileInfos_.clear(); 63 } 64 65 void ParseFromBinary(void *buffer, SectionInfo *const info); 66 void ProcessToBinary(std::fstream &fileStream, SectionInfo *info) const; 67 void Merge(const PGOPandaFileInfos &pandaFileInfos); 68 bool VerifyChecksum(const PGOPandaFileInfos &pandaFileInfos, const std::string &base, 69 const std::string &incoming) const; 70 71 void ProcessToText(std::ofstream &stream) const; 72 bool ParseFromText(std::ifstream &stream); 73 74 bool Checksum(uint32_t checksum) const; 75 76 private: 77 class FileInfo { 78 public: 79 FileInfo() = default; FileInfo(uint32_t checksum)80 FileInfo(uint32_t checksum) : size_(LastSize()), checksum_(checksum) {} 81 LastSize()82 static size_t LastSize() 83 { 84 return sizeof(FileInfo); 85 } 86 Size()87 size_t Size() const 88 { 89 return static_cast<size_t>(size_); 90 } 91 92 bool operator<(const FileInfo &right) const 93 { 94 return checksum_ < right.checksum_; 95 } 96 GetChecksum()97 uint32_t GetChecksum() const 98 { 99 return checksum_; 100 } 101 102 private: 103 // Support extended fields 104 uint32_t size_; 105 uint32_t checksum_; 106 }; 107 108 std::set<FileInfo> fileInfos_; 109 }; 110 111 class PGOMethodInfo { 112 public: 113 static constexpr int METHOD_INFO_COUNT = 4; 114 static constexpr int METHOD_ID_INDEX = 0; 115 static constexpr int METHOD_COUNT_INDEX = 1; 116 static constexpr int METHOD_MODE_INDEX = 2; 117 static constexpr int METHOD_NAME_INDEX = 3; 118 static constexpr uint32_t METHOD_MAX_HIT_COUNT = 10000U; 119 PGOMethodInfo(PGOMethodId id)120 explicit PGOMethodInfo(PGOMethodId id) : id_(id) {} 121 PGOMethodInfo(PGOMethodId id,uint32_t count,SampleMode mode,const char * methodName)122 PGOMethodInfo(PGOMethodId id, uint32_t count, SampleMode mode, const char *methodName) 123 : id_(id), count_(count), mode_(mode) 124 { 125 size_t len = strlen(methodName); 126 size_ = static_cast<uint32_t>(Size(len)); 127 if (len > 0 && memcpy_s(&methodName_, len, methodName, len) != EOK) { 128 LOG_ECMA(ERROR) << "SetMethodName memcpy_s failed" << methodName << ", len = " << len; 129 UNREACHABLE(); 130 } 131 *(&methodName_ + len) = '\0'; 132 } 133 134 static uint32_t PUBLIC_API CalcChecksum(const char *name, const uint8_t *byteCodeArray, uint32_t byteCodeLength); 135 136 static uint32_t CalcOpCodeChecksum(const uint8_t *byteCodeArray, uint32_t byteCodeLength); 137 Size(uint32_t length)138 static int32_t Size(uint32_t length) 139 { 140 return sizeof(PGOMethodInfo) + AlignUp(length, GetAlignmentInBytes(ALIGN_SIZE)); 141 } 142 Size()143 int32_t Size() const 144 { 145 return size_; 146 } 147 GetSampleMode(std::string content,SampleMode & mode)148 static bool GetSampleMode(std::string content, SampleMode &mode) 149 { 150 if (content == "HOTNESS_MODE") { 151 mode = SampleMode::HOTNESS_MODE; 152 } else if (content == "CALL_MODE") { 153 mode = SampleMode::CALL_MODE; 154 } else { 155 return false; 156 } 157 return true; 158 } 159 IncreaseCount()160 void IncreaseCount() 161 { 162 count_++; 163 } 164 ClearCount()165 void ClearCount() 166 { 167 count_ = 0; 168 } 169 Merge(const PGOMethodInfo * info)170 void Merge(const PGOMethodInfo *info) 171 { 172 if (!(id_ == info->GetMethodId())) { 173 LOG_ECMA(ERROR) << "The method id must same for merging"; 174 return; 175 } 176 count_ = std::min(count_ + info->GetCount(), METHOD_MAX_HIT_COUNT); 177 SetSampleMode(info->GetSampleMode()); 178 } 179 GetMethodId()180 PGOMethodId GetMethodId() const 181 { 182 return id_; 183 } 184 GetCount()185 uint32_t GetCount() const 186 { 187 return count_; 188 } 189 GetMethodName()190 const char *GetMethodName() const 191 { 192 return &methodName_; 193 } 194 SetSampleMode(SampleMode mode)195 void SetSampleMode(SampleMode mode) 196 { 197 if (mode_ == SampleMode::HOTNESS_MODE) { 198 return; 199 } 200 mode_ = mode; 201 } 202 GetSampleMode()203 SampleMode GetSampleMode() const 204 { 205 return mode_; 206 } 207 GetSampleModeToString()208 std::string GetSampleModeToString() const 209 { 210 std::string result; 211 switch (mode_) { 212 case SampleMode::HOTNESS_MODE: 213 result = "HOTNESS_MODE"; 214 break; 215 case SampleMode::CALL_MODE: 216 result = "CALL_MODE"; 217 break; 218 default: 219 LOG_ECMA(ERROR) << "mode error"; 220 } 221 return result; 222 } 223 IsFilter(uint32_t threshold)224 bool IsFilter(uint32_t threshold) const 225 { 226 if (count_ < threshold && mode_ == SampleMode::CALL_MODE) { 227 return true; 228 } 229 return false; 230 } 231 232 void ParseFromBinary(void **buffer); 233 void ProcessToBinary(std::ofstream &fileStream) const; 234 235 static std::vector<std::string> ParseFromText(const std::string &infoString); 236 void ProcessToText(std::string &text) const; 237 238 void ProcessToJson(ProfileType::VariantMap &function) const; 239 240 NO_COPY_SEMANTIC(PGOMethodInfo); 241 NO_MOVE_SEMANTIC(PGOMethodInfo); 242 243 private: 244 uint32_t size_ {0}; 245 PGOMethodId id_; 246 uint32_t count_ {0}; 247 SampleMode mode_ {SampleMode::CALL_MODE}; 248 char methodName_ {0}; 249 }; 250 251 class PGODecodeMethodInfo { 252 public: PGODecodeMethodInfo(PGOMethodId id)253 explicit PGODecodeMethodInfo(PGOMethodId id) : methodId_(id) {} 254 GetMethodId()255 PGOMethodId GetMethodId() const 256 { 257 return methodId_; 258 } 259 GetPGOMethodTypeSet()260 PGOMethodTypeSet &GetPGOMethodTypeSet() 261 { 262 return pgoMethodTypeSet_; 263 } 264 265 void Merge(const PGODecodeMethodInfo &from); 266 267 private: 268 PGOMethodId methodId_ {0}; 269 PGOMethodTypeSet pgoMethodTypeSet_ {}; 270 }; 271 272 class PGOMethodInfoMap { 273 public: 274 PGOMethodInfoMap() = default; 275 Clear()276 void Clear() 277 { 278 // PGOMethodInfo release by chunk 279 for (auto &entry:methodTypeInfos_) { 280 entry.second->Clear(); 281 } 282 methodInfos_.clear(); 283 methodTypeInfos_.clear(); 284 } 285 286 bool AddMethod(Chunk *chunk, Method *jsMethod, SampleMode mode); 287 bool AddType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type); 288 bool AddCallTargetType(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGOSampleType type); 289 bool AddObjectInfo(Chunk *chunk, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info); 290 bool AddDefine(Chunk *chunk, PGOMethodId methodId, int32_t offset, PGODefineOpType type); 291 void Merge(Chunk *chunk, PGOMethodInfoMap *methodInfos); 292 293 bool ParseFromBinary(Chunk *chunk, PGOContext &context, void **buffer); 294 bool ProcessToBinary(PGOContext &context, ProfileTypeRef recordProfileRef, const SaveTask *task, 295 std::fstream &fileStream, PGOProfilerHeader *const header) const; 296 297 bool ParseFromText(Chunk *chunk, uint32_t threshold, const std::vector<std::string> &content); 298 void ProcessToText(uint32_t threshold, const CString &recordName, std::ofstream &stream) const; 299 300 void ProcessToJson(uint32_t threshold, ProfileType::jModuleType &jModule) const; 301 GetMethodInfos()302 const CMap<PGOMethodId, PGOMethodInfo *> &GetMethodInfos() const 303 { 304 return methodInfos_; 305 } 306 307 NO_COPY_SEMANTIC(PGOMethodInfoMap); 308 NO_MOVE_SEMANTIC(PGOMethodInfoMap); 309 310 private: 311 PGOMethodTypeSet *GetOrInsertMethodTypeSet(Chunk *chunk, PGOMethodId methodId); 312 313 CMap<PGOMethodId, PGOMethodInfo *> methodInfos_; 314 CMap<PGOMethodId, PGOMethodTypeSet *> methodTypeInfos_; 315 CMap<PGOMethodId, uint32_t> methodsChecksum_; 316 CMap<PGOSampleType, CMap<CString, TrackType>> globalLayoutDescInfos_; 317 }; 318 319 class PGOMethodIdSet { 320 public: PGOMethodIdSet(Chunk * chunk)321 explicit PGOMethodIdSet(Chunk* chunk): chunk_(chunk), methodInfoMap_(chunk) {}; 322 ~PGOMethodIdSet() = default; 323 Clear()324 void Clear() 325 { 326 candidateSet_.clear(); 327 for (auto &methodNameSet : methodInfoMap_) { 328 methodNameSet.second.Clear(); 329 } 330 methodInfoMap_.clear(); 331 } 332 Match(EntityId methodId)333 bool Match(EntityId methodId) 334 { 335 return candidateSet_.find(methodId) != candidateSet_.end(); 336 } 337 338 template <typename Callback> Update(const CString & recordName,Callback callback)339 bool Update(const CString &recordName, Callback callback) 340 { 341 std::unordered_set<EntityId> newIds = callback(recordName, candidateSet_); 342 if (!newIds.empty()) { 343 candidateSet_.insert(newIds.begin(), newIds.end()); 344 return true; 345 } 346 return false; 347 } 348 349 template <typename Callback> GetTypeInfo(const char * methodName,Callback callback)350 void GetTypeInfo(const char *methodName, Callback callback) 351 { 352 // for no function checksum in ap file 353 auto iter = methodInfoMap_.find(methodName); 354 if ((iter != methodInfoMap_.end()) && (iter->second.GetFirstMethodInfo() != nullptr)) { 355 iter->second.GetFirstMethodInfo()->GetPGOMethodTypeSet().GetTypeInfo(callback); 356 } 357 } 358 359 template <typename Callback> GetTypeInfo(const char * methodName,uint32_t checksum,Callback callback)360 void GetTypeInfo(const char *methodName, uint32_t checksum, Callback callback) 361 { 362 auto iter = methodInfoMap_.find(methodName); 363 if ((iter != methodInfoMap_.end()) && (iter->second.GetMethodInfo(checksum) != nullptr)) { 364 return iter->second.GetMethodInfo(checksum)->GetPGOMethodTypeSet().GetTypeInfo(callback); 365 } 366 LOG_ECMA(DEBUG) << "Method checksum mismatched, name: " << methodName; 367 } 368 MatchAndMarkMethod(const char * methodName,EntityId methodId)369 void MatchAndMarkMethod(const char *methodName, EntityId methodId) 370 { 371 const auto &iter = methodInfoMap_.find(methodName); 372 if (iter == methodInfoMap_.end()) { 373 // no matching method in PGO file. 374 return; 375 } 376 candidateSet_.emplace(methodId); 377 iter->second.SetMatch(); 378 } 379 380 bool ParseFromBinary(PGOContext &context, void **buffer); 381 382 void GetMismatchResult(const CString &recordName, uint32_t &totalMethodCount, uint32_t &mismatchMethodCount, 383 std::set<std::pair<std::string, CString>> &mismatchMethodSet) const; 384 385 void Merge(const PGOMethodIdSet &from); 386 387 class PGOMethodNameSet { 388 public: PGOMethodNameSet(Chunk * chunk)389 explicit PGOMethodNameSet(Chunk* chunk): methodMap_(chunk) {}; SetMatch()390 void SetMatch() 391 { 392 methodNameMatch_ = true; 393 } 394 IsMatch()395 bool IsMatch() const 396 { 397 return methodNameMatch_; 398 } 399 GetOrCreateMethodInfo(uint32_t checksum,PGOMethodId methodId)400 PGODecodeMethodInfo& GetOrCreateMethodInfo(uint32_t checksum, PGOMethodId methodId) 401 { 402 auto methodIter = methodMap_.find(checksum); 403 if (methodIter == methodMap_.end()) { 404 auto ret = methodMap_.emplace(checksum, methodId); 405 ASSERT(ret.second); 406 methodIter = ret.first; 407 } 408 return methodIter->second; 409 } 410 Merge(const PGOMethodNameSet & from)411 void Merge(const PGOMethodNameSet &from) 412 { 413 for (const auto &method : from.methodMap_) { 414 uint32_t checksum = method.first; 415 auto methodInfo = methodMap_.find(checksum); 416 if (methodInfo == methodMap_.end()) { 417 auto ret = methodMap_.emplace(checksum, method.second.GetMethodId()); 418 ASSERT(ret.second); 419 methodInfo = ret.first; 420 } 421 methodInfo->second.Merge(method.second); 422 } 423 } 424 GetFirstMethodInfo()425 PGODecodeMethodInfo *GetFirstMethodInfo() 426 { 427 if (methodMap_.empty()) { 428 return nullptr; 429 } 430 return &(methodMap_.begin()->second); 431 } 432 GetMethodInfo(uint32_t checksum)433 PGODecodeMethodInfo *GetMethodInfo(uint32_t checksum) 434 { 435 auto methodInfo = methodMap_.find(checksum); 436 if (methodInfo == methodMap_.end()) { 437 return nullptr; 438 } 439 return &(methodInfo->second); 440 } 441 Clear()442 void Clear() 443 { 444 methodMap_.clear(); 445 } 446 447 private: 448 bool methodNameMatch_ {false}; 449 ChunkUnorderedMap<uint32_t, PGODecodeMethodInfo> methodMap_; 450 }; 451 452 NO_COPY_SEMANTIC(PGOMethodIdSet); 453 NO_MOVE_SEMANTIC(PGOMethodIdSet); 454 455 private: 456 Chunk* chunk_; 457 std::unordered_set<EntityId> candidateSet_; // methodId in abc file, DO NOT for pgo internal use 458 ChunkUnorderedMap<CString, PGOMethodNameSet> methodInfoMap_; 459 }; 460 461 class PGORecordDetailInfos : public PGOContext { 462 public: 463 explicit PGORecordDetailInfos(uint32_t hotnessThreshold); 464 465 ~PGORecordDetailInfos() override; 466 467 void Clear(); 468 void InitSections(); 469 470 // If it is a new method, return true. 471 bool AddMethod(ProfileType recordProfileType, Method *jsMethod, SampleMode mode); 472 bool AddType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGOSampleType type); 473 bool AddCallTargetType(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGOSampleType type); 474 bool AddObjectInfo(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, const PGOObjectInfo &info); 475 bool AddDefine(ProfileType recordProfileType, PGOMethodId methodId, int32_t offset, PGODefineOpType type); 476 477 bool AddRwUseInfo(ProfileType rootType); 478 bool AddRootLayout(JSTaggedType hclass, ProfileType rootType); 479 bool UpdateTransitionLayout( 480 ProfileType rootType, JSTaggedType parent, ProfileType parentType, JSTaggedType child, ProfileType childType); 481 bool UpdateLayout(ProfileType rootType, JSTaggedType hclass, ProfileType curType); 482 void AddRootPtType(ProfileType rootType, ProfileType ptType); 483 bool IsDumped(ProfileType rootType, ProfileType curType) const; 484 485 void Merge(const PGORecordDetailInfos &recordInfos); 486 487 void UpdateLayout(); 488 489 bool ParseFromBinary(void *buffer, PGOProfilerHeader *const header); 490 void ProcessToBinary(const SaveTask *task, std::fstream &fileStream, PGOProfilerHeader *const header); 491 492 bool ParseFromText(std::ifstream &stream); 493 void ProcessToText(std::ofstream &stream) const; 494 GetRecordInfos()495 const CMap<ProfileType, PGOMethodInfoMap *> &GetRecordInfos() const 496 { 497 return recordInfos_; 498 } 499 GetRecordPool()500 std::shared_ptr<PGORecordPool> GetRecordPool() const 501 { 502 return recordPool_; 503 } 504 GetProfileTypePool()505 std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override 506 { 507 return profileTypePool_; 508 } 509 GetProtoTransitionPool()510 std::shared_ptr<PGOProtoTransitionPool> GetProtoTransitionPool() const 511 { 512 return protoTransitionPool_; 513 } 514 GetHotnessThreshold()515 uint32_t GetHotnessThreshold() const override 516 { 517 return hotnessThreshold_; 518 } 519 GetHeader()520 PGOProfilerHeader *GetHeader() const override 521 { 522 return header_; 523 } 524 SupportElementsKind()525 bool SupportElementsKind() const override 526 { 527 ASSERT(header_ != nullptr); 528 return header_->SupportElementsKind(); 529 } 530 SupportElementsTrackInfo()531 bool SupportElementsTrackInfo() const override 532 { 533 ASSERT(header_ != nullptr); 534 return header_->SupportElementsTrackInfo(); 535 } 536 ResetAbcIdRemap()537 void ResetAbcIdRemap() const override 538 { 539 abcIdRemap_.clear(); 540 } 541 AddAbcIdRemap(ApEntityId oldId,ApEntityId newId)542 void AddAbcIdRemap(ApEntityId oldId, ApEntityId newId) const override 543 { 544 abcIdRemap_[oldId] = newId; 545 } 546 GetAbcIdRemap()547 const std::map<ApEntityId, ApEntityId> &GetAbcIdRemap() const override 548 { 549 return abcIdRemap_; 550 } 551 552 NO_COPY_SEMANTIC(PGORecordDetailInfos); 553 NO_MOVE_SEMANTIC(PGORecordDetailInfos); 554 555 private: 556 PGOMethodInfoMap *GetMethodInfoMap(ProfileType recordProfileType); 557 bool ParseFromBinaryForLayout(void **buffer); 558 bool ProcessToBinaryForLayout(NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream); 559 560 uint32_t hotnessThreshold_ {2}; 561 NativeAreaAllocator nativeAreaAllocator_; 562 std::unique_ptr<Chunk> chunk_; 563 CMap<ProfileType, PGOMethodInfoMap *> recordInfos_; 564 std::set<PGOHClassTreeDesc> hclassTreeDescInfos_; 565 PGOProfilerHeader *header_ {nullptr}; 566 std::shared_ptr<PGORecordPool> recordPool_; 567 std::shared_ptr<PGOProtoTransitionPool> protoTransitionPool_; 568 std::shared_ptr<PGOProfileTypePool> profileTypePool_; 569 mutable std::map<ApEntityId, ApEntityId> abcIdRemap_; 570 }; 571 572 class PGORecordSimpleInfos : public PGOContext { 573 public: 574 explicit PGORecordSimpleInfos(uint32_t threshold); 575 576 ~PGORecordSimpleInfos() override; 577 578 void Clear(); 579 580 void InitSections(); 581 582 bool Match(const CString &abcNormalizedDesc, const CString &recordName, EntityId methodId); 583 584 template <typename Callback> Update(const CString & abcNormalizedDesc,Callback callback)585 void Update(const CString &abcNormalizedDesc, Callback callback) 586 { 587 auto abcMethodIds = methodIds_.find(abcNormalizedDesc); 588 if (abcMethodIds == methodIds_.end()) { 589 return; 590 } 591 for (auto iter = abcMethodIds->second.begin(); iter != abcMethodIds->second.end(); iter++) { 592 auto recordName = iter->first; 593 auto methodIds = iter->second; 594 methodIds->Update(recordName, callback); 595 } 596 } 597 598 template <typename Callback> Update(const CString & abcNormalizedDesc,const CString & recordName,Callback callback)599 void Update(const CString &abcNormalizedDesc, const CString &recordName, Callback callback) 600 { 601 auto abcMethodIds = methodIds_.find(abcNormalizedDesc); 602 if (abcMethodIds == methodIds_.end()) { 603 return; 604 } 605 auto iter = abcMethodIds->second.find(recordName); 606 if (iter != abcMethodIds->second.end()) { 607 iter->second->Update(recordName, callback); 608 } else { 609 PGOMethodIdSet *methodIdSet = nativeAreaAllocator_.New<PGOMethodIdSet>(chunk_.get()); 610 if (methodIdSet->Update(recordName, callback)) { 611 abcMethodIds->second.emplace(recordName, methodIdSet); 612 } else { 613 nativeAreaAllocator_.Delete(methodIdSet); 614 } 615 } 616 } 617 618 template <typename Callback> GetTypeInfo(const CString & abcNormalizedDesc,const CString & recordName,const char * methodName,Callback callback)619 void GetTypeInfo(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName, 620 Callback callback) 621 { 622 auto abcMethodIds = methodIds_.find(abcNormalizedDesc); 623 if (abcMethodIds == methodIds_.end()) { 624 return; 625 } 626 auto iter = abcMethodIds->second.find(recordName); 627 if (iter != abcMethodIds->second.end()) { 628 iter->second->GetTypeInfo(methodName, callback); 629 } 630 } 631 632 template <typename Callback> GetTypeInfo(const CString & abcNormalizedDesc,const CString & recordName,const char * methodName,uint32_t checksum,Callback callback)633 void GetTypeInfo(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName, 634 uint32_t checksum, Callback callback) 635 { 636 auto abcMethodIds = methodIds_.find(abcNormalizedDesc); 637 if (abcMethodIds == methodIds_.end()) { 638 return; 639 } 640 auto iter = abcMethodIds->second.find(recordName); 641 if (iter != abcMethodIds->second.end()) { 642 iter->second->GetTypeInfo(methodName, checksum, callback); 643 } 644 } 645 GetProtoTransitionPool()646 std::shared_ptr<PGOProtoTransitionPool> GetProtoTransitionPool() const 647 { 648 return protoTransitionPool_; 649 } 650 GetHClassTreeDesc(PGOSampleType profileType,PGOHClassTreeDesc ** desc)651 bool GetHClassTreeDesc(PGOSampleType profileType, PGOHClassTreeDesc **desc) const 652 { 653 auto iter = hclassTreeDescInfos_.find(PGOHClassTreeDesc(profileType.GetProfileType())); 654 if (iter != hclassTreeDescInfos_.end()) { 655 *desc = &(const_cast<PGOHClassTreeDesc &>(*iter)); 656 return true; 657 } 658 return false; 659 } 660 661 template <typename Callback> IterateHClassTreeDesc(Callback callback)662 bool IterateHClassTreeDesc(Callback callback) const 663 { 664 for (auto treeDescInfo : hclassTreeDescInfos_) { 665 callback(&treeDescInfo); 666 } 667 return true; 668 } 669 670 template <typename Callback> IterateProtoTransitionPool(Callback callback)671 bool IterateProtoTransitionPool(Callback callback) const 672 { 673 protoTransitionPool_->Iterate(callback); 674 return true; 675 } 676 MatchAndMarkMethod(const CString & abcNormalizedDesc,const CString & recordName,const char * methodName,EntityId methodId)677 void MatchAndMarkMethod(const CString &abcNormalizedDesc, const CString &recordName, const char *methodName, 678 EntityId methodId) 679 { 680 auto abcMethodIds = methodIds_.find(abcNormalizedDesc); 681 if (abcMethodIds == methodIds_.end()) { 682 return; 683 } 684 auto iter = abcMethodIds->second.find(recordName); 685 if (iter != abcMethodIds->second.end()) { 686 return iter->second->MatchAndMarkMethod(methodName, methodId); 687 } 688 } 689 GetMismatchResult(const CString & abcNormalizedDesc,uint32_t & totalMethodCount,uint32_t & mismatchMethodCount,std::set<std::pair<std::string,CString>> & mismatchMethodSet)690 void GetMismatchResult(const CString &abcNormalizedDesc, uint32_t &totalMethodCount, uint32_t &mismatchMethodCount, 691 std::set<std::pair<std::string, CString>> &mismatchMethodSet) const 692 { 693 auto abcMethodIds = methodIds_.find(abcNormalizedDesc); 694 if (abcMethodIds == methodIds_.end()) { 695 return; 696 } 697 for (const auto &methodId : abcMethodIds->second) { 698 methodId.second->GetMismatchResult(methodId.first, totalMethodCount, mismatchMethodCount, 699 mismatchMethodSet); 700 } 701 } 702 703 void ParseFromBinary(void *buffer, PGOProfilerHeader *const header, std::shared_ptr<PGOAbcFilePool> &abcFilePool); 704 705 void Merge(const PGORecordSimpleInfos &simpleInfos); 706 GetProfileTypePool()707 std::shared_ptr<PGOProfileTypePool> GetProfileTypePool() const override 708 { 709 return profileTypePool_; 710 } 711 GetHotnessThreshold()712 uint32_t GetHotnessThreshold() const override 713 { 714 return hotnessThreshold_; 715 } 716 GetHeader()717 PGOProfilerHeader *GetHeader() const override 718 { 719 return header_; 720 } 721 SupportElementsKind()722 bool SupportElementsKind() const override 723 { 724 ASSERT(header_ != nullptr); 725 return header_->SupportElementsKind(); 726 } 727 SupportElementsTrackInfo()728 bool SupportElementsTrackInfo() const override 729 { 730 ASSERT(header_ != nullptr); 731 return header_->SupportElementsTrackInfo(); 732 } 733 ResetAbcIdRemap()734 void ResetAbcIdRemap() const override 735 { 736 abcIdRemap_.clear(); 737 } 738 GetAbcIdRemap()739 const std::map<ApEntityId, ApEntityId> &GetAbcIdRemap() const override 740 { 741 return abcIdRemap_; 742 } 743 AddAbcIdRemap(ApEntityId oldId,ApEntityId newId)744 void AddAbcIdRemap(ApEntityId oldId, ApEntityId newId) const override 745 { 746 abcIdRemap_[oldId] = newId; 747 } 748 749 NO_COPY_SEMANTIC(PGORecordSimpleInfos); 750 NO_MOVE_SEMANTIC(PGORecordSimpleInfos); 751 752 private: 753 bool ParseFromBinaryForLayout(void **buffer); 754 755 uint32_t hotnessThreshold_ {2}; 756 NativeAreaAllocator nativeAreaAllocator_; 757 std::unique_ptr<Chunk> chunk_; 758 CUnorderedMap<CString, CUnorderedMap<CString, PGOMethodIdSet *>> methodIds_; 759 PGOProfilerHeader *header_ {nullptr}; 760 // std::list<std::weak_ptr<PGOFileSectionInterface>> apSectionList_; 761 std::shared_ptr<PGORecordPool> recordPool_; 762 std::shared_ptr<PGOProtoTransitionPool> protoTransitionPool_; 763 std::shared_ptr<PGOProfileTypePool> profileTypePool_; 764 std::set<PGOHClassTreeDesc> hclassTreeDescInfos_; 765 mutable std::map<ApEntityId, ApEntityId> abcIdRemap_; 766 }; 767 } // namespace panda::ecmascript::pgo 768 #endif // ECMASCRIPT_PGO_PROFILER_INFO_H 769