Index: Source/platform/heap/Heap.cpp |
diff --git a/Source/platform/heap/Heap.cpp b/Source/platform/heap/Heap.cpp |
index 3f1948e6cdd9fa8424962f288b751c04f063cfbe..53defd6939fa888f8b413843d0a442528ab23bee 100644 |
--- a/Source/platform/heap/Heap.cpp |
+++ b/Source/platform/heap/Heap.cpp |
@@ -39,7 +39,7 @@ |
#include "wtf/Assertions.h" |
#include "wtf/LeakAnnotations.h" |
#include "wtf/PassOwnPtr.h" |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
#include "wtf/HashMap.h" |
#include "wtf/HashSet.h" |
#include "wtf/text/StringBuilder.h" |
@@ -47,6 +47,9 @@ |
#include <stdio.h> |
#include <utility> |
#endif |
+#if GC_PROFILE_HEAP |
+#include "platform/TracedValue.h" |
+#endif |
#if OS(POSIX) |
#include <sys/mman.h> |
@@ -57,7 +60,7 @@ |
namespace WebCore { |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
static String classOf(const void* object) |
{ |
const GCInfo* gcInfo = Heap::findGCInfo(reinterpret_cast<Address>(const_cast<void*>(object))); |
@@ -505,7 +508,7 @@ void LargeHeapObject<Header>::checkAndMarkPointer(Visitor* visitor, Address addr |
ASSERT(contains(address)); |
if (!objectContains(address)) |
return; |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
visitor->setHostInfo(&address, "stack"); |
#endif |
mark(visitor); |
@@ -641,7 +644,7 @@ BaseHeapPage* ThreadHeap<Header>::heapPageFromAddress(Address address) |
return 0; |
} |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
template<typename Header> |
const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address) |
{ |
@@ -653,6 +656,43 @@ const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address) |
} |
#endif |
+#if GC_PROFILE_HEAP |
+template<typename Header> |
+void ThreadHeap<Header>::snapshot(TracedDictionaryBase* json, ThreadState::SnapshotInfo* info) |
+{ |
+ size_t previousPageCount = info->pageCount; |
+ |
+ TracedArrayBase& pages = json->beginArray("pages"); |
+ for (HeapPage<Header>* page = m_firstPage; page; page = page->next(), ++info->pageCount) { |
+ // FIXME: To limit the size of the snapshot we only output "threshold" many page snapshots. |
+ TracedArrayBase* jsonPage = 0; |
+ if (info->pageCount < GC_PROFILE_HEAP_PAGE_DUMP_THRESHOLD) { |
+ jsonPage = &pages.beginArray(); |
+ jsonPage->pushInteger(reinterpret_cast<intptr_t>(page)); |
+ } |
+ page->snapshot(jsonPage, info); |
+ if (jsonPage) |
+ jsonPage->endArray(); |
+ } |
+ pages.endArray(); |
+ |
+ TracedArrayBase& largeObjects = json->beginArray("largeObjects"); |
+ for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next()) { |
+ TracedDictionaryBase& jsonCurrent = largeObjects.beginDictionary(); |
+ current->snapshot(&jsonCurrent, info); |
+ jsonCurrent.endDictionary(); |
+ } |
+ largeObjects.endArray(); |
+ |
+ size_t pagePoolSize = 0; |
+ for (PagePoolEntry* page = m_pagePool; page; page = page->next()) |
+ ++pagePoolSize; |
+ |
+ json->setInteger("pagePoolSize", pagePoolSize) |
+ .setInteger("pageCount", info->pageCount - previousPageCount); |
+} |
+#endif |
+ |
template<typename Header> |
void ThreadHeap<Header>::addToFreeList(Address address, size_t size) |
{ |
@@ -1201,7 +1241,7 @@ void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
if (!header) |
return; |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
visitor->setHostInfo(&address, "stack"); |
#endif |
if (hasVTable(header) && !vTableInitialized(header->payload())) |
@@ -1210,7 +1250,7 @@ void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
visitor->mark(header, traceCallback(header)); |
} |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
template<typename Header> |
const GCInfo* HeapPage<Header>::findGCInfo(Address address) |
{ |
@@ -1228,6 +1268,42 @@ const GCInfo* HeapPage<Header>::findGCInfo(Address address) |
} |
#endif |
+#if GC_PROFILE_HEAP |
+template<typename Header> |
+void HeapPage<Header>::snapshot(TracedArrayBase* json, ThreadState::SnapshotInfo* info) |
+{ |
+ Header* header = 0; |
+ for (Address addr = payload(); addr < end(); addr += header->size()) { |
+ header = reinterpret_cast<Header*>(addr); |
+ if (json) |
+ json->pushInteger(header->encodedSize()); |
+ if (header->isFree()) { |
+ info->freeSize += header->size(); |
+ continue; |
+ } |
+ |
+ size_t tag = info->getClassTag(header->gcInfo()); |
+ size_t age = header->age(); |
+ if (json) |
+ json->pushInteger(tag); |
+ if (header->isMarked()) { |
+ info->liveCount[tag] += 1; |
+ info->liveSize += header->size(); |
+ // Count objects that are live when promoted to the final generation. |
+ if (age == maxHeapObjectAge - 1) |
+ info->generations[tag][maxHeapObjectAge] += 1; |
+ header->incAge(); |
+ } else { |
+ info->deadCount[tag] += 1; |
+ info->deadSize += header->size(); |
+ // Count objects that are dead before the final generation. |
+ if (age < maxHeapObjectAge) |
+ info->generations[tag][age] += 1; |
+ } |
+ } |
+} |
+#endif |
+ |
#if defined(ADDRESS_SANITIZER) |
template<typename Header> |
void HeapPage<Header>::poisonUnmarkedObjects() |
@@ -1289,6 +1365,37 @@ void LargeHeapObject<Header>::getStats(HeapStats& stats) |
stats.increaseObjectSpace(payloadSize()); |
} |
+#if GC_PROFILE_HEAP |
+template<typename Header> |
+void LargeHeapObject<Header>::snapshot(TracedDictionaryBase* json, ThreadState::SnapshotInfo* info) |
+{ |
+ Header* header = heapObjectHeader(); |
+ size_t tag = info->getClassTag(header->gcInfo()); |
+ size_t age = header->age(); |
+ if (isMarked()) { |
+ info->liveCount[tag] += 1; |
+ info->liveSize += header->size(); |
+ // Count objects that are live when promoted to the final generation. |
+ if (age == maxHeapObjectAge - 1) |
+ info->generations[tag][maxHeapObjectAge] += 1; |
+ header->incAge(); |
+ } else { |
+ info->deadCount[tag] += 1; |
+ info->deadSize += header->size(); |
+ // Count objects that are live when promoted to the final generation. |
+ if (age == maxHeapObjectAge - 1) |
+ info->generations[tag][maxHeapObjectAge] += 1; |
+ header->incAge(); |
+ } |
+ |
+ if (json) { |
+ json->setInteger("class", tag) |
+ .setInteger("size", header->size()) |
+ .setInteger("isMarked", isMarked()); |
+ } |
+} |
+#endif |
+ |
template<typename Entry> |
void HeapExtentCache<Entry>::flush() |
{ |
@@ -1403,7 +1510,7 @@ bool CallbackStack::popAndInvokeCallback(CallbackStack** first, Visitor* visitor |
Item* item = --m_current; |
VisitorCallback callback = item->callback(); |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
if (ThreadState::isAnyThreadInGC()) // weak-processing will also use popAndInvokeCallback |
visitor->setHostInfo(item->object(), classOf(item->object())); |
#endif |
@@ -1461,7 +1568,7 @@ bool CallbackStack::hasCallbackForObject(const void* object) |
class MarkingVisitor : public Visitor { |
public: |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
typedef HashSet<uintptr_t> LiveObjectSet; |
typedef HashMap<String, LiveObjectSet> LiveObjectMap; |
typedef HashMap<uintptr_t, std::pair<uintptr_t, String> > ObjectGraph; |
@@ -1474,7 +1581,7 @@ public: |
if (header->isMarked()) |
return; |
header->mark(); |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
MutexLocker locker(objectGraphMutex()); |
String className(classOf(objectPointer)); |
{ |
@@ -1580,7 +1687,7 @@ public: |
FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS) |
#undef DEFINE_VISITOR_METHODS |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
void reportStats() |
{ |
fprintf(stderr, "\n---------- AFTER MARKING -------------------\n"); |
@@ -1758,12 +1865,14 @@ Address Heap::checkAndMarkPointer(Visitor* visitor, Address address) |
return 0; |
} |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
const GCInfo* Heap::findGCInfo(Address address) |
{ |
return ThreadState::findGCInfoFromAllThreads(address); |
} |
+#endif |
+#if GC_PROFILE_MARKING |
void Heap::dumpPathToObjectOnNextGC(void* p) |
{ |
static_cast<MarkingVisitor*>(s_markingVisitor)->dumpPathToObjectOnNextGC(p); |
@@ -1880,10 +1989,10 @@ void Heap::collectGarbage(ThreadState::StackState stackState) |
ScriptForbiddenScope forbiddenScope; |
s_lastGCWasConservative = false; |
- TRACE_EVENT0("blink", "Heap::collectGarbage"); |
- TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "BlinkGC"); |
+ TRACE_EVENT0(GC_PROFILE_GROUP, "Heap::collectGarbage"); |
+ TRACE_EVENT_SCOPED_SAMPLING_STATE(GC_PROFILE_GROUP, "BlinkGC"); |
double timeStamp = WTF::currentTimeMS(); |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
static_cast<MarkingVisitor*>(s_markingVisitor)->objectGraph().clear(); |
#endif |
@@ -1920,7 +2029,7 @@ void Heap::collectGarbage(ThreadState::StackState stackState) |
// callback phase, so the marking stack should still be empty here. |
ASSERT(s_markingStack->isEmpty()); |
-#if ENABLE(GC_TRACING) |
+#if GC_PROFILE_MARKING |
static_cast<MarkingVisitor*>(s_markingVisitor)->reportStats(); |
#endif |