From ddc9428d4f59004dce55a30cb5860bff26acc6e5 Mon Sep 17 00:00:00 2001 From: LepilkinaElena Date: Fri, 31 Jul 2020 09:50:37 +0300 Subject: [PATCH] =?UTF-8?q?Added=20extra=20GC=20call=20before=20analyzing?= =?UTF-8?q?=20subgraph=20during=20freeze=20operation=E2=80=A6=20(#4314)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- runtime/src/main/cpp/Memory.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/runtime/src/main/cpp/Memory.cpp b/runtime/src/main/cpp/Memory.cpp index 597698a405a..a2ffc3e82cf 100644 --- a/runtime/src/main/cpp/Memory.cpp +++ b/runtime/src/main/cpp/Memory.cpp @@ -1679,7 +1679,7 @@ void garbageCollect(MemoryState* state, bool force) { GC_LOG("||| GC: collectCyclesDuration = %lld\n", cyclicGcEndTime - cyclicGcStartTime); #endif auto cyclicGcDuration = cyclicGcEndTime - cyclicGcStartTime; - if (state->gcErgonomics && cyclicGcDuration > kGcCollectCyclesMinimumDuration && + if (!force && state->gcErgonomics && cyclicGcDuration > kGcCollectCyclesMinimumDuration && double(cyclicGcDuration) / (cyclicGcStartTime - state->lastCyclicGcTimestamp + 1) > kGcCollectCyclesLoadRatio) { increaseGcCollectCyclesThreshold(state); GC_LOG("Adjusting GC collecting cycles threshold to %lld\n", state->gcCollectCyclesThreshold); @@ -1692,7 +1692,7 @@ void garbageCollect(MemoryState* state, bool force) { if (state->gcErgonomics) { auto gcToComputeRatio = double(gcEndTime - gcStartTime) / (gcStartTime - state->lastGcTimestamp + 1); - if (gcToComputeRatio > kGcToComputeRatioThreshold) { + if (!force && gcToComputeRatio > kGcToComputeRatioThreshold) { increaseGcThreshold(state); GC_LOG("Adjusting GC threshold to %d\n", state->gcThreshold); } @@ -1997,6 +1997,16 @@ inline void checkIfGcNeeded(MemoryState* state) { } } +inline void checkIfForceCyclicGcNeeded(MemoryState* state) { + if (state != nullptr && state->toFree != nullptr && state->toFree->size() > kMaxToFreeSizeThreshold) { + // To avoid GC trashing check that at least 10ms passed since last GC. + if (konan::getTimeMicros() - state->lastGcTimestamp > 10 * 1000) { + GC_LOG("Calling GC from checkIfForceCyclicGcNeeded: %d\n", state->toFree->size()) + garbageCollect(state, true); + } + } +} + template OBJ_GETTER(allocInstance, const TypeInfo* type_info) { RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object"); @@ -2400,6 +2410,9 @@ bool clearSubgraphReferences(ObjHeader* root, bool checked) { // TODO: assert for that? return true; + // Free cyclic garbage to decrease number of analyzed objects. + checkIfForceCyclicGcNeeded(state); + ContainerHeaderSet visited; if (!checked) { hasExternalRefs(container, &visited); @@ -2601,6 +2614,12 @@ void freezeSubgraph(ObjHeader* root) { MEMORY_LOG("Freeze subgraph of %p\n", root) + #if USE_GC + auto state = memoryState; + // Free cyclic garbage to decrease number of analyzed objects. + checkIfForceCyclicGcNeeded(state); + #endif + // Do DFS cycle detection. bool hasCycles = false; KRef firstBlocker = root->has_meta_object() && ((root->meta_object()->flags_ & MF_NEVER_FROZEN) != 0) ? @@ -2624,7 +2643,6 @@ void freezeSubgraph(ObjHeader* root) { // Now remove frozen objects from the toFree list. // TODO: optimize it by keeping ignored (i.e. freshly frozen) objects in the set, // and use it when analyzing toFree during collection. - auto state = memoryState; for (auto& container : *(state->toFree)) { if (!isMarkedAsRemoved(container) && container->frozen()) { RuntimeAssert(newlyFrozen.count(container) != 0, "Must be newly frozen");