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..6fbab864188d7b1ccd47c13397df6937bc5711b8 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,29 @@ 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) { |
| + 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 +701,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 +2508,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 +2535,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; |
| @@ -2662,7 +2705,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 +2726,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 +2746,100 @@ static void WriteUChar(OutputStreamWriter* w, unibrow::uchar u) { |
| } |
| +void HeapSnapshotJSONSerializer::SerializeTraceTree() { |
| + AllocationTracker* tracker = snapshot_->collection()->allocation_tracker(); |
| + if (!tracker) return; |
| + AllocationTraceTree* traces = tracker->trace_tree(); |
| + 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; |
|
Hannes Payer (out of office)
2013/10/21 09:57:22
Why don't you define this constant in the header a
yurys
2013/10/21 15:07:56
Not sure I follow you here, this constant is used
|
| + EmbeddedVector<char, kBufferSize> buffer; |
| + 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(']'); |
| +} |
| + |
| + |
| +// 0-based position is converted to 1-based during the serialization. |
| +static int SerializePosition(int position, const Vector<char>& buffer, |
| + int buffer_pos) { |
| + if (position == -1) { |
| + buffer[buffer_pos++] = '0'; |
| + } else { |
| + ASSERT(position >= 0); |
| + buffer_pos = utoa(static_cast<unsigned>(position + 1), 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; |
|
Hannes Payer (out of office)
2013/10/21 09:57:22
Same here.
|
| + 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('\"'); |