| Index: Source/platform/heap/Heap.cpp
|
| diff --git a/Source/platform/heap/Heap.cpp b/Source/platform/heap/Heap.cpp
|
| index 2163e15d963b3259f0c6f7654ee177703cde54f8..3a7ecf0bfd02bd5179ddb522b8d7af925108b9e1 100644
|
| --- a/Source/platform/heap/Heap.cpp
|
| +++ b/Source/platform/heap/Heap.cpp
|
| @@ -50,7 +50,7 @@
|
| #include <stdio.h>
|
| #include <utility>
|
| #endif
|
| -#if ENABLE(GC_PROFILE_HEAP)
|
| +#if ENABLE(GC_PROFILE_HEAP) || ENABLE(GC_PROFILE_FREE_LIST) || ENABLE(GC_PROFILE_MARKING)
|
| #include "platform/TracedValue.h"
|
| #endif
|
|
|
| @@ -63,6 +63,36 @@
|
|
|
| namespace blink {
|
|
|
| +struct AgeHistogram {
|
| + int data[8];
|
| +};
|
| +
|
| +typedef HashMap<String, AgeHistogram> ObjectAgeMap;
|
| +
|
| +static ObjectAgeMap& uom()
|
| +{
|
| + static ObjectAgeMap uomap;
|
| + return uomap;
|
| +}
|
| +
|
| +static Mutex& uomMutex()
|
| +{
|
| + AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex);
|
| + return mutex;
|
| +}
|
| +
|
| +static ObjectAgeMap& mom()
|
| +{
|
| + static ObjectAgeMap momap;
|
| + return momap;
|
| +}
|
| +
|
| +static Mutex& momMutex()
|
| +{
|
| + AtomicallyInitializedStaticReference(Mutex, mutex, new Mutex);
|
| + return mutex;
|
| +}
|
| +
|
| #if ENABLE(GC_PROFILE_MARKING)
|
| static String classOf(const void* object)
|
| {
|
| @@ -543,6 +573,11 @@ ThreadHeap::ThreadHeap(ThreadState* state, int index)
|
| : m_currentAllocationPoint(nullptr)
|
| , m_remainingAllocationSize(0)
|
| , m_lastRemainingAllocationSize(0)
|
| +#if ENABLE(GC_PROFILE_FREE_LIST)
|
| + , m_totalAllocationSize(0.0)
|
| + , m_allocationCount(0)
|
| + , m_inlineAllocationCount(0)
|
| +#endif
|
| , m_firstPage(nullptr)
|
| , m_firstLargeObject(nullptr)
|
| , m_firstUnsweptPage(nullptr)
|
| @@ -606,6 +641,10 @@ void ThreadHeap::setAllocationPoint(Address point, size_t size)
|
| ASSERT(size <= static_cast<HeapPage*>(page)->payloadSize());
|
| }
|
| #endif
|
| +#if ENABLE(GC_PROFILE_FREE_LIST)
|
| + m_allocationPointSizeSum += size;
|
| + ++m_setAllocationPointCount;
|
| +#endif
|
| if (hasCurrentAllocationArea())
|
| addToFreeList(currentAllocationPoint(), remainingAllocationSize());
|
| updateRemainingAllocationSize();
|
| @@ -615,6 +654,9 @@ void ThreadHeap::setAllocationPoint(Address point, size_t size)
|
|
|
| Address ThreadHeap::outOfLineAllocate(size_t allocationSize, size_t gcInfoIndex)
|
| {
|
| +#if ENABLE(GC_PROFILE_FREE_LIST)
|
| + m_threadState->snapshotFreeListIfNecessary();
|
| +#endif
|
| ASSERT(allocationSize > remainingAllocationSize());
|
| ASSERT(allocationSize >= allocationGranularity);
|
|
|
| @@ -857,7 +899,9 @@ static bool isLargeObjectAligned(LargeObject* largeObject, Address address)
|
| // for the guard page).
|
| return reinterpret_cast<Address>(largeObject) - WTF::kSystemPageSize == roundToBlinkPageStart(reinterpret_cast<Address>(largeObject));
|
| }
|
| +#endif
|
|
|
| +#if ENABLE(ASSERT) || ENABLE(GC_PROFILE_MARKING)
|
| BaseHeapPage* ThreadHeap::findPageFromAddress(Address address)
|
| {
|
| for (HeapPage* page = m_firstPage; page; page = page->next()) {
|
| @@ -882,6 +926,44 @@ BaseHeapPage* ThreadHeap::findPageFromAddress(Address address)
|
| }
|
| #endif
|
|
|
| +#if ENABLE(GC_PROFILE_FREE_LIST)
|
| +void ThreadHeap::snapshotFreeList(TracedValue* json)
|
| +{
|
| + json->setDouble("totalAllocationSize", m_totalAllocationSize);
|
| + json->setDouble("inlineAllocationRate", static_cast<double>(m_inlineAllocationCount) / m_allocationCount);
|
| + json->setInteger("inlineAllocationCount", m_inlineAllocationCount);
|
| + json->setInteger("allocationCount", m_allocationCount);
|
| + if (m_setAllocationPointCount > 0) {
|
| + json->setDouble("averageAllocationPointSize", static_cast<double>(m_allocationPointSizeSum) / m_setAllocationPointCount);
|
| + }
|
| + m_allocationPointSizeSum = 0;
|
| + m_setAllocationPointCount = 0;
|
| + size_t pageCount = 0;
|
| + size_t totalPageSize = 0;
|
| + for (HeapPage* page = m_firstPage; page; page = page->next()) {
|
| + ++pageCount;
|
| + totalPageSize += page->payloadSize();
|
| + }
|
| + json->setInteger("pageCount", pageCount);
|
| + json->setInteger("totalPageSize", totalPageSize);
|
| + size_t bucketSizes[blinkPageSizeLog2];
|
| + size_t bucketTotalSizes[blinkPageSizeLog2];
|
| + size_t freeSize = 0;
|
| + m_freeList.countBucketSizes(bucketSizes, bucketTotalSizes, &freeSize);
|
| + json->setInteger("freeSize", freeSize);
|
| + json->beginArray("bucketSizes");
|
| + for (size_t i = 0; i < blinkPageSizeLog2; ++i) {
|
| + json->pushInteger(bucketSizes[i]);
|
| + }
|
| + json->endArray();
|
| + json->beginArray("bucketTotalSizes");
|
| + for (size_t i = 0; i < blinkPageSizeLog2; ++i) {
|
| + json->pushInteger(bucketTotalSizes[i]);
|
| + }
|
| + json->endArray();
|
| +}
|
| +#endif
|
| +
|
| #if ENABLE(GC_PROFILE_HEAP)
|
| #define GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD 0
|
| void ThreadHeap::snapshot(TracedValue* json, ThreadState::SnapshotInfo* info)
|
| @@ -949,6 +1031,24 @@ void FreeList::addToFreeList(Address address, size_t size)
|
| m_biggestFreeListIndex = index;
|
| }
|
|
|
| +#if ENABLE(GC_PROFILE_FREE_LIST)
|
| +void FreeList::countBucketSizes(size_t sizes[], size_t totalSizes[], size_t* freeSize) const
|
| +{
|
| + *freeSize = 0;
|
| + for (size_t i = 0; i < blinkPageSizeLog2; i++) {
|
| + sizes[i] = 0;
|
| + totalSizes[i] = 0;
|
| + FreeListEntry* entry = m_freeLists[i];
|
| + while (entry) {
|
| + ++sizes[i];
|
| + *freeSize += entry->size();
|
| + totalSizes[i] += entry->size();
|
| + entry = entry->next();
|
| + }
|
| + }
|
| +}
|
| +#endif
|
| +
|
| bool ThreadHeap::expandObject(HeapObjectHeader* header, size_t newSize)
|
| {
|
| // It's possible that Vector requests a smaller expanded size because
|
| @@ -1762,6 +1862,32 @@ size_t LargeObject::objectPayloadSizeForTesting()
|
| return payloadSize();
|
| }
|
|
|
| +void HeapPage::countUnmarkedObjects()
|
| +{
|
| + MutexLocker locker(uomMutex());
|
| + for (Address headerAddress = payload(); headerAddress < payloadEnd(); ) {
|
| + HeapObjectHeader* header = reinterpret_cast<HeapObjectHeader*>(headerAddress);
|
| + ASSERT(header->size() < blinkPagePayloadSize());
|
| +
|
| + if (!header->isFree() && !header->isMarked()) {
|
| + String className(classOf(header->payload()));
|
| + ObjectAgeMap::AddResult result = uom().add(className, AgeHistogram());
|
| + result.storedValue->value.data[header->age()]++;
|
| + }
|
| + headerAddress += header->size();
|
| + }
|
| +}
|
| +
|
| +#if ENABLE(GC_PROFILE_MARKING)
|
| +const GCInfo* LargeObject::findGCInfo(Address address)
|
| +{
|
| + if (!containedInObjectPayload(address))
|
| + return nullptr;
|
| + HeapObjectHeader* header = heapObjectHeader();
|
| + return Heap::gcInfo(header->gcInfoIndex());
|
| +}
|
| +#endif
|
| +
|
| #if ENABLE(GC_PROFILE_HEAP)
|
| void LargeObject::snapshot(TracedValue* json, ThreadState::SnapshotInfo* info)
|
| {
|
| @@ -1921,7 +2047,7 @@ public:
|
| void reportStats()
|
| {
|
| fprintf(stderr, "\n---------- AFTER MARKING -------------------\n");
|
| - for (LiveObjectMap::iterator it = currentlyLive().begin(), end = currentlyLive().payloadEnd(); it != end; ++it) {
|
| + for (LiveObjectMap::iterator it = currentlyLive().begin(), end = currentlyLive().end(); it != end; ++it) {
|
| fprintf(stderr, "%s %u", it->key.ascii().data(), it->value.size());
|
|
|
| if (it->key == "blink::Document")
|
| @@ -1938,13 +2064,28 @@ public:
|
| }
|
| }
|
|
|
| + void reportMarkingStats()
|
| + {
|
| + MutexLocker locker(momMutex());
|
| + RefPtr<TracedValue> json = TracedValue::create();
|
| + for (ObjectAgeMap::iterator it = mom().begin(), end = mom().end(); it != end; ++it) {
|
| + json->beginArray(it->key.ascii().data());
|
| + for (size_t i = 0; i < 8; ++i) {
|
| + json->pushInteger(it->value.data[i]);
|
| + }
|
| + json->endArray();
|
| + }
|
| + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID("blink_gc", "MarkingStats", (unsigned long long)0, json.release());
|
| + mom().clear();
|
| + }
|
| +
|
| static void reportStillAlive(LiveObjectSet current, LiveObjectSet previous)
|
| {
|
| int count = 0;
|
|
|
| fprintf(stderr, " [previously %u]", previous.size());
|
| for (uintptr_t object : current) {
|
| - if (previous.find(object) == previous.payloadEnd())
|
| + if (previous.find(object) == previous.end())
|
| continue;
|
| count++;
|
| }
|
| @@ -1954,7 +2095,7 @@ public:
|
|
|
| fprintf(stderr, " {survived 2GCs %d: ", count);
|
| for (uintptr_t object : current) {
|
| - if (previous.find(object) == previous.payloadEnd())
|
| + if (previous.find(object) == previous.end())
|
| continue;
|
| fprintf(stderr, "%ld", object);
|
| if (--count)
|
| @@ -1967,10 +2108,10 @@ public:
|
| static void dumpPathToObjectFromObjectGraph(const ObjectGraph& graph, uintptr_t target)
|
| {
|
| ObjectGraph::const_iterator it = graph.find(target);
|
| - if (it == graph.payloadEnd())
|
| + if (it == graph.end())
|
| return;
|
| fprintf(stderr, "Path to %lx of %s\n", target, classOf(reinterpret_cast<const void*>(target)).ascii().data());
|
| - while (it != graph.payloadEnd()) {
|
| + while (it != graph.end()) {
|
| fprintf(stderr, "<- %lx of %s\n", it->value.first, it->value.second.utf8().data());
|
| it = graph.find(it->value.first);
|
| }
|
| @@ -2284,6 +2425,21 @@ void Heap::preGC()
|
| state->preGC();
|
| }
|
|
|
| +void Heap::reportSweepingStats()
|
| +{
|
| + MutexLocker locker(uomMutex());
|
| + RefPtr<TracedValue> json = TracedValue::create();
|
| + for (ObjectAgeMap::iterator it = uom().begin(), end = uom().end(); it != end; ++it) {
|
| + json->beginArray(it->key.ascii().data());
|
| + for (size_t i = 0; i < 8; ++i) {
|
| + json->pushInteger(it->value.data[i]);
|
| + }
|
| + json->endArray();
|
| + }
|
| + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID("blink_gc", "SweepingStats", (unsigned long long)0, json.release());
|
| + uom().clear();
|
| +}
|
| +
|
| void Heap::postGC(ThreadState::GCType gcType)
|
| {
|
| ASSERT(ThreadState::current()->isInGC());
|
| @@ -2296,6 +2452,10 @@ void Heap::collectGarbage(ThreadState::StackState stackState, ThreadState::GCTyp
|
| ThreadState* state = ThreadState::current();
|
| state->setGCState(ThreadState::StoppingOtherThreads);
|
|
|
| +#if ENABLE(GC_PROFILE_FREE_LIST)
|
| + state->snapshotFreeListIfNecessary();
|
| +#endif
|
| +
|
| GCScope gcScope(stackState);
|
| // Check if we successfully parked the other threads. If not we bail out of
|
| // the GC.
|
| @@ -2357,7 +2517,8 @@ void Heap::collectGarbage(ThreadState::StackState stackState, ThreadState::GCTyp
|
| postGC(gcType);
|
|
|
| #if ENABLE(GC_PROFILE_MARKING)
|
| - static_cast<MarkingVisitor<GlobalMarking>*>(s_markingVisitor)->reportStats();
|
| + //static_cast<MarkingVisitor<GlobalMarking>*>(s_markingVisitor)->reportStats();
|
| + static_cast<MarkingVisitor<GlobalMarking>*>(s_markingVisitor)->reportMarkingStats();
|
| #endif
|
|
|
| if (Platform::current()) {
|
|
|