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