Index: Source/platform/heap/Heap.cpp |
diff --git a/Source/platform/heap/Heap.cpp b/Source/platform/heap/Heap.cpp |
index 4062e5c03157ee62d0fb62a1e211b63410917618..111562a5ce26c4e116118796c3a6c9f0b8a67811 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 ENABLE(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 ENABLE(GC_PROFILE_HEAP) |
+#include "platform/TracedValue.h" |
+#endif |
#if OS(POSIX) |
#include <sys/mman.h> |
@@ -57,7 +60,7 @@ |
namespace blink { |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
static String classOf(const void* object) |
{ |
const GCInfo* gcInfo = Heap::findGCInfo(reinterpret_cast<Address>(const_cast<void*>(object))); |
@@ -369,10 +372,10 @@ public: |
, m_safePointScope(stackState) |
, m_parkedAllThreads(false) |
{ |
- TRACE_EVENT0("blink", "Heap::GCScope"); |
+ TRACE_EVENT0("blink_gc", "Heap::GCScope"); |
const char* samplingState = TRACE_EVENT_GET_SAMPLING_STATE(); |
if (m_state->isMainThread()) |
- TRACE_EVENT_SET_SAMPLING_STATE("blink", "BlinkGCWaiting"); |
+ TRACE_EVENT_SET_SAMPLING_STATE("blink_gc", "BlinkGCWaiting"); |
m_state->checkThread(); |
@@ -512,7 +515,7 @@ void LargeHeapObject<Header>::checkAndMarkPointer(Visitor* visitor, Address addr |
ASSERT(contains(address)); |
if (!objectContains(address) || heapObjectHeader()->hasDeadMark()) |
return; |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
visitor->setHostInfo(&address, "stack"); |
#endif |
mark(visitor); |
@@ -662,7 +665,7 @@ BaseHeapPage* ThreadHeap<Header>::heapPageFromAddress(Address address) |
return 0; |
} |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
template<typename Header> |
const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address) |
{ |
@@ -674,6 +677,39 @@ const GCInfo* ThreadHeap<Header>::findGCInfoOfLargeHeapObject(Address address) |
} |
#endif |
+#if ENABLE(GC_PROFILE_HEAP) |
+#define GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD 0 |
+template<typename Header> |
+void ThreadHeap<Header>::snapshot(TracedValue* json, ThreadState::SnapshotInfo* info) |
+{ |
+ size_t previousPageCount = info->pageCount; |
+ |
+ 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. |
+ if (info->pageCount < GC_PROFILE_HEAP_PAGE_SNAPSHOT_THRESHOLD) { |
+ json->beginArray(); |
+ json->pushInteger(reinterpret_cast<intptr_t>(page)); |
+ page->snapshot(json, info); |
+ json->endArray(); |
+ } else { |
+ page->snapshot(0, info); |
+ } |
+ } |
+ json->endArray(); |
+ |
+ json->beginArray("largeObjects"); |
+ for (LargeHeapObject<Header>* current = m_firstLargeHeapObject; current; current = current->next()) { |
+ json->beginDictionary(); |
+ current->snapshot(json, info); |
+ json->endDictionary(); |
+ } |
+ json->endArray(); |
+ |
+ json->setInteger("pageCount", info->pageCount - previousPageCount); |
+} |
+#endif |
+ |
template<typename Header> |
void ThreadHeap<Header>::addToFreeList(Address address, size_t size) |
{ |
@@ -1323,7 +1359,7 @@ void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
if (!header || header->hasDeadMark()) |
return; |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
visitor->setHostInfo(&address, "stack"); |
#endif |
if (hasVTable(header) && !vTableInitialized(header->payload())) |
@@ -1332,7 +1368,7 @@ void HeapPage<Header>::checkAndMarkPointer(Visitor* visitor, Address address) |
visitor->mark(header, traceCallback(header)); |
} |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
template<typename Header> |
const GCInfo* HeapPage<Header>::findGCInfo(Address address) |
{ |
@@ -1350,6 +1386,42 @@ const GCInfo* HeapPage<Header>::findGCInfo(Address address) |
} |
#endif |
+#if ENABLE(GC_PROFILE_HEAP) |
+template<typename Header> |
+void HeapPage<Header>::snapshot(TracedValue* 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() |
@@ -1411,6 +1483,36 @@ void LargeHeapObject<Header>::getStats(HeapStats& stats) |
stats.increaseObjectSpace(payloadSize()); |
} |
+#if ENABLE(GC_PROFILE_HEAP) |
+template<typename Header> |
+void LargeHeapObject<Header>::snapshot(TracedValue* 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 dead before the final generation. |
+ if (age < maxHeapObjectAge) |
+ info->generations[tag][age] += 1; |
+ } |
+ |
+ if (json) { |
+ json->setInteger("class", tag); |
+ json->setInteger("size", header->size()); |
+ json->setInteger("isMarked", isMarked()); |
+ } |
+} |
+#endif |
+ |
template<typename Entry> |
void HeapExtentCache<Entry>::flush() |
{ |
@@ -1549,7 +1651,7 @@ bool CallbackStack::popAndInvokeCallback(CallbackStack** first, Visitor* visitor |
// collection. However we assert it in Heap::pushWeakObjectPointerCallback. |
VisitorCallback callback = item->callback(); |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
if (ThreadState::isAnyThreadInGC()) // weak-processing will also use popAndInvokeCallback |
visitor->setHostInfo(item->object(), classOf(item->object())); |
#endif |
@@ -1624,7 +1726,7 @@ bool CallbackStack::hasCallbackForObject(const void* object) |
class MarkingVisitor : public Visitor { |
public: |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
typedef HashSet<uintptr_t> LiveObjectSet; |
typedef HashMap<String, LiveObjectSet> LiveObjectMap; |
typedef HashMap<uintptr_t, std::pair<uintptr_t, String> > ObjectGraph; |
@@ -1641,7 +1743,7 @@ public: |
if (header->isMarked()) |
return; |
header->mark(); |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
MutexLocker locker(objectGraphMutex()); |
String className(classOf(objectPointer)); |
{ |
@@ -1747,7 +1849,7 @@ public: |
FOR_EACH_TYPED_HEAP(DEFINE_VISITOR_METHODS) |
#undef DEFINE_VISITOR_METHODS |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
void reportStats() |
{ |
fprintf(stderr, "\n---------- AFTER MARKING -------------------\n"); |
@@ -1938,12 +2040,14 @@ Address Heap::checkAndMarkPointer(Visitor* visitor, Address address) |
return 0; |
} |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
const GCInfo* Heap::findGCInfo(Address address) |
{ |
return ThreadState::findGCInfoFromAllThreads(address); |
} |
+#endif |
+#if ENABLE(GC_PROFILE_MARKING) |
void Heap::dumpPathToObjectOnNextGC(void* p) |
{ |
static_cast<MarkingVisitor*>(s_markingVisitor)->dumpPathToObjectOnNextGC(p); |
@@ -2068,10 +2172,10 @@ void Heap::collectGarbage(ThreadState::StackState stackState) |
s_lastGCWasConservative = false; |
- TRACE_EVENT0("blink", "Heap::collectGarbage"); |
- TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "BlinkGC"); |
+ TRACE_EVENT0("blink_gc", "Heap::collectGarbage"); |
+ TRACE_EVENT_SCOPED_SAMPLING_STATE("blink_gc", "BlinkGC"); |
double timeStamp = WTF::currentTimeMS(); |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
static_cast<MarkingVisitor*>(s_markingVisitor)->objectGraph().clear(); |
#endif |
@@ -2109,7 +2213,7 @@ void Heap::collectGarbage(ThreadState::StackState stackState) |
// a dangling pointer. |
orphanedPagePool()->decommitOrphanedPages(); |
-#if ENABLE(GC_TRACING) |
+#if ENABLE(GC_PROFILE_MARKING) |
static_cast<MarkingVisitor*>(s_markingVisitor)->reportStats(); |
#endif |