diff --git a/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp b/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp index b5e283ef44..64bcf99b30 100644 --- a/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp +++ b/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp @@ -76,7 +76,7 @@ void CpuProfiler::StartCpuProfilerForInfo() vm_->GetJSThread()->SetCallNapiGetStack(true); generator_->SetIsStart(true); Taskpool::GetCurrentTaskpool()->PostTask( - std::make_unique(generator_, interval_)); + std::make_unique(vm_->GetJSThread()->GetThreadId(), generator_, interval_)); } void CpuProfiler::StartCpuProfilerForFile(const std::string &fileName) @@ -132,7 +132,7 @@ void CpuProfiler::StartCpuProfilerForFile(const std::string &fileName) vm_->GetJSThread()->SetCallNapiGetStack(true); generator_->SetIsStart(true); Taskpool::GetCurrentTaskpool()->PostTask( - std::make_unique(generator_, interval_)); + std::make_unique(vm_->GetJSThread()->GetThreadId(), generator_, interval_)); } std::unique_ptr CpuProfiler::StopCpuProfilerForInfo() @@ -267,7 +267,7 @@ void CpuProfiler::GetFrameStack(FrameHandler &frameHandler) if (method == nullptr) { continue; } - + void *methodIdentifier = GetMethodIdentifier(method, frameHandler); if (stackInfo.count(methodIdentifier) == 0) { if (UNLIKELY(!ParseMethodInfo(methodIdentifier, frameHandler, method->GetJSPandaFile(), false))) { diff --git a/ecmascript/dfx/cpu_profiler/sampling_processor.cpp b/ecmascript/dfx/cpu_profiler/sampling_processor.cpp index 868b432d36..02771b7ba6 100644 --- a/ecmascript/dfx/cpu_profiler/sampling_processor.cpp +++ b/ecmascript/dfx/cpu_profiler/sampling_processor.cpp @@ -29,7 +29,7 @@ namespace panda::ecmascript { const int USEC_PER_SEC = 1000 * 1000; const int NSEC_PER_USEC = 1000; -SamplingProcessor::SamplingProcessor(SamplesRecord *generator, int interval) +SamplingProcessor::SamplingProcessor(int32_t id, SamplesRecord *generator, int interval) : Task(id) { generator_ = generator; interval_ = interval; diff --git a/ecmascript/dfx/cpu_profiler/sampling_processor.h b/ecmascript/dfx/cpu_profiler/sampling_processor.h index a8fabe5f46..93003b9e93 100644 --- a/ecmascript/dfx/cpu_profiler/sampling_processor.h +++ b/ecmascript/dfx/cpu_profiler/sampling_processor.h @@ -31,7 +31,7 @@ class SamplingProcessor : public Task { public: static uint64_t GetMicrosecondsTimeStamp(); - explicit SamplingProcessor(SamplesRecord *generator, int interval); + explicit SamplingProcessor(int32_t id, SamplesRecord *generator, int interval); virtual ~SamplingProcessor(); bool Run(uint32_t threadIndex) override; @@ -47,4 +47,4 @@ private: bool firstWrite_ = true; }; } // namespace panda::ecmascript -#endif // ECMASCRIPT_SAMPLING_PROCESSOR_H \ No newline at end of file +#endif // ECMASCRIPT_SAMPLING_PROCESSOR_H diff --git a/ecmascript/dfx/pgo_profiler/pgo_profiler_manager.cpp b/ecmascript/dfx/pgo_profiler/pgo_profiler_manager.cpp index d978042055..d61625dcc5 100644 --- a/ecmascript/dfx/pgo_profiler/pgo_profiler_manager.cpp +++ b/ecmascript/dfx/pgo_profiler/pgo_profiler_manager.cpp @@ -15,7 +15,7 @@ #include "ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h" -#include +#include #include "ecmascript/base/file_path_helper.h" #include "ecmascript/js_function.h" @@ -24,6 +24,13 @@ #include "ecmascript/mem/c_string.h" namespace panda::ecmascript { + +PGOProfiler::~PGOProfiler() +{ + isEnable_ = false; + profilerMap_.clear(); +} + void PGOProfiler::Sample(JSTaggedType value) { if (!isEnable_) { @@ -40,36 +47,66 @@ void PGOProfiler::Sample(JSTaggedType value) CString recordName = ConvertToString(recordNameValue); auto iter = profilerMap_.find(recordName); if (iter != profilerMap_.end()) { - auto &methodCountMap = iter->second; - auto result = methodCountMap.find(jsMethod->GetMethodId()); - if (result != methodCountMap.end()) { - auto &info = result->second; + auto methodCountMap = iter->second; + auto result = methodCountMap->find(jsMethod->GetMethodId()); + if (result != methodCountMap->end()) { + auto info = result->second; info->IncreaseCount(); } else { - auto info = new MethodProfilerInfo(1, jsMethod->ParseFunctionName()); - methodCountMap.emplace(jsMethod->GetMethodId(), info); + auto info = chunk_.New(1, jsMethod->ParseFunctionName()); + methodCountMap->emplace(jsMethod->GetMethodId(), info); + methodCount_++; } } else { - std::unordered_map methodsCountMap; - auto info = new MethodProfilerInfo(1, jsMethod->ParseFunctionName()); - methodsCountMap.emplace(jsMethod->GetMethodId(), info); + ChunkUnorderedMap *methodsCountMap = + chunk_.New>(&chunk_); + auto info = chunk_.New(1, jsMethod->ParseFunctionName()); + methodsCountMap->emplace(jsMethod->GetMethodId(), info); profilerMap_.emplace(recordName, methodsCountMap); + methodCount_++; + } + // Merged every 10 methods + if (methodCount_ >= MERGED_EVERY_COUNT) { + LOG_ECMA(INFO) << "Sample: post task to save profiler"; + PGOProfilerManager::GetInstance()->TerminateSaveTask(); + PGOProfilerManager::GetInstance()->Merge(this); + PGOProfilerManager::GetInstance()->PostSaveTask(); + methodCount_ = 0; } } } void PGOProfilerManager::Initialize(uint32_t hotnessThreshold, const std::string &outDir) { - isEnable_ = false; - globalProfilerMap_.clear(); hotnessThreshold_ = hotnessThreshold; - if (outDir.empty()) { - outDir_ = ""; - isEnable_ = false; - } outDir_ = outDir; } +void PGOProfilerManager::Destroy() +{ + if (!isEnable_) { + return; + } + // SaveTask is already finished + SaveProfiler(); + globalProfilerMap_->clear(); + chunk_.reset(); + nativeAreaAllocator_.reset(); + isEnable_ = false; +} + +void PGOProfilerManager::InitializeData() +{ + os::memory::LockHolder lock(mutex_); + if (!isEnable_) { + isEnable_ = true; + nativeAreaAllocator_ = std::make_unique(); + chunk_ = std::make_unique(nativeAreaAllocator_.get()); + globalProfilerMap_ = chunk_-> + New *>>(chunk_.get()); + } +} + void PGOProfilerManager::Merge(PGOProfiler *profiler) { if (!isEnable_) { @@ -80,28 +117,31 @@ void PGOProfilerManager::Merge(PGOProfiler *profiler) for (auto iter = profiler->profilerMap_.begin(); iter != profiler->profilerMap_.end(); iter++) { auto recordName = iter->first; auto methodCountMap = iter->second; - auto globalMethodCountIter = globalProfilerMap_.find(recordName); - if (globalMethodCountIter == globalProfilerMap_.end()) { - globalProfilerMap_.emplace(recordName, methodCountMap); - continue; + auto globalMethodCountIter = globalProfilerMap_->find(recordName); + ChunkUnorderedMap *globalMethodCountMap = nullptr; + if (globalMethodCountIter == globalProfilerMap_->end()) { + globalMethodCountMap = chunk_->New>(chunk_.get()); + globalProfilerMap_->emplace(recordName, globalMethodCountMap); + } else { + globalMethodCountMap = globalMethodCountIter->second; } - auto &globalMethodCountMap = globalMethodCountIter->second; - for (auto countIter = methodCountMap.begin(); countIter != methodCountMap.end(); countIter++) { + for (auto countIter = methodCountMap->begin(); countIter != methodCountMap->end(); countIter++) { auto methodId = countIter->first; - auto result = globalMethodCountMap.find(methodId); - if (result != globalMethodCountMap.end()) { + auto &localInfo = countIter->second; + auto result = globalMethodCountMap->find(methodId); + if (result != globalMethodCountMap->end()) { auto &info = result->second; - info->AddCount(countIter->second->GetCount()); - delete countIter->second; + info->AddCount(localInfo->GetCount()); } else { - globalMethodCountMap.emplace(methodId, countIter->second); + auto info = chunk_->New(localInfo->GetCount(), localInfo->GetMethodName()); + globalMethodCountMap->emplace(methodId, info); } + localInfo->ClearCount(); } } - profiler->profilerMap_.clear(); } -void PGOProfilerManager::SaveProfiler() +void PGOProfilerManager::SaveProfiler(SaveTask *task) { std::string realOutPath; if (!base::FilePathHelper::RealPath(outDir_, realOutPath, false)) { @@ -114,48 +154,79 @@ void PGOProfilerManager::SaveProfiler() realOutPath += PROFILE_FILE_NAME; LOG_ECMA(INFO) << "Save profiler to file:" << realOutPath; - std::ofstream file(realOutPath.c_str()); - if (!file.is_open()) { + std::ofstream fileStream(realOutPath.c_str()); + if (!fileStream.is_open()) { LOG_ECMA(ERROR) << "The file path(" << realOutPath << ") open failure!"; return; } - std::string profilerString = ProcessProfile(); - file.write(profilerString.c_str(), profilerString.size()); - file.close(); + ProcessProfile(fileStream, task); + fileStream.close(); } -std::string PGOProfilerManager::ProcessProfile() +void PGOProfilerManager::ProcessProfile(std::ofstream &fileStream, SaveTask *task) { - std::stringstream profilerStream; - for (auto iter = globalProfilerMap_.begin(); iter != globalProfilerMap_.end(); iter++) { + std::string profilerString; + for (auto iter = globalProfilerMap_->begin(); iter != globalProfilerMap_->end(); iter++) { auto methodCountMap = iter->second; bool isFirst = true; - for (auto countIter = methodCountMap.begin(); countIter != methodCountMap.end(); countIter++) { - LOG_ECMA(DEBUG) << "Method id:" << countIter->first << "(" << countIter->second->GetCount() << ")"; + for (auto countIter = methodCountMap->begin(); countIter != methodCountMap->end(); countIter++) { + LOG_ECMA(DEBUG) << "Method:" << countIter->first << "/" << countIter->second->GetMethodName() + << "(" << countIter->second->GetCount() << ")"; + if (task && task->IsTerminate()) { + LOG_ECMA(INFO) << "ProcessProfile: task is already terminate"; + return; + } if (countIter->second->GetCount() < hotnessThreshold_) { continue; } if (!isFirst) { - profilerStream << ","; + profilerString += ","; } else { auto recordName = iter->first; - profilerStream << recordName; - profilerStream << ":["; + profilerString += recordName; + profilerString += ":["; isFirst = false; } - profilerStream << countIter->first.GetOffset(); - profilerStream << "/"; - profilerStream << countIter->second->GetCount(); - profilerStream << "/"; - profilerStream << countIter->second->GetMethodName(); - delete countIter->second; + profilerString += std::to_string(countIter->first.GetOffset()); + profilerString += "/"; + profilerString += std::to_string(countIter->second->GetCount()); + profilerString += "/"; + profilerString += countIter->second->GetMethodName(); } if (!isFirst) { - profilerStream << "]\n"; + profilerString += "]\n"; + fileStream.write(profilerString.c_str(), profilerString.size()); + profilerString.clear(); } } - globalProfilerMap_.clear(); +} - return profilerStream.str(); +void PGOProfilerManager::TerminateSaveTask() +{ + if (!isEnable_) { + return; + } + Taskpool::GetCurrentTaskpool()->TerminateTask(GLOBAL_TASK_ID, TaskType::PGO_SAVE_TASK); +} + +void PGOProfilerManager::PostSaveTask() +{ + if (!isEnable_) { + return; + } + Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(GLOBAL_TASK_ID)); +} + +void PGOProfilerManager::StartSaveTask(SaveTask *task) +{ + if (task == nullptr) { + return; + } + if (task->IsTerminate()) { + LOG_ECMA(ERROR) << "StartSaveTask: task is already terminate"; + return; + } + os::memory::LockHolder lock(mutex_); + SaveProfiler(task); } } // namespace panda::ecmascript diff --git a/ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h b/ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h index a5e1263d6b..a70e475e74 100644 --- a/ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h +++ b/ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h @@ -16,10 +16,14 @@ #ifndef ECMASCRIPT_DFX_PGO_PROFILER_MANAGER_H #define ECMASCRIPT_DFX_PGO_PROFILER_MANAGER_H -#include +#include +#include #include "ecmascript/ecma_macros.h" -#include "ecmascript/jspandafile/method_literal.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/mem/chunk_containers.h" +#include "ecmascript/mem/native_area_allocator.h" +#include "ecmascript/taskpool/task.h" namespace panda::ecmascript { /* @@ -39,6 +43,11 @@ public: count_++; } + void ClearCount() + { + count_ = 0; + } + void AddCount(uint32_t count) { count_ += count; @@ -68,11 +77,15 @@ public: void Sample(JSTaggedType value); private: - PGOProfiler(bool isEnable) : isEnable_(isEnable) {}; - virtual ~PGOProfiler() = default; + PGOProfiler(EcmaVM *vm, bool isEnable) + : isEnable_(isEnable), chunk_(vm->GetNativeAreaAllocator()), profilerMap_(&chunk_) {}; + virtual ~PGOProfiler(); + static constexpr uint32_t MERGED_EVERY_COUNT = 10; bool isEnable_ {false}; - std::unordered_map> profilerMap_; + Chunk chunk_; + ChunkUnorderedMap *> profilerMap_; + uint32_t methodCount_ {0}; friend class PGOProfilerManager; }; @@ -85,26 +98,23 @@ public: } PGOProfilerManager() = default; + ~PGOProfilerManager() = default; NO_COPY_SEMANTIC(PGOProfilerManager); NO_MOVE_SEMANTIC(PGOProfilerManager); void Initialize(uint32_t hotnessThreshold, const std::string &outDir); + void InitializeData(); - void Destroy() - { - if (!isEnable_) { - return; - } - SaveProfiler(); - } + void Destroy(); - PGOProfiler *Build(bool isEnable) + // Factory + PGOProfiler *Build(EcmaVM *vm, bool isEnable) { if (isEnable) { - isEnable_ = true; + InitializeData(); } - return new PGOProfiler(isEnable); + return new PGOProfiler(vm, isEnable); } void Destroy(PGOProfiler *profiler) @@ -115,16 +125,42 @@ public: } } -private: void Merge(PGOProfiler *profile); - void SaveProfiler(); - std::string ProcessProfile(); + void TerminateSaveTask(); + void PostSaveTask(); + +private: + class SaveTask : public Task { + public: + SaveTask(int32_t id) : Task(id) {}; + virtual ~SaveTask() = default; + + bool Run([[maybe_unused]] uint32_t threadIndex) override + { + PGOProfilerManager::GetInstance()->StartSaveTask(this); + return true; + } + + TaskType GetTaskType() override + { + return TaskType::PGO_SAVE_TASK; + } + + NO_COPY_SEMANTIC(SaveTask); + NO_MOVE_SEMANTIC(SaveTask); + }; + + void StartSaveTask(SaveTask *task); + void SaveProfiler(SaveTask *task = nullptr); + void ProcessProfile(std::ofstream &fileStream, SaveTask *task); - os::memory::Mutex mutex_; bool isEnable_ {false}; uint32_t hotnessThreshold_ {2}; std::string outDir_; - std::unordered_map> globalProfilerMap_; + std::unique_ptr nativeAreaAllocator_; + std::unique_ptr chunk_; + ChunkUnorderedMap *> *globalProfilerMap_; + os::memory::Mutex mutex_; }; } // namespace panda::ecmascript diff --git a/ecmascript/dfx/pgo_profiler/tests/pgo_profiler_test.cpp b/ecmascript/dfx/pgo_profiler/tests/pgo_profiler_test.cpp index 2236fe2561..e7eb680b25 100644 --- a/ecmascript/dfx/pgo_profiler/tests/pgo_profiler_test.cpp +++ b/ecmascript/dfx/pgo_profiler/tests/pgo_profiler_test.cpp @@ -16,6 +16,7 @@ #include "gtest/gtest.h" #include "ecmascript/dfx/pgo_profiler/pgo_profiler_loader.h" +#include "ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/jspandafile/method_literal.h" #include "ecmascript/js_thread.h" @@ -62,7 +63,11 @@ HWTEST_F_L0(PGOProfilerTest, Sample) PGOProfilerLoader loader; loader.LoadProfiler("ark-profiler/profiler.aprof", 2); CString expectRecordName = "test"; +#if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(10))); +#else + ASSERT_TRUE(loader.Match(expectRecordName, EntityId(10))); +#endif unlink("ark-profiler/profiler.aprof"); rmdir("ark-profiler/"); } @@ -102,14 +107,13 @@ HWTEST_F_L0(PGOProfilerTest, Sample1) PGOProfilerLoader loader; loader.LoadProfiler("ark-profiler1/profiler.aprof", 2); CString expectRecordName = "test"; -#if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(loader.Match(expectRecordName, EntityId(10))); ASSERT_TRUE(loader.Match(expectRecordName, EntityId(20))); -#else - ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(10))); - ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(20))); -#endif +#if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(15))); +#else + ASSERT_TRUE(loader.Match(expectRecordName, EntityId(15))); +#endif unlink("ark-profiler1/profiler.aprof"); rmdir("ark-profiler1/"); } @@ -144,12 +148,12 @@ HWTEST_F_L0(PGOProfilerTest, Sample2) loader.LoadProfiler("ark-profiler2/profiler.aprof", 2); CString expectRecordName = "test"; CString expectRecordName1 = "test1"; - ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(10))); #if defined(SUPPORT_ENABLE_ASM_INTERP) - ASSERT_TRUE(loader.Match(expectRecordName1, EntityId(15))); + ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(10))); #else - ASSERT_TRUE(!loader.Match(expectRecordName1, EntityId(15))); + ASSERT_TRUE(loader.Match(expectRecordName, EntityId(10))); #endif + ASSERT_TRUE(loader.Match(expectRecordName1, EntityId(15))); unlink("ark-profiler2/profiler.aprof"); rmdir("ark-profiler2/"); } @@ -277,7 +281,11 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerDoubleVM) ASSERT_TRUE(loader.Match(expectRecordName, EntityId(15))); loader.LoadProfiler("ark-profiler5/profiler.aprof", 2); +#if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(15))); +#else + ASSERT_TRUE(loader.Match(expectRecordName, EntityId(15))); +#endif unlink("ark-profiler5/profiler.aprof"); rmdir("ark-profiler5/profiler"); @@ -346,9 +354,59 @@ HWTEST_F_L0(PGOProfilerTest, PGOProfilerLoaderNoHotMethod) PGOProfilerLoader loader; loader.LoadProfiler("ark-profiler8/profiler.aprof", 2); CString expectRecordName = "test"; +#if defined(SUPPORT_ENABLE_ASM_INTERP) ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(10))); +#else + ASSERT_TRUE(loader.Match(expectRecordName, EntityId(10))); +#endif unlink("ark-profiler8/profiler.aprof"); rmdir("ark-profiler8/"); } + +HWTEST_F_L0(PGOProfilerTest, PGOProfilerPostTask) +{ + mkdir("ark-profiler9/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + RuntimeOption option; + option.SetEnableProfile(true); + option.SetProfileDir("ark-profiler9/"); + vm_ = JSNApi::CreateJSVM(option); + + for (int i = 0; i < 5; i++) { + PGOProfilerManager::GetInstance()->PostSaveTask(); + PGOProfilerManager::GetInstance()->TerminateSaveTask(); + } + + JSHandle recordName(vm_->GetFactory()->NewFromStdString("test")); + for (int i = 0; i < 31; i++) { + MethodLiteral *methodLiteral = new MethodLiteral(nullptr, EntityId(i)); + JSHandle method = vm_->GetFactory()->NewMethod(methodLiteral); + JSHandle func = vm_->GetFactory()->NewJSFunction(vm_->GetGlobalEnv(), method); + func->SetModule(vm_->GetJSThread(), recordName); + vm_->GetPGOProfiler()->Sample(func.GetTaggedType()); + if (i % 3 == 0) { + vm_->GetPGOProfiler()->Sample(func.GetTaggedType()); + } + } + + JSNApi::DestroyJSVM(vm_); + + PGOProfilerLoader loader; + loader.LoadProfiler("ark-profiler9/profiler.aprof", 2); + CString expectRecordName = "test"; + for (int i = 0; i < 31; i++) { + if (i % 3 == 0) { + ASSERT_TRUE(loader.Match(expectRecordName, EntityId(i))); + } else { +#if defined(SUPPORT_ENABLE_ASM_INTERP) + ASSERT_TRUE(!loader.Match(expectRecordName, EntityId(i))); +#else + ASSERT_TRUE(loader.Match(expectRecordName, EntityId(i))); +#endif + } + } + + unlink("ark-profiler9/profiler.aprof"); + rmdir("ark-profiler9/"); +} } // namespace panda::test diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index bdb9f6b381..a45f83e963 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -154,7 +154,7 @@ bool EcmaVM::Initialize() { ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "EcmaVM::Initialize"); bool isEnablePGOProfiler = options_.GetEnableAsmInterpreter() && options_.IsEnablePGOProfiler(); - pgoProfiler_ = PGOProfilerManager::GetInstance()->Build(isEnablePGOProfiler); + pgoProfiler_ = PGOProfilerManager::GetInstance()->Build(this, isEnablePGOProfiler); thread_->SetPGOProfilerEnable(isEnablePGOProfiler); Taskpool::GetCurrentTaskpool()->Initialize(); #ifndef PANDA_TARGET_WINDOWS @@ -280,7 +280,7 @@ EcmaVM::~EcmaVM() { initialized_ = false; heap_->WaitAllTasksFinished(); - Taskpool::GetCurrentTaskpool()->Destroy(); + Taskpool::GetCurrentTaskpool()->Destroy(thread_->GetThreadId()); if (runtimeStat_ != nullptr && runtimeStat_->IsRuntimeStatEnabled()) { runtimeStat_->Print(); diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index 8cc0ee4b51..adeae444e1 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -17,7 +17,6 @@ #define ECMASCRIPT_ECMA_VM_H #include "ecmascript/base/config.h" -#include "ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_runtime_options.h" #include "ecmascript/js_thread.h" @@ -53,6 +52,7 @@ class EcmaStringTable; class SnapshotEnv; class SnapshotSerialize; class SnapshotProcessor; +class PGOProfiler; #if !WIN_OR_MAC_OR_IOS_PLATFORM class HeapProfilerInterface; #endif diff --git a/ecmascript/mem/concurrent_marker.cpp b/ecmascript/mem/concurrent_marker.cpp index 9dec0ef173..7c7b16bef0 100644 --- a/ecmascript/mem/concurrent_marker.cpp +++ b/ecmascript/mem/concurrent_marker.cpp @@ -64,7 +64,7 @@ void ConcurrentMarker::Mark() MEM_ALLOCATE_AND_GC_TRACE(vm_, ConcurrentMarking); ClockScope scope; InitializeMarking(); - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(heap_)); + Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(heap_->GetJSThread()->GetThreadId(), heap_)); if (!heap_->IsFullMark() && heap_->IsParallelGCEnabled()) { heap_->PostParallelGCTask(ParallelGCTaskPhase::CONCURRENT_HANDLE_OLD_TO_NEW_TASK); } diff --git a/ecmascript/mem/concurrent_marker.h b/ecmascript/mem/concurrent_marker.h index c96dfd52e9..b024635c35 100644 --- a/ecmascript/mem/concurrent_marker.h +++ b/ecmascript/mem/concurrent_marker.h @@ -120,7 +120,7 @@ private: class MarkerTask : public Task { public: - explicit MarkerTask(Heap *heap) : heap_(heap) {} + explicit MarkerTask(int32_t id, Heap *heap) : Task(id), heap_(heap) {} ~MarkerTask() override = default; bool Run(uint32_t threadId) override; diff --git a/ecmascript/mem/concurrent_sweeper.cpp b/ecmascript/mem/concurrent_sweeper.cpp index ff7c73ee02..edf691cf03 100644 --- a/ecmascript/mem/concurrent_sweeper.cpp +++ b/ecmascript/mem/concurrent_sweeper.cpp @@ -46,10 +46,13 @@ void ConcurrentSweeper::Sweep(bool fullGC) remainingTaskNum_[type] = FREE_LIST_NUM - startSpaceType_; } if (!fullGC) { - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(this, OLD_SPACE)); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(heap_->GetJSThread()->GetThreadId(), this, OLD_SPACE)); } - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(this, NON_MOVABLE)); - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(this, MACHINE_CODE_SPACE)); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(heap_->GetJSThread()->GetThreadId(), this, NON_MOVABLE)); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(heap_->GetJSThread()->GetThreadId(), this, MACHINE_CODE_SPACE)); } else { if (!fullGC) { heap_->GetOldSpace()->Sweep(); diff --git a/ecmascript/mem/concurrent_sweeper.h b/ecmascript/mem/concurrent_sweeper.h index 02ca3db756..5a7d19af0d 100644 --- a/ecmascript/mem/concurrent_sweeper.h +++ b/ecmascript/mem/concurrent_sweeper.h @@ -77,7 +77,7 @@ public: return enableType_ == EnableConcurrentSweepType::DISABLE || enableType_ == EnableConcurrentSweepType::CONFIG_DISABLE; } - + bool IsRequestDisabled() const { return enableType_ == EnableConcurrentSweepType::REQUEST_DISABLE; @@ -90,7 +90,8 @@ public: private: class SweeperTask : public Task { public: - SweeperTask(ConcurrentSweeper *sweeper, MemSpaceType type) : sweeper_(sweeper), type_(type) {}; + SweeperTask(int32_t id, ConcurrentSweeper *sweeper, MemSpaceType type) + : Task(id), sweeper_(sweeper), type_(type) {}; ~SweeperTask() override = default; bool Run(uint32_t threadIndex) override; diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index 24e6081bfb..0e0d986351 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -266,7 +266,8 @@ void Heap::Resume(TriggerGCType gcType) hugeObjectSpace_->ReclaimHugeRegion(); if (parallelGC_) { clearTaskFinished_ = false; - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(this, gcType)); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(GetJSThread()->GetThreadId(), this, gcType)); } else { ReclaimRegions(gcType); } @@ -300,7 +301,7 @@ void Heap::DisableParallelGC() stwYoungGC_->ConfigParallelGC(false); sweeper_->ConfigConcurrentSweep(false); concurrentMarker_->ConfigConcurrentMark(false); - Taskpool::GetCurrentTaskpool()->Destroy(); + Taskpool::GetCurrentTaskpool()->Destroy(GetJSThread()->GetThreadId()); } void Heap::EnableParallelGC() @@ -810,7 +811,8 @@ void Heap::WaitConcurrentMarkingFinished() void Heap::PostParallelGCTask(ParallelGCTaskPhase gcTask) { IncreaseTaskCount(); - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(this, gcTask)); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(GetJSThread()->GetThreadId(), this, gcTask)); } void Heap::IncreaseTaskCount() diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h index 8df115bce3..f3096f0983 100644 --- a/ecmascript/mem/heap.h +++ b/ecmascript/mem/heap.h @@ -455,7 +455,8 @@ private: class ParallelGCTask : public Task { public: - ParallelGCTask(Heap *heap, ParallelGCTaskPhase taskPhase) : heap_(heap), taskPhase_(taskPhase) {}; + ParallelGCTask(int32_t id, Heap *heap, ParallelGCTaskPhase taskPhase) + : Task(id), heap_(heap), taskPhase_(taskPhase) {}; ~ParallelGCTask() override = default; bool Run(uint32_t threadIndex) override; @@ -469,7 +470,8 @@ private: class AsyncClearTask : public Task { public: - AsyncClearTask(Heap *heap, TriggerGCType type) : heap_(heap), gcType_(type) {} + AsyncClearTask(int32_t id, Heap *heap, TriggerGCType type) + : Task(id), heap_(heap), gcType_(type) {} ~AsyncClearTask() override = default; bool Run(uint32_t threadIndex) override; diff --git a/ecmascript/mem/parallel_evacuator.cpp b/ecmascript/mem/parallel_evacuator.cpp index 83fc5f3010..16e11b8611 100644 --- a/ecmascript/mem/parallel_evacuator.cpp +++ b/ecmascript/mem/parallel_evacuator.cpp @@ -69,7 +69,8 @@ void ParallelEvacuator::EvacuateSpace() os::memory::LockHolder holder(mutex_); parallel_ = CalculateEvacuationThreadNum(); for (int i = 0; i < parallel_; i++) { - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(this)); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(heap_->GetJSThread()->GetThreadId(), this)); } } @@ -205,7 +206,8 @@ void ParallelEvacuator::UpdateReference() os::memory::LockHolder holder(mutex_); parallel_ = CalculateUpdateThreadNum(); for (int i = 0; i < parallel_; i++) { - Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique(this)); + Taskpool::GetCurrentTaskpool()->PostTask( + std::make_unique(heap_->GetJSThread()->GetThreadId(), this)); } } @@ -408,8 +410,8 @@ bool ParallelEvacuator::ProcessWorkloads(bool isMain) return true; } -ParallelEvacuator::EvacuationTask::EvacuationTask(ParallelEvacuator *evacuator) - : evacuator_(evacuator) +ParallelEvacuator::EvacuationTask::EvacuationTask(int32_t id, ParallelEvacuator *evacuator) + : Task(id), evacuator_(evacuator) { allocator_ = new TlabAllocator(evacuator->heap_); } diff --git a/ecmascript/mem/parallel_evacuator.h b/ecmascript/mem/parallel_evacuator.h index 3e799ebf68..8cdd004cb1 100644 --- a/ecmascript/mem/parallel_evacuator.h +++ b/ecmascript/mem/parallel_evacuator.h @@ -47,7 +47,7 @@ public: private: class EvacuationTask : public Task { public: - explicit EvacuationTask(ParallelEvacuator *evacuator); + explicit EvacuationTask(int32_t id, ParallelEvacuator *evacuator); ~EvacuationTask() override; bool Run(uint32_t threadIndex) override; @@ -61,7 +61,7 @@ private: class UpdateReferenceTask : public Task { public: - explicit UpdateReferenceTask(ParallelEvacuator *evacuator) : evacuator_(evacuator) {}; + explicit UpdateReferenceTask(int32_t id, ParallelEvacuator *evacuator) : Task(id), evacuator_(evacuator) {}; ~UpdateReferenceTask() override = default; bool Run(uint32_t threadIndex) override; diff --git a/ecmascript/taskpool/runner.cpp b/ecmascript/taskpool/runner.cpp index d0d9fc5a78..b55c1a1edc 100644 --- a/ecmascript/taskpool/runner.cpp +++ b/ecmascript/taskpool/runner.cpp @@ -32,11 +32,18 @@ Runner::Runner(uint32_t threadNum) : totalThreadNum_(threadNum) } } -void Runner::TerminateTask() +void Runner::TerminateTask(int32_t id, TaskType type) { + taskQueue_.TerminateTask(id, type); os::memory::LockHolder holder(mtx_); for (uint32_t i = 0; i < runningTask_.size(); i++) { if (runningTask_[i] != nullptr) { + if (id != ALL_TASK_ID && id != runningTask_[i]->GetId()) { + continue; + } + if (type != TaskType::ALL && type != runningTask_[i]->GetTaskType()) { + continue; + } runningTask_[i]->Terminated(); } } @@ -44,8 +51,8 @@ void Runner::TerminateTask() void Runner::TerminateThread() { + TerminateTask(ALL_TASK_ID, TaskType::ALL); taskQueue_.Terminate(); - TerminateTask(); uint32_t threadNum = threadPool_.size(); for (uint32_t i = 0; i < threadNum; i++) { diff --git a/ecmascript/taskpool/runner.h b/ecmascript/taskpool/runner.h index 191281b253..8f67d9e528 100644 --- a/ecmascript/taskpool/runner.h +++ b/ecmascript/taskpool/runner.h @@ -44,7 +44,7 @@ public: } void PUBLIC_API TerminateThread(); - void TerminateTask(); + void TerminateTask(int32_t id, TaskType type); uint32_t GetTotalThreadNum() const { diff --git a/ecmascript/taskpool/task.h b/ecmascript/taskpool/task.h index beaed57bce..35a246fad8 100644 --- a/ecmascript/taskpool/task.h +++ b/ecmascript/taskpool/task.h @@ -19,15 +19,34 @@ #include "libpandabase/macros.h" namespace panda::ecmascript { +enum class TaskType : uint8_t { + PGO_SAVE_TASK, + ALL, +}; + +static constexpr int32_t ALL_TASK_ID = -1; +// Tasks not managed by VM +static constexpr int32_t GLOBAL_TASK_ID = 0; + class Task { public: - Task() = default; + Task(int32_t id) : id_(id) {}; virtual ~Task() = default; virtual bool Run(uint32_t threadIndex) = 0; NO_COPY_SEMANTIC(Task); NO_MOVE_SEMANTIC(Task); + virtual TaskType GetTaskType() + { + return TaskType::ALL; + } + + int32_t GetId() + { + return id_; + } + void Terminated() { terminate_ = true; @@ -39,6 +58,7 @@ public: } private: + int32_t id_ {0}; volatile bool terminate_ {false}; }; } // namespace panda::ecmascript diff --git a/ecmascript/taskpool/task_queue.cpp b/ecmascript/taskpool/task_queue.cpp index 043b38bd1b..4c186650d8 100644 --- a/ecmascript/taskpool/task_queue.cpp +++ b/ecmascript/taskpool/task_queue.cpp @@ -20,7 +20,7 @@ void TaskQueue::PostTask(std::unique_ptr task) { os::memory::LockHolder holder(mtx_); ASSERT(!terminate_); - tasks_.push(std::move(task)); + tasks_.push_back(std::move(task)); cv_.Signal(); } @@ -30,7 +30,7 @@ std::unique_ptr TaskQueue::PopTask() while (true) { if (!tasks_.empty()) { std::unique_ptr task = std::move(tasks_.front()); - tasks_.pop(); + tasks_.pop_front(); return task; } if (terminate_) { @@ -41,6 +41,21 @@ std::unique_ptr TaskQueue::PopTask() } } +void TaskQueue::TerminateTask(int32_t id, TaskType type) +{ + os::memory::LockHolder holder(mtx_); + for (auto iter = tasks_.begin(); iter != tasks_.end(); iter++) { + if (id != ALL_TASK_ID && id != (*iter)->GetId()) { + continue; + } + if (type != TaskType::ALL && type != (*iter)->GetTaskType()) { + iter++; + continue; + } + (*iter)->Terminated(); + } +} + void TaskQueue::Terminate() { os::memory::LockHolder holder(mtx_); diff --git a/ecmascript/taskpool/task_queue.h b/ecmascript/taskpool/task_queue.h index 42f96ba087..cabd5d3044 100644 --- a/ecmascript/taskpool/task_queue.h +++ b/ecmascript/taskpool/task_queue.h @@ -18,8 +18,8 @@ #include #include +#include #include -#include #include "ecmascript/taskpool/task.h" #include "os/mutex.h" @@ -37,9 +37,10 @@ public: std::unique_ptr PopTask(); void Terminate(); + void TerminateTask(int32_t id, TaskType type); private: - std::queue> tasks_; + std::deque> tasks_; std::atomic_bool terminate_ = false; os::memory::Mutex mtx_; diff --git a/ecmascript/taskpool/taskpool.cpp b/ecmascript/taskpool/taskpool.cpp index cfc38882ff..abc92f5605 100644 --- a/ecmascript/taskpool/taskpool.cpp +++ b/ecmascript/taskpool/taskpool.cpp @@ -38,7 +38,7 @@ void Taskpool::Initialize(int threadNum) } } -void Taskpool::Destroy() +void Taskpool::Destroy(int32_t id) { os::memory::LockHolder lock(mutex_); if (isInitialized_ <= 0) { @@ -48,10 +48,21 @@ void Taskpool::Destroy() if (isInitialized_ == 0) { runner_->TerminateThread(); } else { - runner_->TerminateTask(); + runner_->TerminateTask(id, TaskType::ALL); } } +void Taskpool::TerminateTask(int32_t id, TaskType type) +{ + { + os::memory::LockHolder lock(mutex_); + if (isInitialized_ <= 0) { + return; + } + } + runner_->TerminateTask(id, type); +} + uint32_t Taskpool::TheMostSuitableThreadNum(uint32_t threadNum) const { if (threadNum > 0) { diff --git a/ecmascript/taskpool/taskpool.h b/ecmascript/taskpool/taskpool.h index d5a8fdc01d..52f4703016 100644 --- a/ecmascript/taskpool/taskpool.h +++ b/ecmascript/taskpool/taskpool.h @@ -42,7 +42,7 @@ public: NO_MOVE_SEMANTIC(Taskpool); void Initialize(int threadNum = DEFAULT_TASKPOOL_THREAD_NUM); - void Destroy(); + void Destroy(int32_t id); void PostTask(std::unique_ptr task) const { @@ -50,6 +50,9 @@ public: runner_->PostTask(std::move(task)); } + // Terminate a task of a specified type + void TerminateTask(int32_t id, TaskType type = TaskType::ALL); + uint32_t GetTotalThreadNum() const { return runner_->GetTotalThreadNum();