Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index da2a969e7123ea132e550cee99a0df60b7a0f208..b670d4e7fb8dc0e6b88e78c3021019c3a96596a1 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -964,16 +964,10 @@ HeapEntry::HeapEntry(HeapSnapshot* snapshot, |
const char* name, |
SnapshotObjectId id, |
int self_size) |
- : painted_(false), |
- user_reachable_(false), |
- dominator_(kNoEntry), |
- type_(type), |
- retainers_count_(0), |
- retainers_index_(-1), |
+ : type_(type), |
children_count_(0), |
children_index_(-1), |
self_size_(self_size), |
- retained_size_(0), |
id_(id), |
snapshot_(snapshot), |
name_(name) { } |
@@ -985,7 +979,6 @@ void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, |
HeapGraphEdge edge(type, name, this->index(), entry->index()); |
snapshot_->edges().Add(edge); |
++children_count_; |
- ++entry->retainers_count_; |
} |
@@ -995,7 +988,6 @@ void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, |
HeapGraphEdge edge(type, index, this->index(), entry->index()); |
snapshot_->edges().Add(edge); |
++children_count_; |
- ++entry->retainers_count_; |
} |
@@ -1007,9 +999,8 @@ Handle<HeapObject> HeapEntry::GetHeapObject() { |
void HeapEntry::Print( |
const char* prefix, const char* edge_name, int max_depth, int indent) { |
STATIC_CHECK(sizeof(unsigned) == sizeof(id())); |
- OS::Print("%6d %7d @%6u %*c %s%s: ", |
- self_size(), retained_size(), id(), |
- indent, ' ', prefix, edge_name); |
+ OS::Print("%6d @%6u %*c %s%s: ", |
+ self_size(), id(), indent, ' ', prefix, edge_name); |
if (type() != kString) { |
OS::Print("%s %.40s\n", TypeAsString(), name_); |
} else { |
@@ -1091,13 +1082,13 @@ template <size_t ptr_size> struct SnapshotSizeConstants; |
template <> struct SnapshotSizeConstants<4> { |
static const int kExpectedHeapGraphEdgeSize = 12; |
- static const int kExpectedHeapEntrySize = 40; |
+ static const int kExpectedHeapEntrySize = 24; |
static const size_t kMaxSerializableSnapshotRawSize = 256 * MB; |
}; |
template <> struct SnapshotSizeConstants<8> { |
static const int kExpectedHeapGraphEdgeSize = 24; |
- static const int kExpectedHeapEntrySize = 48; |
+ static const int kExpectedHeapEntrySize = 32; |
static const uint64_t kMaxSerializableSnapshotRawSize = |
static_cast<uint64_t>(6000) * MB; |
}; |
@@ -1139,16 +1130,6 @@ void HeapSnapshot::RememberLastJSObjectId() { |
} |
-static void HeapEntryClearPaint(HeapEntry* entry_ptr) { |
- entry_ptr->clear_paint(); |
-} |
- |
- |
-void HeapSnapshot::ClearPaint() { |
- entries_.Iterate(HeapEntryClearPaint); |
-} |
- |
- |
HeapEntry* HeapSnapshot::AddRootEntry() { |
ASSERT(root_index_ == HeapEntry::kNoEntry); |
ASSERT(entries_.is_empty()); // Root entry must be the first one. |
@@ -1196,32 +1177,19 @@ HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, |
} |
-void HeapSnapshot::FillChildrenAndRetainers() { |
+void HeapSnapshot::FillChildren() { |
ASSERT(children().is_empty()); |
children().Allocate(edges().length()); |
- ASSERT(retainers().is_empty()); |
- retainers().Allocate(edges().length()); |
int children_index = 0; |
- int retainers_index = 0; |
for (int i = 0; i < entries().length(); ++i) { |
HeapEntry* entry = &entries()[i]; |
children_index = entry->set_children_index(children_index); |
- retainers_index = entry->set_retainers_index(retainers_index); |
} |
ASSERT(edges().length() == children_index); |
- ASSERT(edges().length() == retainers_index); |
for (int i = 0; i < edges().length(); ++i) { |
HeapGraphEdge* edge = &edges()[i]; |
edge->ReplaceToIndexWithEntry(this); |
edge->from()->add_child(edge); |
- edge->to()->add_retainer(edge); |
- } |
-} |
- |
- |
-void HeapSnapshot::SetDominatorsToSelf() { |
- for (int i = 0; i < entries_.length(); ++i) { |
- entries_[i].set_dominator(&entries_[i]); |
} |
} |
@@ -1284,7 +1252,6 @@ size_t HeapSnapshot::RawSnapshotSize() const { |
GetMemoryUsedByList(entries_) + |
GetMemoryUsedByList(edges_) + |
GetMemoryUsedByList(children_) + |
- GetMemoryUsedByList(retainers_) + |
GetMemoryUsedByList(sorted_entries_); |
} |
@@ -3091,12 +3058,9 @@ bool HeapSnapshotGenerator::GenerateSnapshot() { |
if (!FillReferences()) return false; |
- snapshot_->FillChildrenAndRetainers(); |
+ snapshot_->FillChildren(); |
snapshot_->RememberLastJSObjectId(); |
- if (!SetEntriesDominators()) return false; |
- if (!CalculateRetainedSizes()) return false; |
- |
progress_counter_ = progress_total_; |
if (!ProgressReport(true)) return false; |
return true; |
@@ -3138,187 +3102,6 @@ bool HeapSnapshotGenerator::FillReferences() { |
} |
-bool HeapSnapshotGenerator::IsUserGlobalReference(const HeapGraphEdge* edge) { |
- ASSERT(edge->from() == snapshot_->root()); |
- return edge->type() == HeapGraphEdge::kShortcut; |
-} |
- |
- |
-void HeapSnapshotGenerator::MarkUserReachableObjects() { |
- List<HeapEntry*> worklist; |
- |
- Vector<HeapGraphEdge*> children = snapshot_->root()->children(); |
- for (int i = 0; i < children.length(); ++i) { |
- if (IsUserGlobalReference(children[i])) { |
- worklist.Add(children[i]->to()); |
- } |
- } |
- |
- while (!worklist.is_empty()) { |
- HeapEntry* entry = worklist.RemoveLast(); |
- if (entry->user_reachable()) continue; |
- entry->set_user_reachable(); |
- Vector<HeapGraphEdge*> children = entry->children(); |
- for (int i = 0; i < children.length(); ++i) { |
- HeapEntry* child = children[i]->to(); |
- if (!child->user_reachable()) { |
- worklist.Add(child); |
- } |
- } |
- } |
-} |
- |
- |
-static bool IsRetainingEdge(HeapGraphEdge* edge) { |
- if (edge->type() == HeapGraphEdge::kShortcut) return false; |
- // The edge is not retaining if it goes from system domain |
- // (i.e. an object not reachable from window) to the user domain |
- // (i.e. a reachable object). |
- return edge->from()->user_reachable() |
- || !edge->to()->user_reachable(); |
-} |
- |
- |
-void HeapSnapshotGenerator::FillPostorderIndexes( |
- Vector<HeapEntry*>* entries) { |
- snapshot_->ClearPaint(); |
- int current_entry = 0; |
- List<HeapEntry*> nodes_to_visit; |
- HeapEntry* root = snapshot_->root(); |
- nodes_to_visit.Add(root); |
- snapshot_->root()->paint(); |
- while (!nodes_to_visit.is_empty()) { |
- HeapEntry* entry = nodes_to_visit.last(); |
- Vector<HeapGraphEdge*> children = entry->children(); |
- bool has_new_edges = false; |
- for (int i = 0; i < children.length(); ++i) { |
- if (entry != root && !IsRetainingEdge(children[i])) continue; |
- HeapEntry* child = children[i]->to(); |
- if (!child->painted()) { |
- nodes_to_visit.Add(child); |
- child->paint(); |
- has_new_edges = true; |
- } |
- } |
- if (!has_new_edges) { |
- entry->set_postorder_index(current_entry); |
- (*entries)[current_entry++] = entry; |
- nodes_to_visit.RemoveLast(); |
- } |
- } |
- ASSERT_EQ(current_entry, entries->length()); |
-} |
- |
- |
-static int Intersect(int i1, int i2, const Vector<int>& dominators) { |
- int finger1 = i1, finger2 = i2; |
- while (finger1 != finger2) { |
- while (finger1 < finger2) finger1 = dominators[finger1]; |
- while (finger2 < finger1) finger2 = dominators[finger2]; |
- } |
- return finger1; |
-} |
- |
- |
-// The algorithm is based on the article: |
-// K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" |
-// Softw. Pract. Exper. 4 (2001), pp. 1-10. |
-bool HeapSnapshotGenerator::BuildDominatorTree( |
- const Vector<HeapEntry*>& entries, |
- Vector<int>* dominators) { |
- if (entries.length() == 0) return true; |
- HeapEntry* root = snapshot_->root(); |
- const int entries_length = entries.length(), root_index = entries_length - 1; |
- for (int i = 0; i < root_index; ++i) (*dominators)[i] = HeapEntry::kNoEntry; |
- (*dominators)[root_index] = root_index; |
- |
- // The affected array is used to mark entries which dominators |
- // have to be racalculated because of changes in their retainers. |
- ScopedVector<bool> affected(entries_length); |
- for (int i = 0; i < affected.length(); ++i) affected[i] = false; |
- // Mark the root direct children as affected. |
- Vector<HeapGraphEdge*> children = entries[root_index]->children(); |
- for (int i = 0; i < children.length(); ++i) { |
- affected[children[i]->to()->postorder_index()] = true; |
- } |
- |
- bool changed = true; |
- while (changed) { |
- changed = false; |
- if (!ProgressReport(false)) return false; |
- for (int i = root_index - 1; i >= 0; --i) { |
- if (!affected[i]) continue; |
- affected[i] = false; |
- // If dominator of the entry has already been set to root, |
- // then it can't propagate any further. |
- if ((*dominators)[i] == root_index) continue; |
- int new_idom_index = HeapEntry::kNoEntry; |
- Vector<HeapGraphEdge*> rets = entries[i]->retainers(); |
- for (int j = 0; j < rets.length(); ++j) { |
- if (rets[j]->from() != root && !IsRetainingEdge(rets[j])) continue; |
- int ret_index = rets[j]->from()->postorder_index(); |
- if (dominators->at(ret_index) != HeapEntry::kNoEntry) { |
- new_idom_index = new_idom_index == HeapEntry::kNoEntry |
- ? ret_index |
- : Intersect(ret_index, new_idom_index, *dominators); |
- // If idom has already reached the root, it doesn't make sense |
- // to check other retainers. |
- if (new_idom_index == root_index) break; |
- } |
- } |
- if (new_idom_index != HeapEntry::kNoEntry |
- && dominators->at(i) != new_idom_index) { |
- (*dominators)[i] = new_idom_index; |
- changed = true; |
- Vector<HeapGraphEdge*> children = entries[i]->children(); |
- for (int j = 0; j < children.length(); ++j) { |
- affected[children[j]->to()->postorder_index()] = true; |
- } |
- } |
- } |
- } |
- return true; |
-} |
- |
- |
-bool HeapSnapshotGenerator::SetEntriesDominators() { |
- MarkUserReachableObjects(); |
- // This array is used for maintaining postorder of nodes. |
- ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries().length()); |
- FillPostorderIndexes(&ordered_entries); |
- ScopedVector<int> dominators(ordered_entries.length()); |
- if (!BuildDominatorTree(ordered_entries, &dominators)) return false; |
- for (int i = 0; i < ordered_entries.length(); ++i) { |
- ASSERT(dominators[i] != HeapEntry::kNoEntry); |
- ordered_entries[i]->set_dominator(ordered_entries[dominators[i]]); |
- } |
- return true; |
-} |
- |
- |
-bool HeapSnapshotGenerator::CalculateRetainedSizes() { |
- // As for the dominators tree we only know parent nodes, not |
- // children, to sum up total sizes we "bubble" node's self size |
- // adding it to all of its parents. |
- List<HeapEntry>& entries = snapshot_->entries(); |
- for (int i = 0; i < entries.length(); ++i) { |
- HeapEntry* entry = &entries[i]; |
- entry->set_retained_size(entry->self_size()); |
- } |
- for (int i = 0; i < entries.length(); ++i) { |
- int entry_size = entries[i].self_size(); |
- HeapEntry* current = &entries[i]; |
- for (HeapEntry* dominator = current->dominator(); |
- dominator != current; |
- current = dominator, dominator = current->dominator()) { |
- ASSERT(current->dominator() != NULL); |
- dominator->add_retained_size(entry_size); |
- } |
- } |
- return true; |
-} |
- |
- |
template<int bytes> struct MaxDecimalDigitsIn; |
template<> struct MaxDecimalDigitsIn<4> { |
static const int kSigned = 11; |
@@ -3417,8 +3200,8 @@ class OutputStreamWriter { |
// type, name|index, to_node. |
const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3; |
-// type, name, id, self_size, retained_size, dominator, children_index. |
-const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 7; |
+// type, name, id, self_size, children_index. |
+const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 5; |
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { |
ASSERT(writer_ == NULL); |
@@ -3458,8 +3241,7 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() { |
(snapshot_->RawSnapshotSize() + MB - 1) / MB); |
HeapEntry* message = result->AddEntry(HeapEntry::kString, text, 0, 4); |
result->root()->SetIndexedReference(HeapGraphEdge::kElement, 1, message); |
- result->FillChildrenAndRetainers(); |
- result->SetDominatorsToSelf(); |
+ result->FillChildren(); |
return result; |
} |
@@ -3557,11 +3339,10 @@ void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry>& nodes) { |
void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, |
int edges_index) { |
- // The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0 |
+ // The buffer needs space for 5 uint32_t, 5 commas, \n and \0 |
static const int kBufferSize = |
- 6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT |
- + MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT |
- + 7 + 1 + 1; |
+ 5 * MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT |
+ + 5 + 1 + 1; |
EmbeddedVector<char, kBufferSize> buffer; |
int buffer_pos = 0; |
if (entry_index(entry) != 0) { |
@@ -3575,10 +3356,6 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry, |
buffer[buffer_pos++] = ','; |
buffer_pos = utoa(entry->self_size(), buffer, buffer_pos); |
buffer[buffer_pos++] = ','; |
- buffer_pos = utoa(entry->retained_size(), buffer, buffer_pos); |
- buffer[buffer_pos++] = ','; |
- buffer_pos = utoa(entry_index(entry->dominator()), buffer, buffer_pos); |
- buffer[buffer_pos++] = ','; |
buffer_pos = utoa(edges_index, buffer, buffer_pos); |
buffer[buffer_pos++] = '\n'; |
buffer[buffer_pos++] = '\0'; |
@@ -3615,8 +3392,6 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { |
JSON_S("name") "," |
JSON_S("id") "," |
JSON_S("self_size") "," |
- JSON_S("retained_size") "," |
- JSON_S("dominator") "," |
JSON_S("edges_index")) "," |
JSON_S("node_types") ":" JSON_A( |
JSON_A( |