perf(PGO Profiler): optimizer PGO Profiler

1、Modify occasion of saveing profiler data
    2、Change allocation from new to chunk

Closes #I61UVO

Change-Id: I1aae4a5c3f8117dae78921f654140f20f1bbe9f5
Signed-off-by: yingguofeng@huawei.com <yingguofeng@huawei.com>
This commit is contained in:
yingguofeng@huawei.com 2022-11-18 11:58:51 +08:00
parent 2dc5a68cf3
commit c9d4e14744
23 changed files with 349 additions and 117 deletions

View File

@ -76,7 +76,7 @@ void CpuProfiler::StartCpuProfilerForInfo()
vm_->GetJSThread()->SetCallNapiGetStack(true);
generator_->SetIsStart(true);
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<SamplingProcessor>(generator_, interval_));
std::make_unique<SamplingProcessor>(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<SamplingProcessor>(generator_, interval_));
std::make_unique<SamplingProcessor>(vm_->GetJSThread()->GetThreadId(), generator_, interval_));
}
std::unique_ptr<struct ProfileInfo> 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))) {

View File

@ -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;

View File

@ -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
#endif // ECMASCRIPT_SAMPLING_PROCESSOR_H

View File

@ -15,7 +15,7 @@
#include "ecmascript/dfx/pgo_profiler/pgo_profiler_manager.h"
#include <sstream>
#include <string>
#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<MethodProfilerInfo>(1, jsMethod->ParseFunctionName());
methodCountMap->emplace(jsMethod->GetMethodId(), info);
methodCount_++;
}
} else {
std::unordered_map<EntityId, MethodProfilerInfo *> methodsCountMap;
auto info = new MethodProfilerInfo(1, jsMethod->ParseFunctionName());
methodsCountMap.emplace(jsMethod->GetMethodId(), info);
ChunkUnorderedMap<EntityId, MethodProfilerInfo *> *methodsCountMap =
chunk_.New<ChunkUnorderedMap<EntityId, MethodProfilerInfo *>>(&chunk_);
auto info = chunk_.New<MethodProfilerInfo>(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<NativeAreaAllocator>();
chunk_ = std::make_unique<Chunk>(nativeAreaAllocator_.get());
globalProfilerMap_ = chunk_->
New<ChunkUnorderedMap<CString, ChunkUnorderedMap<EntityId, MethodProfilerInfo *> *>>(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<EntityId, MethodProfilerInfo *> *globalMethodCountMap = nullptr;
if (globalMethodCountIter == globalProfilerMap_->end()) {
globalMethodCountMap = chunk_->New<ChunkUnorderedMap<EntityId, MethodProfilerInfo *>>(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<MethodProfilerInfo>(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<SaveTask>(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

View File

@ -16,10 +16,14 @@
#ifndef ECMASCRIPT_DFX_PGO_PROFILER_MANAGER_H
#define ECMASCRIPT_DFX_PGO_PROFILER_MANAGER_H
#include <unordered_map>
#include <algorithm>
#include <memory>
#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<CString, std::unordered_map<EntityId, MethodProfilerInfo *>> profilerMap_;
Chunk chunk_;
ChunkUnorderedMap<CString, ChunkUnorderedMap<EntityId, MethodProfilerInfo *> *> 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<CString, std::unordered_map<EntityId, MethodProfilerInfo *>> globalProfilerMap_;
std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_;
std::unique_ptr<Chunk> chunk_;
ChunkUnorderedMap<CString, ChunkUnorderedMap<EntityId, MethodProfilerInfo *> *> *globalProfilerMap_;
os::memory::Mutex mutex_;
};
} // namespace panda::ecmascript

View File

@ -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<JSTaggedValue> recordName(vm_->GetFactory()->NewFromStdString("test"));
for (int i = 0; i < 31; i++) {
MethodLiteral *methodLiteral = new MethodLiteral(nullptr, EntityId(i));
JSHandle<Method> method = vm_->GetFactory()->NewMethod(methodLiteral);
JSHandle<JSFunction> 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

View File

@ -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();

View File

@ -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

View File

@ -64,7 +64,7 @@ void ConcurrentMarker::Mark()
MEM_ALLOCATE_AND_GC_TRACE(vm_, ConcurrentMarking);
ClockScope scope;
InitializeMarking();
Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<MarkerTask>(heap_));
Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<MarkerTask>(heap_->GetJSThread()->GetThreadId(), heap_));
if (!heap_->IsFullMark() && heap_->IsParallelGCEnabled()) {
heap_->PostParallelGCTask(ParallelGCTaskPhase::CONCURRENT_HANDLE_OLD_TO_NEW_TASK);
}

View File

@ -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;

View File

@ -46,10 +46,13 @@ void ConcurrentSweeper::Sweep(bool fullGC)
remainingTaskNum_[type] = FREE_LIST_NUM - startSpaceType_;
}
if (!fullGC) {
Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<SweeperTask>(this, OLD_SPACE));
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<SweeperTask>(heap_->GetJSThread()->GetThreadId(), this, OLD_SPACE));
}
Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<SweeperTask>(this, NON_MOVABLE));
Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<SweeperTask>(this, MACHINE_CODE_SPACE));
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<SweeperTask>(heap_->GetJSThread()->GetThreadId(), this, NON_MOVABLE));
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<SweeperTask>(heap_->GetJSThread()->GetThreadId(), this, MACHINE_CODE_SPACE));
} else {
if (!fullGC) {
heap_->GetOldSpace()->Sweep();

View File

@ -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;

View File

@ -266,7 +266,8 @@ void Heap::Resume(TriggerGCType gcType)
hugeObjectSpace_->ReclaimHugeRegion();
if (parallelGC_) {
clearTaskFinished_ = false;
Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<AsyncClearTask>(this, gcType));
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<AsyncClearTask>(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<ParallelGCTask>(this, gcTask));
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<ParallelGCTask>(GetJSThread()->GetThreadId(), this, gcTask));
}
void Heap::IncreaseTaskCount()

View File

@ -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;

View File

@ -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<EvacuationTask>(this));
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<EvacuationTask>(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<UpdateReferenceTask>(this));
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<UpdateReferenceTask>(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_);
}

View File

@ -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;

View File

@ -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++) {

View File

@ -44,7 +44,7 @@ public:
}
void PUBLIC_API TerminateThread();
void TerminateTask();
void TerminateTask(int32_t id, TaskType type);
uint32_t GetTotalThreadNum() const
{

View File

@ -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

View File

@ -20,7 +20,7 @@ void TaskQueue::PostTask(std::unique_ptr<Task> 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<Task> TaskQueue::PopTask()
while (true) {
if (!tasks_.empty()) {
std::unique_ptr<Task> task = std::move(tasks_.front());
tasks_.pop();
tasks_.pop_front();
return task;
}
if (terminate_) {
@ -41,6 +41,21 @@ std::unique_ptr<Task> 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_);

View File

@ -18,8 +18,8 @@
#include <algorithm>
#include <atomic>
#include <deque>
#include <memory>
#include <queue>
#include "ecmascript/taskpool/task.h"
#include "os/mutex.h"
@ -37,9 +37,10 @@ public:
std::unique_ptr<Task> PopTask();
void Terminate();
void TerminateTask(int32_t id, TaskType type);
private:
std::queue<std::unique_ptr<Task>> tasks_;
std::deque<std::unique_ptr<Task>> tasks_;
std::atomic_bool terminate_ = false;
os::memory::Mutex mtx_;

View File

@ -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) {

View File

@ -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> 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();