| Index: Source/platform/heap/ThreadState.cpp
|
| diff --git a/Source/platform/heap/ThreadState.cpp b/Source/platform/heap/ThreadState.cpp
|
| index 7c857b9c609fc6962df5e713383dcfff6424b36c..d7c104263a1b4cd8216c13a959ae6972009fe51e 100644
|
| --- a/Source/platform/heap/ThreadState.cpp
|
| +++ b/Source/platform/heap/ThreadState.cpp
|
| @@ -97,8 +97,8 @@ ThreadState::ThreadState()
|
| , m_sweepForbidden(false)
|
| , m_noAllocationCount(0)
|
| , m_gcForbiddenCount(0)
|
| - , m_persistentAllocated(0)
|
| - , m_persistentFreed(0)
|
| + , m_wrapperAllocated(0)
|
| + , m_wrapperFreed(0)
|
| , m_vectorBackingHeapIndex(Vector1HeapIndex)
|
| , m_currentHeapAges(0)
|
| , m_isTerminating(false)
|
| @@ -558,110 +558,82 @@ CrossThreadPersistentRegion& ThreadState::crossThreadPersistentRegion()
|
| return persistentRegion;
|
| }
|
|
|
| -void ThreadState::updatePersistentCounters()
|
| +void ThreadState::updateWrapperCounters()
|
| {
|
| - if (m_persistentAllocated >= m_persistentFreed)
|
| - Heap::increasePersistentCount(m_persistentAllocated - m_persistentFreed);
|
| + if (m_wrapperAllocated >= m_wrapperFreed)
|
| + Heap::increaseWrapperCount(m_wrapperAllocated - m_wrapperFreed);
|
| else
|
| - Heap::decreasePersistentCount(m_persistentFreed - m_persistentAllocated);
|
| - Heap::increaseCollectedPersistentCount(m_persistentFreed);
|
| - m_persistentAllocated = 0;
|
| - m_persistentFreed = 0;
|
| -}
|
| -
|
| -size_t ThreadState::estimatedLiveObjectSize()
|
| -{
|
| - // We estimate the live object size with the following equations.
|
| - //
|
| - // heapSizePerPersistent = (marked(t0, t1) + partitionAlloc(t0)) / persistentCount(t0)
|
| - // estimatedLiveObjectSize = marked(t0, t) + allocated(t0, t) + partitionAlloc(t) - heapSizePerPersistent * collectedPersistentCount(t0, t)
|
| - //
|
| - // t0: The time when the last collectGarbage runs.
|
| - // t1: The time when the last completeSweep runs.
|
| - // t: The current time.
|
| - // marked(t0, t): The size of marked objects between t0 and t.
|
| - // allocated(t0, t): The size of newly allocated objects between t0 and t.
|
| - // persistentCount(t): The number of existing persistent handles at t.
|
| - // collectedPersistentCount(t0, t):
|
| - // The number of persistent handles collected between
|
| - // t0 and t.
|
| - // partitionAlloc(t): The size of allocated memory in PartitionAlloc at t.
|
| - size_t currentHeapSize = currentObjectSize();
|
| - size_t heapSizeRetainedByCollectedPersistents = Heap::heapSizePerPersistent() * Heap::collectedPersistentCount();
|
| - size_t estimatedSize = 0;
|
| - if (currentHeapSize > heapSizeRetainedByCollectedPersistents)
|
| - estimatedSize = currentHeapSize - heapSizeRetainedByCollectedPersistents;
|
| - TRACE_COUNTER1("blink_gc", "ThreadState::currentHeapSizeKB", std::min(currentHeapSize / 1024, static_cast<size_t>(INT_MAX)));
|
| - TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLiveObjectSizeKB", std::min(estimatedSize / 1024, static_cast<size_t>(INT_MAX)));
|
| - TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>(100.0 * currentHeapSize / estimatedSize));
|
| - return estimatedSize;
|
| -}
|
| -
|
| -size_t ThreadState::currentObjectSize()
|
| -{
|
| - return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages();
|
| + Heap::decreaseWrapperCount(m_wrapperFreed - m_wrapperAllocated);
|
| + Heap::increaseCollectedWrapperCount(m_wrapperFreed);
|
| + m_wrapperAllocated = 0;
|
| + m_wrapperFreed = 0;
|
| }
|
|
|
| -bool ThreadState::shouldForceMemoryPressureGC()
|
| +double ThreadState::partitionAllocGrowingRate()
|
| {
|
| - // Avoid potential overflow by truncating to Kb.
|
| - size_t currentObjectSizeKb = currentObjectSize() >> 10;
|
| - if (currentObjectSizeKb < 300 * 1024)
|
| + size_t sizeAtLastGC = Heap::partitionAllocSizeAtLastGC();
|
| + size_t wrapperCountAtLastGC = Heap::wrapperCountAtLastGC();
|
| + size_t sizeRetainedByCollectedPersistents = wrapperCountAtLastGC ? Heap::collectedWrapperCount() * sizeAtLastGC / wrapperCountAtLastGC : 0;
|
| + size_t estimatedLiveSize = sizeAtLastGC > sizeRetainedByCollectedPersistents ? sizeAtLastGC - sizeRetainedByCollectedPersistents : 0;
|
| + double growingRate = estimatedLiveSize ? 1.0 * WTF::Partitions::totalSizeOfCommittedPages() / estimatedLiveSize : 0;
|
| + TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLivePartitionAllocSizeKB", std::min(estimatedLiveSize / 1024, static_cast<size_t>(INT_MAX)));
|
| + TRACE_COUNTER1("blink_gc", "ThreadState::partitionAllocGrowingRate", static_cast<int>(100 * growingRate));
|
| + return growingRate;
|
| +}
|
| +
|
| +double ThreadState::heapGrowingRate()
|
| +{
|
| + size_t markedObjectSize = Heap::markedObjectSizeAtLastCompleteSweep();
|
| + size_t currentObjectSize = Heap::allocatedObjectSize() + markedObjectSize;
|
| + double growingRate = markedObjectSize ? 1.0 * currentObjectSize / markedObjectSize : 0;
|
| + TRACE_COUNTER1("blink_gc", "ThreadState::currentObjectSizeKB", std::min(currentObjectSize / 1024, static_cast<size_t>(INT_MAX)));
|
| + TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>(100 * growingRate));
|
| + return growingRate;
|
| +}
|
| +
|
| +// TODO(haraken): We should improve the GC heuristics. These heuristics
|
| +// significantly affect performance.
|
| +bool ThreadState::judgeGCThreshold(size_t allocatedObjectSizeThreshold, double heapGrowingRateThreshold, double partitionAllocGrowingRateThreshold)
|
| +{
|
| + if (Heap::allocatedObjectSize() < allocatedObjectSizeThreshold)
|
| return false;
|
| + if (heapGrowingRate() >= heapGrowingRateThreshold)
|
| + return true;
|
| + return partitionAllocGrowingRate() >= partitionAllocGrowingRateThreshold;
|
| +}
|
|
|
| - size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10;
|
| - // If we're consuming too much memory, trigger a conservative GC
|
| - // aggressively. This is a safe guard to avoid OOM.
|
| - return currentObjectSizeKb > (estimatedLiveObjectSizeKb * 3) / 2;
|
| +bool ThreadState::shouldForceMemoryPressureGC()
|
| +{
|
| + size_t totalObjectSize = Heap::allocatedObjectSize() + Heap::markedObjectSizeAtLastCompleteSweep() + WTF::Partitions::totalSizeOfCommittedPages();
|
| + if (totalObjectSize < 300 * 1024 * 1024)
|
| + return false;
|
| + return judgeGCThreshold(0, 1.5, 1.5);
|
| }
|
|
|
| -// TODO(haraken): We should improve the GC heuristics.
|
| -// These heuristics affect performance significantly.
|
| bool ThreadState::shouldScheduleIdleGC()
|
| {
|
| if (gcState() != NoGCScheduled)
|
| return false;
|
| #if ENABLE(IDLE_GC)
|
| - // Avoid potential overflow by truncating to Kb.
|
| - size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10;
|
| - // The estimated size is updated when the main thread finishes lazy
|
| - // sweeping. If this thread reaches here before the main thread finishes
|
| - // lazy sweeping, the thread will use the estimated size of the last GC.
|
| - size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10;
|
| - // Heap::markedObjectSize() may be underestimated if any thread has not
|
| - // finished completeSweep().
|
| - size_t currentObjectSizeKb = currentObjectSize() >> 10;
|
| - // Schedule an idle GC if Oilpan has allocated more than 1 MB since
|
| - // the last GC and the current memory usage is >50% larger than
|
| - // the estimated live memory usage.
|
| - return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLiveObjectSizeKb * 3) / 2;
|
| + return judgeGCThreshold(1024 * 1024, 1.5, 1.5);
|
| #else
|
| return false;
|
| #endif
|
| }
|
|
|
| -// TODO(haraken): We should improve the GC heuristics.
|
| -// These heuristics affect performance significantly.
|
| bool ThreadState::shouldSchedulePreciseGC()
|
| {
|
| - if (gcState() != NoGCScheduled)
|
| + if (isGCForbidden())
|
| return false;
|
| +
|
| + if (shouldForceMemoryPressureGC())
|
| + return true;
|
| +
|
| #if ENABLE(IDLE_GC)
|
| - return false;
|
| + return judgeGCThreshold(32 * 1024 * 1024, 4.0, 4.0);
|
| + // return false;
|
| #else
|
| - // Avoid potential overflow by truncating to Kb.
|
| - size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10;
|
| - // The estimated size is updated when the main thread finishes lazy
|
| - // sweeping. If this thread reaches here before the main thread finishes
|
| - // lazy sweeping, the thread will use the estimated size of the last GC.
|
| - size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10;
|
| - // Heap::markedObjectSize() may be underestimated if any thread has not
|
| - // finished completeSweep().
|
| - size_t currentObjectSizeKb = currentObjectSize() >> 10;
|
| - // Schedule a precise GC if Oilpan has allocated more than 1 MB since
|
| - // the last GC and the current memory usage is >50% larger than
|
| - // the estimated live memory usage.
|
| - return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLiveObjectSizeKb * 3) / 2;
|
| + return judgeGCThreshold(1024 * 1024, 1.5, 1.5);
|
| #endif
|
| }
|
|
|
| @@ -714,26 +686,13 @@ void ThreadState::schedulePageNavigationGC()
|
| // These heuristics affect performance significantly.
|
| bool ThreadState::shouldForceConservativeGC()
|
| {
|
| - if (UNLIKELY(isGCForbidden()))
|
| + if (isGCForbidden())
|
| return false;
|
|
|
| if (shouldForceMemoryPressureGC())
|
| return true;
|
|
|
| - // Avoid potential overflow by truncating to Kb.
|
| - size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10;
|
| - // The estimated size is updated when the main thread finishes lazy
|
| - // sweeping. If this thread reaches here before the main thread finishes
|
| - // lazy sweeping, the thread will use the estimated size of the last GC.
|
| - size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10;
|
| - // Heap::markedObjectSize() may be underestimated if any thread has not
|
| - // finished completeSweep().
|
| - size_t currentObjectSizeKb = currentObjectSize() >> 10;
|
| - // Schedule a conservative GC if Oilpan has allocated more than 32 MB since
|
| - // the last GC and the current memory usage is >400% larger than
|
| - // the estimated live memory usage.
|
| - // TODO(haraken): 400% is too large. Lower the heap growing factor.
|
| - return allocatedObjectSizeKb >= 32 * 1024 && currentObjectSizeKb > 5 * estimatedLiveObjectSizeKb;
|
| + return judgeGCThreshold(32 * 1024 * 1024, 5.0, 5.0);
|
| }
|
|
|
| void ThreadState::scheduleGCIfNeeded()
|
| @@ -938,18 +897,6 @@ ThreadState::GCState ThreadState::gcState() const
|
| return m_gcState;
|
| }
|
|
|
| -void ThreadState::didV8MajorGC()
|
| -{
|
| - ASSERT(checkThread());
|
| - if (isMainThread()) {
|
| - if (shouldForceMemoryPressureGC()) {
|
| - // Under memory pressure, force a conservative GC.
|
| - Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::ConservativeGC);
|
| - return;
|
| - }
|
| - }
|
| -}
|
| -
|
| void ThreadState::runScheduledGC(StackState stackState)
|
| {
|
| ASSERT(checkThread());
|
| @@ -1012,7 +959,7 @@ void ThreadState::preGC()
|
| makeConsistentForGC();
|
| flushHeapDoesNotContainCacheIfNeeded();
|
| clearHeapAges();
|
| - updatePersistentCounters();
|
| + updateWrapperCounters();
|
| }
|
|
|
| void ThreadState::postGC(GCType gcType)
|
| @@ -1193,14 +1140,11 @@ void ThreadState::postSweep()
|
| Heap::reportMemoryUsageForTracing();
|
|
|
| if (isMainThread()) {
|
| - // See the comment in estimatedLiveObjectSize() for what we're
|
| - // calculating here.
|
| - //
|
| // Heap::markedObjectSize() may be underestimated here if any other
|
| // thread has not yet finished lazy sweeping.
|
| - if (Heap::persistentCountAtLastGC() > 0) {
|
| - TRACE_EVENT1("blink_gc", "ThreadState::postSweep", "collection rate", 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC());
|
| - Heap::setHeapSizePerPersistent((Heap::markedObjectSize() + Heap::partitionAllocSizeAtLastGC()) / Heap::persistentCountAtLastGC());
|
| + if (Heap::objectSizeAtLastGC()) {
|
| + TRACE_EVENT1("blink_gc", "ThreadState::postSweep", "collection rate", 1 - 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC());
|
| + Heap::setMarkedObjectSizeAtLastCompleteSweep(Heap::markedObjectSize());
|
| }
|
| }
|
|
|
|
|