| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/profiler/heap-snapshot-generator.h" | 5 #include "src/profiler/heap-snapshot-generator.h" |
| 6 | 6 |
| 7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
| 8 #include "src/conversions.h" | 8 #include "src/conversions.h" |
| 9 #include "src/debug/debug.h" | 9 #include "src/debug/debug.h" |
| 10 #include "src/objects-body-descriptors.h" | 10 #include "src/objects-body-descriptors.h" |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 snapshot_(snapshot), | 56 snapshot_(snapshot), |
| 57 name_(name), | 57 name_(name), |
| 58 id_(id), | 58 id_(id), |
| 59 trace_node_id_(trace_node_id) { } | 59 trace_node_id_(trace_node_id) { } |
| 60 | 60 |
| 61 | 61 |
| 62 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, | 62 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, |
| 63 const char* name, | 63 const char* name, |
| 64 HeapEntry* entry) { | 64 HeapEntry* entry) { |
| 65 HeapGraphEdge edge(type, name, this->index(), entry->index()); | 65 HeapGraphEdge edge(type, name, this->index(), entry->index()); |
| 66 snapshot_->edges().Add(edge); | 66 snapshot_->edges().push_back(edge); |
| 67 ++children_count_; | 67 ++children_count_; |
| 68 } | 68 } |
| 69 | 69 |
| 70 | 70 |
| 71 void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, | 71 void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, |
| 72 int index, | 72 int index, |
| 73 HeapEntry* entry) { | 73 HeapEntry* entry) { |
| 74 HeapGraphEdge edge(type, index, this->index(), entry->index()); | 74 HeapGraphEdge edge(type, index, this->index(), entry->index()); |
| 75 snapshot_->edges().Add(edge); | 75 snapshot_->edges().push_back(edge); |
| 76 ++children_count_; | 76 ++children_count_; |
| 77 } | 77 } |
| 78 | 78 |
| 79 | 79 |
| 80 void HeapEntry::Print( | 80 void HeapEntry::Print( |
| 81 const char* prefix, const char* edge_name, int max_depth, int indent) { | 81 const char* prefix, const char* edge_name, int max_depth, int indent) { |
| 82 STATIC_ASSERT(sizeof(unsigned) == sizeof(id())); | 82 STATIC_ASSERT(sizeof(unsigned) == sizeof(id())); |
| 83 base::OS::Print("%6" PRIuS " @%6u %*c %s%s: ", self_size(), id(), indent, ' ', | 83 base::OS::Print("%6" PRIuS " @%6u %*c %s%s: ", self_size(), id(), indent, ' ', |
| 84 prefix, edge_name); | 84 prefix, edge_name); |
| 85 if (type() != kString) { | 85 if (type() != kString) { |
| 86 base::OS::Print("%s %.40s\n", TypeAsString(), name_); | 86 base::OS::Print("%s %.40s\n", TypeAsString(), name_); |
| 87 } else { | 87 } else { |
| 88 base::OS::Print("\""); | 88 base::OS::Print("\""); |
| 89 const char* c = name_; | 89 const char* c = name_; |
| 90 while (*c && (c - name_) <= 40) { | 90 while (*c && (c - name_) <= 40) { |
| 91 if (*c != '\n') | 91 if (*c != '\n') |
| 92 base::OS::Print("%c", *c); | 92 base::OS::Print("%c", *c); |
| 93 else | 93 else |
| 94 base::OS::Print("\\n"); | 94 base::OS::Print("\\n"); |
| 95 ++c; | 95 ++c; |
| 96 } | 96 } |
| 97 base::OS::Print("\"\n"); | 97 base::OS::Print("\"\n"); |
| 98 } | 98 } |
| 99 if (--max_depth == 0) return; | 99 if (--max_depth == 0) return; |
| 100 Vector<HeapGraphEdge*> ch = children(); | 100 for (auto i = children_begin(); i != children_end(); ++i) { |
| 101 for (int i = 0; i < ch.length(); ++i) { | 101 HeapGraphEdge& edge = **i; |
| 102 HeapGraphEdge& edge = *ch[i]; | |
| 103 const char* edge_prefix = ""; | 102 const char* edge_prefix = ""; |
| 104 EmbeddedVector<char, 64> index; | 103 EmbeddedVector<char, 64> index; |
| 105 const char* edge_name = index.start(); | 104 const char* edge_name = index.start(); |
| 106 switch (edge.type()) { | 105 switch (edge.type()) { |
| 107 case HeapGraphEdge::kContextVariable: | 106 case HeapGraphEdge::kContextVariable: |
| 108 edge_prefix = "#"; | 107 edge_prefix = "#"; |
| 109 edge_name = edge.name(); | 108 edge_name = edge.name(); |
| 110 break; | 109 break; |
| 111 case HeapGraphEdge::kElement: | 110 case HeapGraphEdge::kElement: |
| 112 SNPrintF(index, "%d", edge.index()); | 111 SNPrintF(index, "%d", edge.index()); |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 SnapshotObjectId id, | 262 SnapshotObjectId id, |
| 264 size_t size, | 263 size_t size, |
| 265 unsigned trace_node_id) { | 264 unsigned trace_node_id) { |
| 266 HeapEntry entry(this, type, name, id, size, trace_node_id); | 265 HeapEntry entry(this, type, name, id, size, trace_node_id); |
| 267 entries_.Add(entry); | 266 entries_.Add(entry); |
| 268 return &entries_.last(); | 267 return &entries_.last(); |
| 269 } | 268 } |
| 270 | 269 |
| 271 | 270 |
| 272 void HeapSnapshot::FillChildren() { | 271 void HeapSnapshot::FillChildren() { |
| 273 DCHECK(children().is_empty()); | 272 DCHECK(children().empty()); |
| 274 children().Allocate(edges().length()); | 273 children().resize(edges().size()); |
| 275 int children_index = 0; | 274 int children_index = 0; |
| 276 for (int i = 0; i < entries().length(); ++i) { | 275 for (int i = 0; i < entries().length(); ++i) { |
| 277 HeapEntry* entry = &entries()[i]; | 276 HeapEntry* entry = &entries()[i]; |
| 278 children_index = entry->set_children_index(children_index); | 277 children_index = entry->set_children_index(children_index); |
| 279 } | 278 } |
| 280 DCHECK(edges().length() == children_index); | 279 DCHECK_EQ(edges().size(), static_cast<size_t>(children_index)); |
| 281 for (int i = 0; i < edges().length(); ++i) { | 280 for (size_t i = 0; i < edges().size(); ++i) { |
| 282 HeapGraphEdge* edge = &edges()[i]; | 281 HeapGraphEdge* edge = &edges()[i]; |
| 283 edge->ReplaceToIndexWithEntry(this); | 282 edge->ReplaceToIndexWithEntry(this); |
| 284 edge->from()->add_child(edge); | 283 edge->from()->add_child(edge); |
| 285 } | 284 } |
| 286 } | 285 } |
| 287 | 286 |
| 288 | 287 |
| 289 class FindEntryById { | 288 class FindEntryById { |
| 290 public: | 289 public: |
| 291 explicit FindEntryById(SnapshotObjectId id) : id_(id) { } | 290 explicit FindEntryById(SnapshotObjectId id) : id_(id) { } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 return &sorted_entries_; | 327 return &sorted_entries_; |
| 329 } | 328 } |
| 330 | 329 |
| 331 | 330 |
| 332 void HeapSnapshot::Print(int max_depth) { | 331 void HeapSnapshot::Print(int max_depth) { |
| 333 root()->Print("", "", max_depth, 0); | 332 root()->Print("", "", max_depth, 0); |
| 334 } | 333 } |
| 335 | 334 |
| 336 | 335 |
| 337 size_t HeapSnapshot::RawSnapshotSize() const { | 336 size_t HeapSnapshot::RawSnapshotSize() const { |
| 338 return | 337 return sizeof(*this) + GetMemoryUsedByList(entries_) + |
| 339 sizeof(*this) + | 338 edges_.size() * sizeof(decltype(edges_)::value_type) + |
| 340 GetMemoryUsedByList(entries_) + | 339 children_.size() * sizeof(decltype(children_)::value_type) + |
| 341 GetMemoryUsedByList(edges_) + | 340 GetMemoryUsedByList(sorted_entries_); |
| 342 GetMemoryUsedByList(children_) + | |
| 343 GetMemoryUsedByList(sorted_entries_); | |
| 344 } | 341 } |
| 345 | 342 |
| 346 | 343 |
| 347 // We split IDs on evens for embedder objects (see | 344 // We split IDs on evens for embedder objects (see |
| 348 // HeapObjectsMap::GenerateId) and odds for native objects. | 345 // HeapObjectsMap::GenerateId) and odds for native objects. |
| 349 const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1; | 346 const SnapshotObjectId HeapObjectsMap::kInternalRootObjectId = 1; |
| 350 const SnapshotObjectId HeapObjectsMap::kGcRootsObjectId = | 347 const SnapshotObjectId HeapObjectsMap::kGcRootsObjectId = |
| 351 HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep; | 348 HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep; |
| 352 const SnapshotObjectId HeapObjectsMap::kGcRootsFirstSubrootId = | 349 const SnapshotObjectId HeapObjectsMap::kGcRootsFirstSubrootId = |
| 353 HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep; | 350 HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep; |
| (...skipping 2436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2790 buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos); | 2787 buffer_pos = utoa(edge_name_or_index, buffer, buffer_pos); |
| 2791 buffer[buffer_pos++] = ','; | 2788 buffer[buffer_pos++] = ','; |
| 2792 buffer_pos = utoa(entry_index(edge->to()), buffer, buffer_pos); | 2789 buffer_pos = utoa(entry_index(edge->to()), buffer, buffer_pos); |
| 2793 buffer[buffer_pos++] = '\n'; | 2790 buffer[buffer_pos++] = '\n'; |
| 2794 buffer[buffer_pos++] = '\0'; | 2791 buffer[buffer_pos++] = '\0'; |
| 2795 writer_->AddString(buffer.start()); | 2792 writer_->AddString(buffer.start()); |
| 2796 } | 2793 } |
| 2797 | 2794 |
| 2798 | 2795 |
| 2799 void HeapSnapshotJSONSerializer::SerializeEdges() { | 2796 void HeapSnapshotJSONSerializer::SerializeEdges() { |
| 2800 List<HeapGraphEdge*>& edges = snapshot_->children(); | 2797 std::deque<HeapGraphEdge*>& edges = snapshot_->children(); |
| 2801 for (int i = 0; i < edges.length(); ++i) { | 2798 for (size_t i = 0; i < edges.size(); ++i) { |
| 2802 DCHECK(i == 0 || | 2799 DCHECK(i == 0 || |
| 2803 edges[i - 1]->from()->index() <= edges[i]->from()->index()); | 2800 edges[i - 1]->from()->index() <= edges[i]->from()->index()); |
| 2804 SerializeEdge(edges[i], i == 0); | 2801 SerializeEdge(edges[i], i == 0); |
| 2805 if (writer_->aborted()) return; | 2802 if (writer_->aborted()) return; |
| 2806 } | 2803 } |
| 2807 } | 2804 } |
| 2808 | 2805 |
| 2809 | 2806 |
| 2810 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { | 2807 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { |
| 2811 // The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n and \0 | 2808 // The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n and \0 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2909 JSON_S("children")) "," | 2906 JSON_S("children")) "," |
| 2910 JSON_S("sample_fields") ":" JSON_A( | 2907 JSON_S("sample_fields") ":" JSON_A( |
| 2911 JSON_S("timestamp_us") "," | 2908 JSON_S("timestamp_us") "," |
| 2912 JSON_S("last_assigned_id")))); | 2909 JSON_S("last_assigned_id")))); |
| 2913 #undef JSON_S | 2910 #undef JSON_S |
| 2914 #undef JSON_O | 2911 #undef JSON_O |
| 2915 #undef JSON_A | 2912 #undef JSON_A |
| 2916 writer_->AddString(",\"node_count\":"); | 2913 writer_->AddString(",\"node_count\":"); |
| 2917 writer_->AddNumber(snapshot_->entries().length()); | 2914 writer_->AddNumber(snapshot_->entries().length()); |
| 2918 writer_->AddString(",\"edge_count\":"); | 2915 writer_->AddString(",\"edge_count\":"); |
| 2919 writer_->AddNumber(snapshot_->edges().length()); | 2916 writer_->AddNumber(static_cast<double>(snapshot_->edges().size())); |
| 2920 writer_->AddString(",\"trace_function_count\":"); | 2917 writer_->AddString(",\"trace_function_count\":"); |
| 2921 uint32_t count = 0; | 2918 uint32_t count = 0; |
| 2922 AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker(); | 2919 AllocationTracker* tracker = snapshot_->profiler()->allocation_tracker(); |
| 2923 if (tracker) { | 2920 if (tracker) { |
| 2924 count = tracker->function_info_list().length(); | 2921 count = tracker->function_info_list().length(); |
| 2925 } | 2922 } |
| 2926 writer_->AddNumber(count); | 2923 writer_->AddNumber(count); |
| 2927 } | 2924 } |
| 2928 | 2925 |
| 2929 | 2926 |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3114 for (int i = 1; i < sorted_strings.length(); ++i) { | 3111 for (int i = 1; i < sorted_strings.length(); ++i) { |
| 3115 writer_->AddCharacter(','); | 3112 writer_->AddCharacter(','); |
| 3116 SerializeString(sorted_strings[i]); | 3113 SerializeString(sorted_strings[i]); |
| 3117 if (writer_->aborted()) return; | 3114 if (writer_->aborted()) return; |
| 3118 } | 3115 } |
| 3119 } | 3116 } |
| 3120 | 3117 |
| 3121 | 3118 |
| 3122 } // namespace internal | 3119 } // namespace internal |
| 3123 } // namespace v8 | 3120 } // namespace v8 |
| OLD | NEW |