Chromium Code Reviews| Index: third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| index 4b07285edcc5fec4f7301044bcb89b3f1f6ac21b..e961657d1f12d327d7e502671efd4f410ff268de 100644 |
| --- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| +++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp |
| @@ -37,6 +37,8 @@ |
| #include "platform/heap/Handle.h" |
| #include "platform/heap/Heap.h" |
| #include "platform/heap/MarkingVisitor.h" |
| +#include "platform/heap/PageMemory.h" |
| +#include "platform/heap/PagePool.h" |
| #include "platform/heap/SafePoint.h" |
| #include "public/platform/Platform.h" |
| #include "public/platform/WebMemoryAllocatorDump.h" |
| @@ -78,9 +80,10 @@ RecursiveMutex& ThreadState::threadAttachMutex() |
| return mutex; |
| } |
| -ThreadState::ThreadState() |
| +ThreadState::ThreadState(PerThreadHeapState perThreadHeap) |
| : m_thread(currentThread()) |
| , m_persistentRegion(adoptPtr(new PersistentRegion())) |
| + , m_xThreadPersistentRegion(adoptPtr(new XThreadPersistentRegion())) |
| #if OS(WIN) && COMPILER(MSVC) |
| , m_threadStackSize(0) |
| #endif |
| @@ -106,6 +109,13 @@ ThreadState::ThreadState() |
| #if defined(LEAK_SANITIZER) |
| , m_disabledStaticPersistentsRegistration(0) |
| #endif |
| + , m_markingStack(adoptPtr(new CallbackStack())) |
| + , m_postMarkingCallbackStack(adoptPtr(new CallbackStack())) |
| + , m_globalWeakCallbackStack(adoptPtr(new CallbackStack())) |
| + , m_ephemeronStack(adoptPtr(new CallbackStack())) |
| + , m_heapDoesNotContainCache(adoptPtr(new HeapDoesNotContainCache())) |
| + , m_regionTree(nullptr) |
| + , m_perThreadHeapEnabled(perThreadHeap == PerThreadHeapEnabled) |
| { |
| ASSERT(checkThread()); |
| ASSERT(!**s_threadSpecific); |
| @@ -116,7 +126,13 @@ ThreadState::ThreadState() |
| size_t underestimatedStackSize = StackFrameDepth::getUnderestimatedStackSize(); |
| if (underestimatedStackSize > sizeof(void*)) |
| s_mainThreadUnderestimatedStackSize = underestimatedStackSize - sizeof(void*); |
| + m_heapStats = new GCHeapStats(); |
| + } else if (perThreadHeapEnabled()) { |
| + m_heapStats = new GCHeapStats(); |
| + } else { |
| + m_heapStats = ThreadState::mainThreadState()->heapStats(); |
| } |
| + ASSERT(m_heapStats); |
| for (int heapIndex = 0; heapIndex < BlinkGC::LargeObjectHeapIndex; heapIndex++) |
| m_heaps[heapIndex] = new NormalPageHeap(this, heapIndex); |
| @@ -138,9 +154,17 @@ ThreadState::~ThreadState() |
| **s_threadSpecific = nullptr; |
| if (isMainThread()) { |
| + delete m_heapStats; |
| + m_heapStats = nullptr; |
| s_mainThreadStackStart = 0; |
| s_mainThreadUnderestimatedStackSize = 0; |
| } |
| + if (perThreadHeapEnabled()) { |
| + delete m_heapStats; |
| + m_heapStats = nullptr; |
| + } |
| + delete m_regionTree; |
| + m_regionTree = nullptr; |
| } |
| void ThreadState::init() |
| @@ -196,7 +220,7 @@ void ThreadState::attachMainThread() |
| { |
| RELEASE_ASSERT(!Heap::s_shutdownCalled); |
| MutexLocker locker(threadAttachMutex()); |
| - ThreadState* state = new(s_mainThreadStateStorage) ThreadState(); |
| + ThreadState* state = new(s_mainThreadStateStorage) ThreadState(PerThreadHeapDisabled); |
| attachedThreads().add(state); |
| } |
| @@ -207,7 +231,6 @@ void ThreadState::detachMainThread() |
| // threadAttachMutex and waiting for other threads to pause or reach a |
| // safepoint. |
| ThreadState* state = mainThreadState(); |
| - |
| // 1. Finish sweeping. |
| state->completeSweep(); |
| { |
| @@ -228,7 +251,7 @@ void ThreadState::shutdownHeapIfNecessary() |
| { |
| // We don't need to enter a safe point before acquiring threadAttachMutex |
| // because this thread is already detached. |
| - |
| + ASSERT(!ThreadState::current()); |
| MutexLocker locker(threadAttachMutex()); |
| // We start shutting down the heap if there is no running thread |
| // and Heap::shutdown() is already called. |
| @@ -236,12 +259,13 @@ void ThreadState::shutdownHeapIfNecessary() |
| Heap::doShutdown(); |
| } |
| -void ThreadState::attach() |
| +void ThreadState::attach(PerThreadHeapState perThreadHeap) |
| { |
| RELEASE_ASSERT(!Heap::s_shutdownCalled); |
| MutexLocker locker(threadAttachMutex()); |
| - ThreadState* state = new ThreadState(); |
| - attachedThreads().add(state); |
| + ThreadState* state = new ThreadState(perThreadHeap); |
| + if (perThreadHeap == PerThreadHeapDisabled) |
| + attachedThreads().add(state); |
| } |
| void ThreadState::cleanupPages() |
| @@ -298,8 +322,10 @@ void ThreadState::cleanup() |
| // on will not trace objects on this thread's heaps. |
| cleanupPages(); |
| - ASSERT(attachedThreads().contains(this)); |
| - attachedThreads().remove(this); |
| + if (!perThreadHeapEnabled()) { |
| + ASSERT(attachedThreads().contains(this)); |
| + attachedThreads().remove(this); |
| + } |
| } |
| } |
| @@ -317,15 +343,17 @@ void ThreadState::visitPersistentRoots(Visitor* visitor) |
| TRACE_EVENT0("blink_gc", "ThreadState::visitPersistentRoots"); |
| crossThreadPersistentRegion().tracePersistentNodes(visitor); |
| - for (ThreadState* state : attachedThreads()) |
| + for (ThreadState* state : attachedThreads()) { |
| state->visitPersistents(visitor); |
| + } |
| } |
| void ThreadState::visitStackRoots(Visitor* visitor) |
| { |
| TRACE_EVENT0("blink_gc", "ThreadState::visitStackRoots"); |
| - for (ThreadState* state : attachedThreads()) |
| + for (ThreadState* state : attachedThreads()) { |
| state->visitStack(visitor); |
| + } |
| } |
| NO_SANITIZE_ADDRESS |
| @@ -403,6 +431,7 @@ void ThreadState::visitStack(Visitor* visitor) |
| void ThreadState::visitPersistents(Visitor* visitor) |
| { |
| m_persistentRegion->tracePersistentNodes(visitor); |
| + m_xThreadPersistentRegion->tracePersistentNodes(visitor); |
| if (m_traceDOMWrappers) { |
| TRACE_EVENT0("blink_gc", "V8GCController::traceDOMWrappers"); |
| m_traceDOMWrappers(m_isolate, visitor); |
| @@ -499,18 +528,18 @@ CrossThreadPersistentRegion& ThreadState::crossThreadPersistentRegion() |
| size_t ThreadState::totalMemorySize() |
| { |
| - return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages(); |
| + return allocatedObjectSize() + markedObjectSize() + WTF::Partitions::totalSizeOfCommittedPages(); |
| } |
| size_t ThreadState::estimatedLiveSize(size_t estimationBaseSize, size_t sizeAtLastGC) |
| { |
| - if (Heap::wrapperCountAtLastGC() == 0) { |
| + if (wrapperCountAtLastGC() == 0) { |
| // We'll reach here only before hitting the first GC. |
| return 0; |
| } |
| // (estimated size) = (estimation base size) - (heap size at the last GC) / (# of persistent handles at the last GC) * (# of persistent handles collected since the last GC); |
| - size_t sizeRetainedByCollectedPersistents = static_cast<size_t>(1.0 * sizeAtLastGC / Heap::wrapperCountAtLastGC() * Heap::collectedWrapperCount()); |
| + size_t sizeRetainedByCollectedPersistents = static_cast<size_t>(1.0 * sizeAtLastGC / wrapperCountAtLastGC() * collectedWrapperCount()); |
| if (estimationBaseSize < sizeRetainedByCollectedPersistents) |
| return 0; |
| return estimationBaseSize - sizeRetainedByCollectedPersistents; |
| @@ -518,8 +547,8 @@ size_t ThreadState::estimatedLiveSize(size_t estimationBaseSize, size_t sizeAtLa |
| double ThreadState::heapGrowingRate() |
| { |
| - size_t currentSize = Heap::allocatedObjectSize() + Heap::markedObjectSize(); |
| - size_t estimatedSize = estimatedLiveSize(Heap::markedObjectSizeAtLastCompleteSweep(), Heap::markedObjectSizeAtLastCompleteSweep()); |
| + size_t currentSize = allocatedObjectSize() + markedObjectSize(); |
| + size_t estimatedSize = estimatedLiveSize(markedObjectSizeAtLastCompleteSweep(), markedObjectSizeAtLastCompleteSweep()); |
| // If the estimatedSize is 0, we set a high growing rate to trigger a GC. |
| double growingRate = estimatedSize > 0 ? 1.0 * currentSize / estimatedSize : 100; |
| @@ -531,7 +560,7 @@ double ThreadState::heapGrowingRate() |
| double ThreadState::partitionAllocGrowingRate() |
| { |
| size_t currentSize = WTF::Partitions::totalSizeOfCommittedPages(); |
| - size_t estimatedSize = estimatedLiveSize(currentSize, Heap::partitionAllocSizeAtLastGC()); |
| + size_t estimatedSize = estimatedLiveSize(currentSize, partitionAllocSizeAtLastGC()); |
| // If the estimatedSize is 0, we set a high growing rate to trigger a GC. |
| double growingRate = estimatedSize > 0 ? 1.0 * currentSize / estimatedSize : 100; |
| @@ -545,7 +574,7 @@ double ThreadState::partitionAllocGrowingRate() |
| bool ThreadState::judgeGCThreshold(size_t totalMemorySizeThreshold, double heapGrowingRateThreshold) |
| { |
| // If the allocated object size or the total memory size is small, don't trigger a GC. |
| - if (Heap::allocatedObjectSize() < 100 * 1024 || totalMemorySize() < totalMemorySizeThreshold) |
| + if (allocatedObjectSize() < 100 * 1024 || totalMemorySize() < totalMemorySizeThreshold) |
| return false; |
| // If the growing rate of Oilpan's heap or PartitionAlloc is high enough, |
| // trigger a GC. |
| @@ -590,7 +619,7 @@ bool ThreadState::shouldForceMemoryPressureGC() |
| void ThreadState::scheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType gcType) |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| #if PRINT_HEAP_STATS |
| dataLogF("ThreadState::scheduleV8FollowupGCIfNeeded (gcType=%s)\n", gcType == BlinkGC::V8MajorGC ? "MajorGC" : "MinorGC"); |
| @@ -611,7 +640,10 @@ void ThreadState::scheduleV8FollowupGCIfNeeded(BlinkGC::V8GCType gcType) |
| #if PRINT_HEAP_STATS |
| dataLogF("Scheduled MemoryPressureGC\n"); |
| #endif |
| - Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::MemoryPressureGC); |
| + if (perThreadHeapEnabled()) |
| + Heap::collectGarbageForIsolatedThread(this); |
|
haraken
2016/01/07 08:06:22
It wouldn't be a good idea to introduce Heap::coll
|
| + else |
| + Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::MemoryPressureGC); |
| return; |
| } |
| if (shouldScheduleV8FollowupGC()) { |
| @@ -649,14 +681,17 @@ void ThreadState::willStartV8GC() |
| #if PRINT_HEAP_STATS |
| dataLogF("Scheduled PageNavigationGC\n"); |
| #endif |
| - Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::PageNavigationGC); |
| + if (perThreadHeapEnabled()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::PageNavigationGC); |
| } |
| } |
| void ThreadState::schedulePageNavigationGCIfNeeded(float estimatedRemovalRatio) |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| #if PRINT_HEAP_STATS |
| dataLogF("ThreadState::schedulePageNavigationGCIfNeeded (estimatedRemovalRatio=%.2lf)\n", estimatedRemovalRatio); |
| @@ -698,7 +733,7 @@ void ThreadState::schedulePageNavigationGC() |
| void ThreadState::scheduleGCIfNeeded() |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| #if PRINT_HEAP_STATS |
| dataLogF("ThreadState::scheduleGCIfNeeded\n"); |
| @@ -730,7 +765,10 @@ void ThreadState::scheduleGCIfNeeded() |
| #if PRINT_HEAP_STATS |
| dataLogF("Scheduled ConservativeGC\n"); |
| #endif |
| - Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::ConservativeGC); |
| + if (perThreadHeapEnabled()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::HeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::ConservativeGC); |
| return; |
| } |
| } |
| @@ -753,15 +791,18 @@ void ThreadState::performIdleGC(double deadlineSeconds) |
| return; |
| double idleDeltaInSeconds = deadlineSeconds - Platform::current()->monotonicallyIncreasingTimeSeconds(); |
| - TRACE_EVENT2("blink_gc", "ThreadState::performIdleGC", "idleDeltaInSeconds", idleDeltaInSeconds, "estimatedMarkingTime", Heap::estimatedMarkingTime()); |
| - if (idleDeltaInSeconds <= Heap::estimatedMarkingTime() && !Platform::current()->currentThread()->scheduler()->canExceedIdleDeadlineIfRequired()) { |
| + TRACE_EVENT2("blink_gc", "ThreadState::performIdleGC", "idleDeltaInSeconds", idleDeltaInSeconds, "estimatedMarkingTime", m_heapStats->estimatedMarkingTime()); |
| + if (idleDeltaInSeconds <= m_heapStats->estimatedMarkingTime() && !Platform::current()->currentThread()->scheduler()->canExceedIdleDeadlineIfRequired()) { |
| // If marking is estimated to take longer than the deadline and we can't |
| // exceed the deadline, then reschedule for the next idle period. |
| scheduleIdleGC(); |
| return; |
| } |
| - Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::IdleGC); |
| + if (perThreadHeapEnabled()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::IdleGC); |
| } |
| void ThreadState::performIdleLazySweep(double deadlineSeconds) |
| @@ -940,10 +981,16 @@ void ThreadState::runScheduledGC(BlinkGC::StackState stackState) |
| Heap::collectAllGarbage(); |
| break; |
| case PreciseGCScheduled: |
| - Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::PreciseGC); |
| + if (perThreadHeapEnabled()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithoutSweep, BlinkGC::PreciseGC); |
| break; |
| case PageNavigationGCScheduled: |
| - Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::PageNavigationGC); |
| + if (perThreadHeapEnabled()) |
| + Heap::collectGarbageForIsolatedThread(this); |
| + else |
| + Heap::collectGarbage(BlinkGC::NoHeapPointersOnStack, BlinkGC::GCWithSweep, BlinkGC::PageNavigationGC); |
| break; |
| case IdleGCScheduled: |
| // Idle time GC will be scheduled by Blink Scheduler. |
| @@ -956,7 +1003,7 @@ void ThreadState::runScheduledGC(BlinkGC::StackState stackState) |
| void ThreadState::flushHeapDoesNotContainCacheIfNeeded() |
| { |
| if (m_shouldFlushHeapDoesNotContainCache) { |
| - Heap::flushHeapDoesNotContainCache(); |
| + flushHeapDoesNotContainCache(); |
| m_shouldFlushHeapDoesNotContainCache = false; |
| } |
| } |
| @@ -1125,12 +1172,12 @@ void ThreadState::completeSweep() |
| void ThreadState::postSweep() |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| if (isMainThread()) { |
| double collectionRate = 0; |
| - if (Heap::objectSizeAtLastGC() > 0) |
| - collectionRate = 1 - 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC(); |
| + if (objectSizeAtLastGC() > 0) |
| + collectionRate = 1 - 1.0 * markedObjectSize() / objectSizeAtLastGC(); |
| TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "ThreadState::collectionRate", static_cast<int>(100 * collectionRate)); |
| #if PRINT_HEAP_STATS |
| @@ -1139,10 +1186,10 @@ void ThreadState::postSweep() |
| // Heap::markedObjectSize() may be underestimated here if any other |
| // thread has not yet finished lazy sweeping. |
| - Heap::setMarkedObjectSizeAtLastCompleteSweep(Heap::markedObjectSize()); |
| + m_heapStats->setMarkedObjectSizeAtLastCompleteSweep(markedObjectSize()); |
| - Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeBeforeGC", Heap::objectSizeAtLastGC() / 1024, 1, 4 * 1024 * 1024, 50); |
| - Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeAfterGC", Heap::markedObjectSize() / 1024, 1, 4 * 1024 * 1024, 50); |
| + Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeBeforeGC", objectSizeAtLastGC() / 1024, 1, 4 * 1024 * 1024, 50); |
| + Platform::current()->histogramCustomCounts("BlinkGC.ObjectSizeAfterGC", markedObjectSize() / 1024, 1, 4 * 1024 * 1024, 50); |
| Platform::current()->histogramCustomCounts("BlinkGC.CollectionRate", static_cast<int>(100 * collectionRate), 1, 100, 20); |
| Platform::current()->histogramCustomCounts("BlinkGC.TimeForSweepingAllObjects", m_accumulatedSweepingTime, 1, 10 * 1000, 50); |
| } |
| @@ -1202,7 +1249,7 @@ void ThreadState::resumeThreads() |
| void ThreadState::safePoint(BlinkGC::StackState stackState) |
| { |
| ASSERT(checkThread()); |
| - Heap::reportMemoryUsageForTracing(); |
| + reportMemoryUsageForTracing(); |
| runScheduledGC(stackState); |
| ASSERT(!m_atSafePoint); |
| @@ -1521,4 +1568,182 @@ void ThreadState::takeSnapshot(SnapshotType type) |
| BlinkGCMemoryDumpProvider::instance()->currentProcessMemoryDump()->addOwnershipEdge(classesDump->guid(), heapsDump->guid()); |
| } |
| +void ThreadState::reportMemoryUsageHistogram() |
| +{ |
| + static size_t supportedMaxSizeInMB = 4 * 1024; |
| + static size_t observedMaxSizeInMB = 0; |
| + |
| + // FIXME: Separate report per thread |
| + |
| + // +1 is for rounding up the sizeInMB. |
| + size_t sizeInMB = allocatedSpace() / 1024 / 1024 + 1; |
| + if (sizeInMB >= supportedMaxSizeInMB) |
| + sizeInMB = supportedMaxSizeInMB - 1; |
| + if (sizeInMB > observedMaxSizeInMB) { |
| + // Send a UseCounter only when we see the highest memory usage |
| + // we've ever seen. |
| + Platform::current()->histogramEnumeration("BlinkGC.CommittedSize", sizeInMB, supportedMaxSizeInMB); |
| + observedMaxSizeInMB = sizeInMB; |
| + } |
| +} |
| + |
| +void ThreadState::reportMemoryUsageForTracing() |
| +{ |
| + // FIXME: Separate report per thread |
|
haraken
2016/01/07 08:06:22
In practice, we're just interested in the memory c
|
| +#if PRINT_HEAP_STATS |
| + // dataLogF("allocatedSpace=%ldMB, allocatedObjectSize=%ldMB, markedObjectSize=%ldMB, partitionAllocSize=%ldMB, wrapperCount=%ld, collectedWrapperCount=%ld\n", Heap::allocatedSpace() / 1024 / 1024, Heap::allocatedObjectSize() / 1024 / 1024, Heap::markedObjectSize() / 1024 / 1024, WTF::Partitions::totalSizeOfCommittedPages() / 1024 / 1024, Heap::wrapperCount(), Heap::collectedWrapperCount()); |
|
haraken
2016/01/07 08:06:22
Heap:: => ThreadState::
|
| +#endif |
| + |
| + bool gcTracingEnabled; |
| + TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink_gc", &gcTracingEnabled); |
| + if (!gcTracingEnabled) |
| + return; |
| + |
| + // These values are divided by 1024 to avoid overflow in practical cases (TRACE_COUNTER values are 32-bit ints). |
| + // They are capped to INT_MAX just in case. |
| + TRACE_COUNTER1("blink_gc", "Heap::allocatedObjectSizeKB", std::min(allocatedObjectSize() / 1024, static_cast<size_t>(INT_MAX))); |
|
haraken
2016/01/07 08:06:22
Heap:: => ThreadState::
|
| + TRACE_COUNTER1("blink_gc", "Heap::markedObjectSizeKB", std::min(markedObjectSize() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::markedObjectSizeAtLastCompleteSweepKB", std::min(markedObjectSizeAtLastCompleteSweep() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1("blink_gc", "Heap::allocatedSpaceKB", std::min(allocatedSpace() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::objectSizeAtLastGCKB", std::min(objectSizeAtLastGC() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::wrapperCount", std::min(wrapperCount(), static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::wrapperCountAtLastGC", std::min(wrapperCountAtLastGC(), static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::collectedWrapperCount", std::min(collectedWrapperCount(), static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("blink_gc"), "Heap::partitionAllocSizeAtLastGCKB", std::min(partitionAllocSizeAtLastGC() / 1024, static_cast<size_t>(INT_MAX))); |
| + TRACE_COUNTER1("blink_gc", "Partitions::totalSizeOfCommittedPagesKB", std::min(WTF::Partitions::totalSizeOfCommittedPages() / 1024, static_cast<size_t>(INT_MAX))); |
| +} |
| + |
| +void ThreadState::resetHeapCounters() |
| +{ |
| + ASSERT(isInGC()); |
| + |
| + reportMemoryUsageForTracing(); |
| + |
| + m_heapStats->reset(); |
| +} |
| + |
| +void ThreadState::flushHeapDoesNotContainCache() |
| +{ |
| + m_heapDoesNotContainCache->flush(); |
| +} |
| + |
| +ThreadState::GCHeapStats::GCHeapStats() |
| + : m_allocatedSpace(0) |
| + , m_allocatedObjectSize(0) |
| + , m_objectSizeAtLastGC(0) |
| + , m_markedObjectSize(0) |
| + , m_markedObjectSizeAtLastCompleteSweep(0) |
| + , m_wrapperCount(0) |
| + , m_wrapperCountAtLastGC(0) |
| + , m_collectedWrapperCount(0) |
| + , m_partitionAllocSizeAtLastGC(WTF::Partitions::totalSizeOfCommittedPages()) |
| + , m_estimatedMarkingTimePerByte(0.0) |
| +#if ENABLE(ASSERT) |
| + // 0 is used to figure non-assigned area, so avoid to use 0 in s_gcGeneration. |
| + , m_gcGeneration(1) |
| +#endif |
| +{ |
| +} |
| + |
| +double ThreadState::GCHeapStats::estimatedMarkingTime() |
| +{ |
| + // Use 8 ms as initial estimated marking time. |
| + // 8 ms is long enough for low-end mobile devices to mark common |
| + // real-world object graphs. |
| + if (m_estimatedMarkingTimePerByte == 0) |
| + return 0.008; |
| + |
| + // Assuming that the collection rate of this GC will be mostly equal to |
| + // the collection rate of the last GC, estimate the marking time of this GC. |
| + return m_estimatedMarkingTimePerByte * (allocatedObjectSize() + markedObjectSize()); |
| +} |
| + |
| +void ThreadState::GCHeapStats::reset() |
| +{ |
| + m_objectSizeAtLastGC = m_allocatedObjectSize + m_markedObjectSize; |
| + m_partitionAllocSizeAtLastGC = WTF::Partitions::totalSizeOfCommittedPages(); |
| + m_allocatedObjectSize = 0; |
| + m_markedObjectSize = 0; |
| + m_wrapperCountAtLastGC = m_wrapperCount; |
| + m_collectedWrapperCount = 0; |
| +} |
| + |
| +PageMemoryRegion* ThreadState::RegionTree::lookup(Address address) |
| +{ |
| + RegionTree* current = this; |
| + while (current) { |
| + Address base = current->m_region->base(); |
| + if (address < base) { |
| + current = current->m_left; |
| + continue; |
| + } |
| + if (address >= base + current->m_region->size()) { |
| + current = current->m_right; |
| + continue; |
| + } |
| + ASSERT(current->m_region->contains(address)); |
| + return current->m_region; |
| + } |
| + return nullptr; |
| +} |
| + |
| +void ThreadState::RegionTree::add(RegionTree* newTree, RegionTree** context) |
| +{ |
| + ASSERT(newTree); |
| + Address base = newTree->m_region->base(); |
| + for (RegionTree* current = *context; current; current = *context) { |
| + ASSERT(!current->m_region->contains(base)); |
| + context = (base < current->m_region->base()) ? ¤t->m_left : ¤t->m_right; |
| + } |
| + *context = newTree; |
| +} |
| + |
| +void ThreadState::RegionTree::remove(PageMemoryRegion* region, RegionTree** context) |
| +{ |
| + ASSERT(region); |
| + ASSERT(context); |
| + Address base = region->base(); |
| + RegionTree* current = *context; |
| + for (; current; current = *context) { |
| + if (region == current->m_region) |
| + break; |
| + context = (base < current->m_region->base()) ? ¤t->m_left : ¤t->m_right; |
| + } |
| + |
| + // Shutdown via detachMainThread might not have populated the region tree. |
| + if (!current) |
| + return; |
| + |
| + *context = nullptr; |
| + if (current->m_left) { |
| + add(current->m_left, context); |
| + current->m_left = nullptr; |
| + } |
| + if (current->m_right) { |
| + add(current->m_right, context); |
| + current->m_right = nullptr; |
| + } |
| + delete current; |
| +} |
| + |
| +void ThreadState::removeFromRegionTree(PageMemoryRegion* region) |
| +{ |
| + if (m_regionTree) |
| + RegionTree::remove(region, &m_regionTree); |
| +} |
| + |
| +ThreadState* ThreadState::forObject(const void* object) |
| +{ |
| + if (!object) |
| + return nullptr; |
| + BasePage* page = pageFromObject(object); |
| + ASSERT(page); |
| + ASSERT(page->heap()); |
| + return page->heap()->threadState(); |
| +} |
| + |
| +size_t ThreadState::s_totalAllocatedSpace = 0; |
| +size_t ThreadState::s_totalAllocatedObjectSize = 0; |
| +size_t ThreadState::s_totalMarkedObjectSize = 0; |
| + |
| } // namespace blink |