Add force expand interface

issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7S293?from=project-issue

Signed-off-by: wuwanqi <wuwanqi2@huawei.com>
Change-Id: I8d46728c381a956d3a14f036fe4c03ad4d0b4c8b
This commit is contained in:
wuwanqi 2023-08-10 10:22:53 +08:00
parent f600731f0a
commit 1f9e21a744
10 changed files with 220 additions and 8 deletions

View File

@ -931,6 +931,10 @@ ohos_source_set("libark_jsruntime_set") {
"/system/lib64/${arkcompiler_relative_lib_path}/lib_ark_builtins.d.abc"
defines += [ "TARGET_BUILTINS_DTS_PATH=\"${target_builtins_dts_path}\"" ]
if (current_cpu == "arm64") {
defines += [ "ENABLE_POSTFORK_FORCEEXPAND" ]
}
sources = ecma_source
sources += ecma_profiler_source
sources += ecma_debugger_source

View File

@ -143,6 +143,9 @@ void EcmaVM::PostFork()
heap_->SetHeapMode(HeapMode::SHARE);
GetAssociatedJSThread()->SetThreadId();
heap_->EnableParallelGC();
#ifdef ENABLE_POSTFORK_FORCEEXPAND
heap_->NotifyPostFork();
#endif
}
EcmaVM::EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config)

View File

@ -726,8 +726,9 @@ bool Heap::CheckAndTriggerOldGC(size_t size)
if (isFullMarking && oldSpace_->GetOvershootSize() == 0) {
oldSpace_->SetOvershootSize(GetEcmaVM()->GetEcmaParamConfiguration().GetOldSpaceOvershootSize());
}
if (isNativeSizeLargeTrigger || OldSpaceExceedLimit() || OldSpaceExceedCapacity(size) ||
GetHeapObjectSize() > globalSpaceAllocLimit_ + oldSpace_->GetOvershootSize()) {
if ((isNativeSizeLargeTrigger || OldSpaceExceedLimit() || OldSpaceExceedCapacity(size) ||
GetHeapObjectSize() > globalSpaceAllocLimit_ + oldSpace_->GetOvershootSize()) &&
!NeedStopCollection()) {
CollectGarbage(TriggerGCType::OLD_GC, GCReason::ALLOCATION_LIMIT);
if (!oldGCRequested_) {
return true;
@ -853,8 +854,7 @@ void Heap::TryTriggerIncrementalMarking()
double oldSpaceRemainSize = (oldSpaceAllocToLimitDuration - oldSpaceMarkDuration) * oldSpaceAllocSpeed;
// mark finished before allocate limit
if ((oldSpaceRemainSize > 0 && oldSpaceRemainSize < DEFAULT_REGION_SIZE) ||
GetHeapObjectSize() >= globalSpaceAllocLimit_) {
if ((oldSpaceRemainSize < DEFAULT_REGION_SIZE) || GetHeapObjectSize() >= globalSpaceAllocLimit_) {
// The object allocated in incremental marking should lower than limit,
// otherwise select trigger concurrent mark.
size_t allocateSize = oldSpaceAllocSpeed * oldSpaceMarkDuration;
@ -1112,6 +1112,74 @@ void Heap::NotifyMemoryPressure(bool inHighMemoryPressure)
}
}
void Heap::NotifyFinishColdStart(bool isMainThread)
{
{
os::memory::LockHolder holder(finishColdStartMutex_);
if (!onStartupEvent_) {
return;
}
// set overshoot size to increase gc threashold larger 8MB than current heap size.
int64_t semiRemainSize = GetNewSpace()->GetInitialCapacity() - GetNewSpace()->GetCommittedSize();
int64_t overshootSize = GetEcmaVM()->GetEcmaParamConfiguration().GetOldSpaceOvershootSize() - semiRemainSize;
// overshoot size should be larger than 0.
GetNewSpace()->SetOverShootSize(std::max(overshootSize, (int64_t)0));
GetNewSpace()->SetWaterLineWithoutGC();
onStartupEvent_ = false;
}
if (isMainThread) {
markType_ = MarkType::MARK_FULL;
TriggerConcurrentMarking();
}
}
void Heap::NotifyFinishColdStartSoon()
{
if (!onStartupEvent_) {
return;
}
// post 2s task
Taskpool::GetCurrentTaskpool()->PostTask(
std::make_unique<FinishColdStartTask>(GetJSThread()->GetThreadId(), this));
}
void Heap::NotifyHighSensitive(bool isStart)
{
onHighSensitiveEvent_ = isStart;
if (!onHighSensitiveEvent_ && !onStartupEvent_) {
// set overshoot size to increase gc threashold larger 8MB than current heap size.
int64_t semiRemainSize = GetNewSpace()->GetInitialCapacity() - GetNewSpace()->GetCommittedSize();
int64_t overshootSize = GetEcmaVM()->GetEcmaParamConfiguration().GetOldSpaceOvershootSize() - semiRemainSize;
// overshoot size should be larger than 0.
GetNewSpace()->SetOverShootSize(std::max(overshootSize, (int64_t)0));
GetNewSpace()->SetWaterLineWithoutGC();
TryTriggerIncrementalMarking();
TryTriggerIdleCollection();
TryTriggerConcurrentMarking();
}
}
bool Heap::NeedStopCollection()
{
if (!InSensitiveStatus()) {
return false;
}
if (GetHeapObjectSize() < ecmaVm_->GetEcmaParamConfiguration().GetMaxHeapSize() -
ecmaVm_->GetEcmaParamConfiguration().GetOldSpaceOvershootSize()) {
return true;
}
GetNewSpace()->SetOverShootSize(
GetNewSpace()->GetCommittedSize() - GetNewSpace()->GetInitialCapacity() +
ecmaVm_->GetEcmaParamConfiguration().GetOldSpaceOvershootSize());
return false;
}
bool Heap::CheckCanDistributeTask()
{
os::memory::LockHolder holder(waitTaskFinishedMutex_);
@ -1167,6 +1235,13 @@ bool Heap::AsyncClearTask::Run([[maybe_unused]] uint32_t threadIndex)
return true;
}
bool Heap::FinishColdStartTask::Run([[maybe_unused]] uint32_t threadIndex)
{
usleep(2000000); // 2000000 means 2s
heap_->NotifyFinishColdStart(false);
return true;
}
size_t Heap::GetArrayBufferSize() const
{
size_t result = 0;

View File

@ -224,6 +224,17 @@ public:
return memController_;
}
bool InSensitiveStatus() const
{
return onHighSensitiveEvent_ || onStartupEvent_;
}
void NotifyPostFork()
{
os::memory::LockHolder holder(finishColdStartMutex_);
onStartupEvent_ = true;
}
/*
* For object allocations.
*/
@ -405,6 +416,19 @@ public:
void ClearIdleTask();
bool IsEmptyIdleTask() const
{
return idleTask_ == IdleTaskType::NO_TASK;
}
void NotifyFinishColdStart(bool isMainThread = true);
void NotifyFinishColdStartSoon();
void NotifyHighSensitive(bool isStart);
bool NeedStopCollection();
#if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
void StartHeapTracking()
{
@ -587,6 +611,19 @@ private:
TriggerGCType gcType_;
};
class FinishColdStartTask : public Task {
public:
FinishColdStartTask(int32_t id, Heap *heap)
: Task(id), heap_(heap) {}
~FinishColdStartTask() override = default;
bool Run(uint32_t threadIndex) override;
NO_COPY_SEMANTIC(FinishColdStartTask);
NO_MOVE_SEMANTIC(FinishColdStartTask);
private:
Heap *heap_;
};
EcmaVM *ecmaVm_ {nullptr};
JSThread *thread_ {nullptr};
@ -683,6 +720,7 @@ private:
uint32_t maxMarkTaskCount_ {0};
// parallel evacuator task number.
uint32_t maxEvacuateTaskCount_ {0};
os::memory::Mutex finishColdStartMutex_;
os::memory::Mutex waitTaskFinishedMutex_;
os::memory::ConditionVariable waitTaskFinishedCV_;
@ -700,6 +738,8 @@ private:
bool inBackground_ {false};
IdleNotifyStatusCallback notifyIdleStatusCallback {nullptr};
bool onHighSensitiveEvent_ {false};
bool onStartupEvent_ {false};
IdleTaskType idleTask_ {IdleTaskType::NO_TASK};
float idlePredictDuration_ {0.0f};

View File

@ -43,13 +43,13 @@ uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted)
return object;
}
if (Expand(isPromoted)) {
if (!isPromoted) {
if (!isPromoted && !heap_->NeedStopCollection()) {
heap_->TryTriggerIncrementalMarking();
heap_->TryTriggerIdleCollection();
heap_->TryTriggerConcurrentMarking();
}
object = allocator_.Allocate(size);
} else if (heap_->GetJSThread()->IsMarking()) {
} else if (heap_->GetJSThread()->IsMarking() || !heap_->IsEmptyIdleTask()) {
// Temporary adjust semi space capacity
if (heap_->IsFullMark()) {
overShootSize_ = heap_->GetOldSpace()->GetMaximumCapacity() - heap_->GetOldSpace()->GetInitialCapacity();
@ -71,7 +71,8 @@ uintptr_t LinearSpace::Allocate(size_t size, bool isPromoted)
bool LinearSpace::Expand(bool isPromoted)
{
if (committedSize_ >= initialCapacity_ + overShootSize_ + outOfMemoryOvershootSize_) {
if (committedSize_ >= initialCapacity_ + overShootSize_ + outOfMemoryOvershootSize_ &&
!heap_->NeedStopCollection()) {
return false;
}
@ -221,6 +222,23 @@ void SemiSpace::SetWaterLine()
}
}
void SemiSpace::SetWaterLineWithoutGC()
{
waterLine_ = allocator_.GetTop();
Region *last = GetCurrentRegion();
if (last != nullptr) {
last->SetGCFlag(RegionGCFlags::HAS_AGE_MARK);
EnumerateRegions([&last](Region *current) {
if (current != last) {
current->SetGCFlag(RegionGCFlags::BELOW_AGE_MARK);
}
});
survivalObjectSize_ += allocateAfterLastGC_;
}
allocateAfterLastGC_ = 0;
}
size_t SemiSpace::GetHeapObjectSize() const
{
return survivalObjectSize_ + allocateAfterLastGC_;

View File

@ -68,6 +68,7 @@ public:
void SetOverShootSize(size_t size);
bool AdjustCapacity(size_t allocatedSizeSinceGC);
void SetWaterLine();
void SetWaterLineWithoutGC();
uintptr_t GetWaterLine() const
{

View File

@ -551,7 +551,7 @@ void LocalSpace::Stop()
}
}
uintptr_t NonMovableSpace::CheckAndAllocate(size_t size)
uintptr_t NonMovableSpace::CheckAndAllocate(size_t size)
{
if (maximumCapacity_ == committedSize_ && GetHeapObjectSize() > MAX_NONMOVABLE_LIVE_OBJ_SIZE &&
!heap_->GetOldGCRequested())

View File

@ -270,6 +270,20 @@ void DFXJSNApi::NotifyMemoryPressure(EcmaVM *vm, bool inHighMemoryPressure)
const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyMemoryPressure(inHighMemoryPressure);
}
void DFXJSNApi::NotifyFinishColdStart(EcmaVM *vm, bool isConvinced)
{
if (isConvinced) {
const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyFinishColdStart();
} else {
const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyFinishColdStartSoon();
}
}
void DFXJSNApi::NotifyHighSensitive(EcmaVM *vm, bool isStart)
{
const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyHighSensitive(isStart);
}
bool DFXJSNApi::StopCpuProfilerForColdStart([[maybe_unused]] const EcmaVM *vm)
{
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)

View File

@ -75,6 +75,8 @@ public:
static void NotifyIdleStatusControl(const EcmaVM *vm, std::function<void(bool)> callback);
static void NotifyIdleTime(const EcmaVM *vm, int idleMicroSec);
static void NotifyMemoryPressure(EcmaVM *vm, bool inHighMemoryPressure);
static void NotifyFinishColdStart(EcmaVM *vm, bool isConvinced);
static void NotifyHighSensitive(EcmaVM *vm, bool isStart);
static bool BuildJsStackInfoList(const EcmaVM *hostVm, uint32_t tid, std::vector<JsFrameInfo>& jsFrames);
// cpuprofiler

View File

@ -307,6 +307,61 @@ HWTEST_F_L0(GCTest, ArkToolsForceFullGC)
ASSERT_TRUE(thread->GetEcmaVM()->GetHeap()->GetCommittedSize() < newSize);
}
HWTEST_F_L0(GCTest, ColdStartForceExpand)
{
auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
size_t originalHeapSize = heap->GetCommittedSize();
heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
heap->NotifyPostFork();
heap->NotifyFinishColdStartSoon();
{
[[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
for (int i = 0; i < 500; i++) {
[[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
10 * 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
}
}
size_t expandHeapSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
usleep(2500000);
{
[[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
for (int i = 0; i < 100; i++) {
[[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
10 * 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
}
}
size_t newSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
EXPECT_TRUE(originalHeapSize < expandHeapSize);
EXPECT_TRUE(expandHeapSize > newSize);
}
HWTEST_F_L0(GCTest, HighSensitiveForceExpand)
{
auto heap = const_cast<Heap *>(thread->GetEcmaVM()->GetHeap());
size_t originalHeapSize = heap->GetCommittedSize();
heap->GetConcurrentMarker()->ConfigConcurrentMark(false);
heap->NotifyHighSensitive(true);
{
[[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
for (int i = 0; i < 500; i++) {
[[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
10 * 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
}
}
size_t expandHeapSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->NotifyHighSensitive(false);
{
[[maybe_unused]] ecmascript::EcmaHandleScope baseScope(thread);
for (int i = 0; i < 100; i++) {
[[maybe_unused]] JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(
10 * 1024, JSTaggedValue::Hole(), MemSpaceType::SEMI_SPACE);
}
}
size_t newSize = thread->GetEcmaVM()->GetHeap()->GetCommittedSize();
EXPECT_TRUE(originalHeapSize < expandHeapSize);
EXPECT_TRUE(expandHeapSize > newSize);
}
HWTEST_F_L0(GCTest, NoFullConcurrentMarkOldGCTrigger)
{
#ifdef NDEBUG