Chromium Code Reviews| Index: src/heap-snapshot-generator.cc |
| diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc |
| index 444bebf8917405aacb2ea7b185b0d890492fb748..00bca3c5b7bdcf3d6f88db5ca71273537006150a 100644 |
| --- a/src/heap-snapshot-generator.cc |
| +++ b/src/heap-snapshot-generator.cc |
| @@ -29,6 +29,7 @@ |
| #include "heap-snapshot-generator-inl.h" |
| +#include "allocation-tracker.h" |
| #include "heap-profiler.h" |
| #include "debug.h" |
| #include "types.h" |
| @@ -634,10 +635,30 @@ static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) { |
| HeapSnapshotsCollection::~HeapSnapshotsCollection() { |
| + delete allocation_tracker_; |
| snapshots_.Iterate(DeleteHeapSnapshot); |
| } |
| +void HeapSnapshotsCollection::StartHeapObjectsTracking() { |
| + ids_.UpdateHeapObjectsMap(); |
| + if (allocation_tracker_ == NULL) { |
| + allocation_tracker_ = new AllocationTracker(&ids_, names()); |
| + } |
| + is_tracking_objects_ = true; |
| +} |
| + |
| + |
| +void HeapSnapshotsCollection::StopHeapObjectsTracking() { |
| + ids_.StopHeapObjectsTracking(); |
| + if (allocation_tracker_ != NULL) { |
| + allocation_tracker_->allocation_traces()->Print(); |
| + delete allocation_tracker_; |
| + allocation_tracker_ = NULL; |
| + } |
| +} |
| + |
| + |
| HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(const char* name, |
| unsigned uid) { |
| is_tracking_objects_ = true; // Start watching for heap objects moves. |
| @@ -681,6 +702,15 @@ Handle<HeapObject> HeapSnapshotsCollection::FindHeapObjectById( |
| } |
| +void HeapSnapshotsCollection::NewObjectEvent(Address addr, int size) { |
| + DisallowHeapAllocation no_allocation; |
| + ids_.NewObject(addr, size); |
| + if (allocation_tracker_ != NULL) { |
| + allocation_tracker_->NewObjectEvent(addr, size); |
| + } |
| +} |
| + |
| + |
| size_t HeapSnapshotsCollection::GetUsedMemorySize() const { |
| size_t size = sizeof(*this); |
| size += names_.GetUsedMemorySize(); |
| @@ -2479,6 +2509,10 @@ const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3; |
| const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 5; |
| void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { |
| + if (AllocationTracker* allocation_tracker = |
| + snapshot_->collection()->allocation_tracker()) { |
| + allocation_tracker->PrepareForSerialization(); |
| + } |
| ASSERT(writer_ == NULL); |
| writer_ = new OutputStreamWriter(stream); |
| SerializeImpl(); |
| @@ -2502,6 +2536,16 @@ void HeapSnapshotJSONSerializer::SerializeImpl() { |
| SerializeEdges(); |
| if (writer_->aborted()) return; |
| writer_->AddString("],\n"); |
| + |
| + writer_->AddString("\"trace_function_infos\":["); |
| + SerializeTraceNodeInfos(); |
| + if (writer_->aborted()) return; |
| + writer_->AddString("],\n"); |
| + writer_->AddString("\"trace_tree\":["); |
| + SerializeTraceTree(); |
| + if (writer_->aborted()) return; |
| + writer_->AddString("],\n"); |
| + |
| writer_->AddString("\"strings\":["); |
| SerializeStrings(); |
| if (writer_->aborted()) return; |
| @@ -2512,6 +2556,7 @@ void HeapSnapshotJSONSerializer::SerializeImpl() { |
| int HeapSnapshotJSONSerializer::GetStringId(const char* s) { |
| + if (s == NULL) s = ""; |
| HashMap::Entry* cache_entry = strings_.Lookup( |
| const_cast<char*>(s), StringHash(s), true); |
| if (cache_entry->value == NULL) { |
| @@ -2662,7 +2707,20 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { |
| JSON_S("shortcut") "," |
| JSON_S("weak")) "," |
| JSON_S("string_or_number") "," |
| - JSON_S("node")))); |
| + JSON_S("node")) "," |
| + JSON_S("trace_function_info_fields") ":" JSON_A( |
| + JSON_S("function_id") "," |
| + JSON_S("name") "," |
| + JSON_S("script_name") "," |
| + JSON_S("script_id") "," |
| + JSON_S("line") "," |
| + JSON_S("column")) "," |
| + JSON_S("trace_node_fields") ":" JSON_A( |
| + JSON_S("id") "," |
| + JSON_S("function_id") "," |
| + JSON_S("count") "," |
| + JSON_S("size") "," |
| + JSON_S("children")))); |
| #undef JSON_S |
| #undef JSON_O |
| #undef JSON_A |
| @@ -2670,6 +2728,13 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { |
| writer_->AddNumber(snapshot_->entries().length()); |
| writer_->AddString(",\"edge_count\":"); |
| writer_->AddNumber(snapshot_->edges().length()); |
| + writer_->AddString(",\"trace_function_count\":"); |
| + uint32_t count = 0; |
| + AllocationTracker* tracker = snapshot_->collection()->allocation_tracker(); |
| + if (tracker) { |
| + count = tracker->id_to_function_info()->occupancy(); |
| + } |
| + writer_->AddNumber(count); |
| } |
| @@ -2683,6 +2748,99 @@ static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) { |
| } |
| +void HeapSnapshotJSONSerializer::SerializeTraceTree() { |
| + AllocationTracker* tracker = snapshot_->collection()->allocation_tracker(); |
| + if (!tracker) return; |
| + AllocationTraceTree* traces = tracker->allocation_traces(); |
| + SerializeTraceNode(traces->root()); |
| +} |
| + |
| + |
| +void HeapSnapshotJSONSerializer::SerializeTraceNode(AllocationTraceNode* node) { |
| + // The buffer needs space for 4 unsigned ints, 4 commas, [ and \0 |
| + const int kBufferSize = |
| + 4 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT |
| + + 4 + 1 + 1; |
| + EmbeddedVector<char, kBufferSize> buffer; |
|
loislo
2013/10/16 15:14:08
looks like you missed tracker check here.
yurys
2013/10/17 15:27:35
The check is performed in its caller SerializeTrac
|
| + int buffer_pos = 0; |
| + buffer_pos = utoa(node->id(), buffer, buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + buffer_pos = utoa(node->function_id(), buffer, buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + buffer_pos = utoa(node->allocation_count(), buffer, buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + buffer_pos = utoa(node->allocation_size(), buffer, buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + buffer[buffer_pos++] = '['; |
| + buffer[buffer_pos++] = '\0'; |
| + writer_->AddString(buffer.start()); |
| + |
| + Vector<AllocationTraceNode*> children = node->children(); |
| + for (int i = 0; i < children.length(); i++) { |
| + if (i > 0) { |
| + writer_->AddCharacter(','); |
| + } |
| + SerializeTraceNode(children[i]); |
| + } |
| + writer_->AddCharacter(']'); |
| +} |
| + |
| + |
| +static int SerializePosition(int position, const Vector<char>& buffer, |
| + int buffer_pos) { |
| + if (position == -1) { |
| + // FIXME: serialize sifned int. |
| + buffer[buffer_pos++] = '0'; |
| + } else { |
| + ASSERT(position >= 0); |
| + buffer_pos = utoa(static_cast<unsigned>(position), buffer, buffer_pos); |
| + } |
| + return buffer_pos; |
| +} |
| + |
| +void HeapSnapshotJSONSerializer::SerializeTraceNodeInfos() { |
| + AllocationTracker* tracker = snapshot_->collection()->allocation_tracker(); |
| + if (!tracker) return; |
| + // The buffer needs space for 6 unsigned ints, 6 commas, \n and \0 |
| + const int kBufferSize = |
| + 6 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT |
| + + 6 + 1 + 1; |
| + EmbeddedVector<char, kBufferSize> buffer; |
| + HashMap* id_to_function_info = tracker->id_to_function_info(); |
| + bool first_entry = true; |
| + for (HashMap::Entry* p = id_to_function_info->Start(); |
| + p != NULL; |
| + p = id_to_function_info->Next(p)) { |
| + SnapshotObjectId id = |
| + static_cast<SnapshotObjectId>(reinterpret_cast<intptr_t>(p->key)); |
| + AllocationTracker::FunctionInfo* info = |
| + reinterpret_cast<AllocationTracker::FunctionInfo* >(p->value); |
| + int buffer_pos = 0; |
| + if (first_entry) { |
| + first_entry = false; |
| + } else { |
| + buffer[buffer_pos++] = ','; |
| + } |
| + buffer_pos = utoa(id, buffer, buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + buffer_pos = utoa(GetStringId(info->name), buffer, buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + buffer_pos = utoa(GetStringId(info->script_name), buffer, buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + // The cast is safe because script id is a non-negative Smi. |
| + buffer_pos = utoa(static_cast<unsigned>(info->script_id), buffer, |
| + buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + buffer_pos = SerializePosition(info->line, buffer, buffer_pos); |
| + buffer[buffer_pos++] = ','; |
| + buffer_pos = SerializePosition(info->column, buffer, buffer_pos); |
| + buffer[buffer_pos++] = '\n'; |
| + buffer[buffer_pos++] = '\0'; |
| + writer_->AddString(buffer.start()); |
| + } |
| +} |
| + |
| + |
| void HeapSnapshotJSONSerializer::SerializeString(const unsigned char* s) { |
| writer_->AddCharacter('\n'); |
| writer_->AddCharacter('\"'); |