!6736 Add shared gc trigger

Merge pull request !6736 from dingwen/shared_gc
This commit is contained in:
openharmony_ci 2024-04-02 20:34:13 +00:00 committed by Gitee
commit eaa9bbd6ea
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
14 changed files with 133 additions and 22 deletions

View File

@ -48,6 +48,7 @@ enum class GCReason : uint8_t {
IDLE,
SWITCH_BACKGROUND,
EXTERNAL_TRIGGER,
WORKER_DESTRUCTION,
OTHER,
};

View File

@ -67,6 +67,7 @@ public:
defaultNonMovableSpaceSize_ = 2_MB;
defaultSnapshotSpaceSize_ = 512_KB;
defaultMachineCodeSpaceSize_ = 2_MB;
defaultGlobalAllocLimit_ = 20_MB;
semiSpaceTriggerConcurrentMark_ = 1_MB;
semiSpaceStepOvershootSize_ = 2_MB;
oldSpaceOvershootSize_ = 4_MB;
@ -75,6 +76,8 @@ public:
minGrowingStep_ = 4_MB;
maxStackSize_ = 128_KB;
maxJSSerializerSize_ = 8_MB;
sharedHeapLimitGrowingFactor_ = 2; // 2: growing factor
sharedHeapLimitGrowingStep_ = 20_MB;
} else if (maxHeapSize_ < HIGH_MEMORY) { // 128_MB ~ 256_MB
minSemiSpaceSize_ = 2_MB;
maxSemiSpaceSize_ = 8_MB;
@ -82,6 +85,7 @@ public:
defaultNonMovableSpaceSize_ = 6_MB;
defaultSnapshotSpaceSize_ = 512_KB;
defaultMachineCodeSpaceSize_ = 2_MB;
defaultGlobalAllocLimit_ = 20_MB;
semiSpaceTriggerConcurrentMark_ = 1.5_MB;
semiSpaceStepOvershootSize_ = 2_MB;
oldSpaceOvershootSize_ = 8_MB;
@ -90,6 +94,8 @@ public:
minGrowingStep_ = 8_MB;
maxStackSize_ = 128_KB;
maxJSSerializerSize_ = 16_MB;
sharedHeapLimitGrowingFactor_ = 2; // 2: growing factor
sharedHeapLimitGrowingStep_ = 40_MB;
} else { // 256_MB ~ 384_MB
minSemiSpaceSize_ = 2_MB;
maxSemiSpaceSize_ = 16_MB;
@ -97,6 +103,7 @@ public:
defaultNonMovableSpaceSize_ = 64_MB;
defaultSnapshotSpaceSize_ = 4_MB;
defaultMachineCodeSpaceSize_ = 8_MB;
defaultGlobalAllocLimit_ = 20_MB;
semiSpaceTriggerConcurrentMark_ = 1.5_MB;
semiSpaceStepOvershootSize_ = 2_MB;
oldSpaceOvershootSize_ = 8_MB;
@ -105,6 +112,8 @@ public:
minGrowingStep_ = 16_MB;
maxStackSize_ = 128_KB;
maxJSSerializerSize_ = 16_MB;
sharedHeapLimitGrowingFactor_ = 4; // 4: growing factor
sharedHeapLimitGrowingStep_ = 80_MB;
}
}
@ -143,6 +152,11 @@ public:
return defaultMachineCodeSpaceSize_;
}
size_t GetDefaultGlobalAllocLimit() const
{
return defaultGlobalAllocLimit_;
}
size_t GetSemiSpaceTriggerConcurrentMark() const
{
return semiSpaceTriggerConcurrentMark_;
@ -173,6 +187,16 @@ public:
return minGrowingStep_;
}
size_t GetSharedHeapLimitGrowingFactor() const
{
return sharedHeapLimitGrowingFactor_;
}
size_t GetSharedHeapLimitGrowingStep() const
{
return sharedHeapLimitGrowingStep_;
}
uint32_t GetMaxStackSize() const
{
return maxStackSize_;
@ -207,12 +231,15 @@ private:
size_t defaultNonMovableSpaceSize_ {0};
size_t defaultSnapshotSpaceSize_ {0};
size_t defaultMachineCodeSpaceSize_ {0};
size_t defaultGlobalAllocLimit_ {0};
size_t semiSpaceTriggerConcurrentMark_ {0};
size_t semiSpaceStepOvershootSize_ {0};
size_t oldSpaceOvershootSize_ {0};
size_t outOfMemoryOvershootSize_ {0};
size_t minAllocLimitGrowingStep_ {0};
size_t minGrowingStep_ {0};
size_t sharedHeapLimitGrowingFactor_ {0};
size_t sharedHeapLimitGrowingStep_ {0};
size_t maxJSSerializerSize_ {0};
uint32_t maxStackSize_ {0};
};

View File

@ -259,7 +259,7 @@ bool EcmaVM::Initialize()
auto context = new EcmaContext(thread_);
thread_->PushContext(context);
[[maybe_unused]] EcmaHandleScope scope(thread_);
thread_->SetReadyForGCIterating();
thread_->SetReadyForGCIterating(true);
snapshotEnv_ = new SnapshotEnv(this);
context->Initialize();
snapshotEnv_->AddGlobalConstToMap();
@ -347,6 +347,14 @@ EcmaVM::~EcmaVM()
heap_ = nullptr;
}
SharedHeap *sHeap = SharedHeap::GetInstance();
const Heap *heap = Runtime::GetInstance()->GetMainThread()->GetEcmaVM()->GetHeap();
if (heap && IsWorkerThread() && Runtime::SharedGCRequest() && !heap->InSensitiveStatus()) {
// destory workervm to release mem.
thread_->SetReadyForGCIterating(false);
sHeap->CollectGarbage(thread_, TriggerGCType::SHARED_GC, GCReason::WORKER_DESTRUCTION);
}
if (debuggerManager_ != nullptr) {
chunk_.Delete(debuggerManager_);
debuggerManager_ = nullptr;

View File

@ -401,9 +401,9 @@ void JSThread::IterateHandleWithCheck(const RootVisitor &visitor, const RootRang
}
}
void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor, bool isSharedGC)
void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor, GCKind gcKind)
{
auto callBack = [this, visitor, isSharedGC](WeakNode *node) {
auto callBack = [this, visitor, gcKind](WeakNode *node) {
JSTaggedValue value(node->GetObject());
if (!value.IsHeapObject()) {
return;
@ -422,7 +422,7 @@ void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor, bool
if (!freeGlobalCallBack) {
// If no callback, dispose global immediately
DisposeGlobalHandle(ToUintPtr(node));
} else if (isSharedGC) {
} else if (gcKind == GCKind::SHARED_GC) {
// For shared GC, free global should defer execute in its own thread
weakNodeFreeGlobalCallbacks_.push_back(std::make_pair(freeGlobalCallBack, node->GetReference()));
} else {

View File

@ -52,6 +52,11 @@ enum class MarkStatus : uint8_t {
MARK_FINISHED,
};
enum class GCKind : uint8_t {
LOCAL_GC,
SHARED_GC
};
enum class PGOProfilerStatus : uint8_t {
PGO_PROFILER_DISABLE,
PGO_PROFILER_ENABLE,
@ -371,7 +376,7 @@ public:
return os::thread::GetCurrentThreadId();
}
void IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor, bool isSharedGC = false);
void IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor, GCKind gcKind = GCKind::LOCAL_GC);
PUBLIC_API PropertiesCache *GetPropertiesCache() const;
@ -518,9 +523,9 @@ public:
return enableLazyBuiltins_;
}
void SetReadyForGCIterating()
void SetReadyForGCIterating(bool flag)
{
readyForGCIterating_ = true;
readyForGCIterating_ = flag;
}
bool ReadyForGCIterating() const

View File

@ -71,6 +71,8 @@ const char *GCStats::GCReasonToString()
return "Switch to background";
case GCReason::EXTERNAL_TRIGGER:
return "Externally triggered";
case GCReason::WORKER_DESTRUCTION:
return "Worker Destruction";
default:
return "Other";
}

View File

@ -567,7 +567,7 @@ TaggedObject *SharedHeap::AllocateHugeObject(JSThread *thread, JSHClass *hclass,
TaggedObject *SharedHeap::AllocateHugeObject(JSThread *thread, size_t size)
{
// Check whether it is necessary to trigger Shared GC before expanding to avoid OOM risk.
CheckHugeAndTriggerGC(thread, size);
CheckHugeAndTriggerSharedGC(thread, size);
auto *object = reinterpret_cast<TaggedObject *>(sHugeObjectSpace_->Allocate(thread, size));
if (UNLIKELY(object == nullptr)) {
CollectGarbage(thread, TriggerGCType::SHARED_GC, GCReason::ALLOCATION_LIMIT);

View File

@ -68,7 +68,7 @@ SharedHeap* SharedHeap::GetInstance()
return shareHeap;
}
bool SharedHeap::CheckAndTriggerGC(JSThread *thread)
bool SharedHeap::CheckAndTriggerSharedGC(JSThread *thread)
{
if ((OldSpaceExceedLimit() || GetHeapObjectSize() > globalSpaceAllocLimit_) &&
!NeedStopCollection()) {
@ -78,15 +78,40 @@ bool SharedHeap::CheckAndTriggerGC(JSThread *thread)
return false;
}
bool SharedHeap::CheckHugeAndTriggerGC(JSThread *thread, size_t size)
bool SharedHeap::CheckHugeAndTriggerSharedGC(JSThread *thread, size_t size)
{
if (sHugeObjectSpace_->CommittedSizeExceed(size) && !NeedStopCollection()) {
if ((sHugeObjectSpace_->CommittedSizeExceed(size) || GetHeapObjectSize() > globalSpaceAllocLimit_) &&
!NeedStopCollection()) {
CollectGarbage(thread, TriggerGCType::SHARED_GC, GCReason::ALLOCATION_LIMIT);
return true;
}
return false;
}
// Shared gc trigger
void SharedHeap::AdjustGlobalSpaceAllocLimit()
{
globalSpaceAllocLimit_ = std::max(GetHeapObjectSize() * growingFactor_,
config_.GetDefaultGlobalAllocLimit() * 2); // 2: double
globalSpaceAllocLimit_ = std::min(std::min(globalSpaceAllocLimit_, GetCommittedSize() + growingStep_),
config_.GetMaxHeapSize());
LOG_ECMA(INFO) << "Shared gc adjust global space alloc limit to: " << globalSpaceAllocLimit_;
}
bool SharedHeap::ObjectExceedMaxHeapSize() const
{
return OldSpaceExceedLimit() || sHugeObjectSpace_->CommittedSizeExceed();
}
bool SharedHeap::MainThreadInSensitiveStatus() const
{
JSThread *mainThread = Runtime::GetInstance()->GetMainThread();
if (mainThread == nullptr) {
return false;
}
return const_cast<Heap *>(mainThread->GetEcmaVM()->GetHeap())->InSensitiveStatus();
}
void SharedHeap::Initialize(NativeAreaAllocator *nativeAreaAllocator, HeapRegionAllocator *heapRegionAllocator,
const JSRuntimeOptions &option)
{
@ -101,11 +126,13 @@ void SharedHeap::Initialize(NativeAreaAllocator *nativeAreaAllocator, HeapRegion
size_t readOnlySpaceCapacity = config_.GetDefaultReadOnlySpaceSize();
size_t oldSpaceCapacity = (maxHeapSize - nonmovableSpaceCapacity - readOnlySpaceCapacity) / 2; // 2: half
globalSpaceAllocLimit_ = maxHeapSize;
globalSpaceAllocLimit_ = config_.GetDefaultGlobalAllocLimit();
sOldSpace_ = new SharedOldSpace(this, oldSpaceCapacity, oldSpaceCapacity);
sReadOnlySpace_ = new SharedReadOnlySpace(this, readOnlySpaceCapacity, readOnlySpaceCapacity);
sHugeObjectSpace_ = new SharedHugeObjectSpace(this, heapRegionAllocator_, oldSpaceCapacity, oldSpaceCapacity);
growingFactor_ = config_.GetSharedHeapLimitGrowingFactor();
growingStep_ = config_.GetSharedHeapLimitGrowingStep();
}
void SharedHeap::PostInitialization(const GlobalEnvConstants *globalEnvConstants, const JSRuntimeOptions &option)
@ -167,6 +194,8 @@ void SharedHeap::CollectGarbageImpl(TriggerGCType gcType, GCReason reason)
sharedGC_->RunPhases();
// Record alive object size after shared gc
NotifyHeapAliveSizeAfterGC(GetHeapObjectSize());
// Adjust shared gc trigger threshold
AdjustGlobalSpaceAllocLimit();
if (UNLIKELY(ShouldVerifyHeap())) {
// pre gc heap verify
LOG_ECMA(DEBUG) << "after gc shared heap verify";
@ -279,6 +308,18 @@ size_t SharedHeap::VerifyHeapObjects(VerifyKind verifyKind) const
return failCount;
}
bool SharedHeap::NeedStopCollection()
{
if (!MainThreadInSensitiveStatus()) {
return false;
}
if (!ObjectExceedMaxHeapSize()) {
return true;
}
return false;
}
Heap::Heap(EcmaVM *ecmaVm)
: BaseHeap(ecmaVm->GetEcmaParamConfiguration()),
ecmaVm_(ecmaVm), thread_(ecmaVm->GetJSThread()) {}

View File

@ -132,6 +132,8 @@ public:
virtual GCStats *GetEcmaGCStats() = 0;
virtual bool ObjectExceedMaxHeapSize() const = 0;
void SetMarkType(MarkType markType)
{
markType_ = markType;
@ -327,6 +329,7 @@ public:
void EnableParallelGC(JSRuntimeOptions &option);
void DisableParallelGC();
void AdjustGlobalSpaceAllocLimit();
class ParallelMarkTask : public Task {
public:
ParallelMarkTask(int32_t id, SharedHeap *heap)
@ -364,14 +367,13 @@ public:
return true;
}
bool NeedStopCollection() override
{
return onSerializeEvent_;
}
bool NeedStopCollection() override;
bool CheckAndTriggerGC(JSThread *thread);
bool ObjectExceedMaxHeapSize() const override;
bool CheckHugeAndTriggerGC(JSThread *thread, size_t size);
bool CheckAndTriggerSharedGC(JSThread *thread);
bool CheckHugeAndTriggerSharedGC(JSThread *thread, size_t size);
void TryTriggerLocalConcurrentMarking(JSThread *currentThread);
@ -414,6 +416,8 @@ public:
return parallelGC_;
}
bool MainThreadInSensitiveStatus() const;
SharedOldSpace *GetOldSpace() const
{
return sOldSpace_;
@ -556,6 +560,8 @@ private:
SharedConcurrentSweeper *sSweeper_ {nullptr};
SharedGC *sharedGC_ {nullptr};
SharedGCMarker *sharedGCMarker_ {nullptr};
size_t growingFactor_ {0};
size_t growingStep_ {0};
};
class Heap : public BaseHeap {
@ -904,7 +910,7 @@ public:
void HandleExitHighSensitiveEvent();
bool ObjectExceedMaxHeapSize() const;
bool ObjectExceedMaxHeapSize() const override;
bool NeedStopCollection() override;

View File

@ -88,7 +88,7 @@ void SharedGC::Sweep()
Runtime::GetInstance()->GCIterateThreadList([&](JSThread *thread) {
ASSERT(!thread->IsInRunningState());
thread->GetCurrentEcmaContext()->ProcessNativeDeleteInSharedGC(gcUpdateWeak);
thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, true);
thread->IterateWeakEcmaGlobalStorage(gcUpdateWeak, GCKind::SHARED_GC);
thread->GetEcmaVM()->ProcessSharedNativeDelete(gcUpdateWeak);
});

View File

@ -75,7 +75,7 @@ uintptr_t SharedSparseSpace::Allocate(JSThread *thread, size_t size, bool allowG
CHECK_SOBJECT_AND_INC_OBJ_SIZE(size);
}
// Check whether it is necessary to trigger Shared GC before expanding to avoid OOM risk.
if (allowGC && sHeap_->CheckAndTriggerGC(thread)) {
if (allowGC && sHeap_->CheckAndTriggerSharedGC(thread)) {
object = TryAllocate(thread, size);
CHECK_SOBJECT_AND_INC_OBJ_SIZE(size);
}

View File

@ -208,7 +208,7 @@ public:
void InvokeAllocationInspector(Address object, size_t objectSize);
bool CommittedSizeExceed(size_t size) const
bool CommittedSizeExceed(size_t size = 0) const
{
return committedSize_ + size >= maximumCapacity_ + outOfMemoryOvershootSize_;
}

View File

@ -31,6 +31,7 @@ namespace panda::ecmascript {
using PGOProfilerManager = pgo::PGOProfilerManager;
int32_t Runtime::vmCount_ = 0;
int32_t Runtime::destroyCount_ = 0;
bool Runtime::firstVmCreated_ = false;
Mutex *Runtime::vmCreationLock_ = new Mutex();
Runtime *Runtime::instance_ = nullptr;

View File

@ -46,6 +46,11 @@ public:
void ResumeAll(JSThread *current);
void IterateSerializeRoot(const RootVisitor &v);
JSThread *GetMainThread() const
{
return mainThread_;
}
MutatorLock *GetMutatorLock()
{
return &mutatorLock_;
@ -101,7 +106,21 @@ public:
serializeDataIndexVector_.emplace_back(index);
}
static bool SharedGCRequest()
{
LockHolder lock(*vmCreationLock_);
destroyCount_++;
if (destroyCount_ == WORKER_DESTRUCTION_COUNT || vmCount_ < MIN_GC_TRIGGER_VM_COUNT) {
destroyCount_ = 0;
return true;
} else {
return false;
}
}
private:
static constexpr int32_t WORKER_DESTRUCTION_COUNT = 3;
static constexpr int32_t MIN_GC_TRIGGER_VM_COUNT = 4;
Runtime() = default;
~Runtime() = default;
void SuspendAllThreadsImpl(JSThread *current);
@ -140,6 +159,7 @@ private:
// Runtime instance and VMs creation.
static int32_t vmCount_;
static int32_t destroyCount_;
static bool firstVmCreated_;
static Mutex *vmCreationLock_;
static Runtime *instance_;