int retainers_count) {
snapshot_ = snapshot;
type_ = type;
- painted_ = kUnpainted;
+ painted_ = false;
name_ = name;
self_size_ = self_size;
retained_size_ = 0;
}
-int HeapEntry::RetainedSize(bool exact) {
- if (exact && (retained_size_ & kExactRetainedSizeTag) == 0) {
- CalculateExactRetainedSize();
- }
- return retained_size_ & (~kExactRetainedSizeTag);
-}
-
-
Handle<HeapObject> HeapEntry::GetHeapObject() {
return snapshot_->collection()->FindHeapObjectById(id());
}
-template<class Visitor>
-void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) {
- List<HeapEntry*> list(10);
- list.Add(this);
- this->paint_reachable();
- visitor->Apply(this);
- while (!list.is_empty()) {
- HeapEntry* entry = list.RemoveLast();
- Vector<HeapGraphEdge> children = entry->children();
- for (int i = 0; i < children.length(); ++i) {
- if (children[i].type() == HeapGraphEdge::kShortcut) continue;
- HeapEntry* child = children[i].to();
- if (!child->painted_reachable()) {
- list.Add(child);
- child->paint_reachable();
- visitor->Apply(child);
- }
- }
- }
-}
-
-
-class NullClass {
- public:
- void Apply(HeapEntry* entry) { }
-};
-
-void HeapEntry::PaintAllReachable() {
- NullClass null;
- ApplyAndPaintAllReachable(&null);
-}
-
-
void HeapEntry::Print(
const char* prefix, const char* edge_name, int max_depth, int indent) {
OS::Print("%6d %7d @%6llu %*c %s%s: ",
- self_size(), RetainedSize(false), id(),
+ self_size(), retained_size(), id(),
indent, ' ', prefix, edge_name);
if (type() != kString) {
OS::Print("%s %.40s\n", TypeAsString(), name_);
}
-class RetainedSizeCalculator {
- public:
- RetainedSizeCalculator()
- : retained_size_(0) {
- }
-
- int retained_size() const { return retained_size_; }
-
- void Apply(HeapEntry** entry_ptr) {
- if ((*entry_ptr)->painted_reachable()) {
- retained_size_ += (*entry_ptr)->self_size();
- }
- }
-
- private:
- int retained_size_;
-};
-
-
-void HeapEntry::CalculateExactRetainedSize() {
- // To calculate retained size, first we paint all reachable nodes in
- // one color, then we paint (or re-paint) all nodes reachable from
- // other nodes with a different color. Then we sum up self sizes of
- // nodes painted with the first color.
- snapshot()->ClearPaint();
- PaintAllReachable();
-
- List<HeapEntry*> list(10);
- HeapEntry* root = snapshot()->root();
- if (this != root) {
- list.Add(root);
- root->paint_reachable_from_others();
- }
- while (!list.is_empty()) {
- HeapEntry* curr = list.RemoveLast();
- Vector<HeapGraphEdge> children = curr->children();
- for (int i = 0; i < children.length(); ++i) {
- if (children[i].type() == HeapGraphEdge::kShortcut) continue;
- HeapEntry* child = children[i].to();
- if (child != this && child->not_painted_reachable_from_others()) {
- list.Add(child);
- child->paint_reachable_from_others();
- }
- }
- }
-
- RetainedSizeCalculator ret_size_calc;
- snapshot()->IterateEntries(&ret_size_calc);
- retained_size_ = ret_size_calc.retained_size();
- ASSERT((retained_size_ & kExactRetainedSizeTag) == 0);
- retained_size_ |= kExactRetainedSizeTag;
-}
-
-
// It is very important to keep objects that form a heap snapshot
// as small as possible.
namespace { // Avoid littering the global namespace.
if (!FillReferences()) return false;
if (!SetEntriesDominators()) return false;
- if (!ApproximateRetainedSizes()) return false;
+ if (!CalculateRetainedSizes()) return false;
progress_counter_ = progress_total_;
if (!ProgressReport(true)) return false;
int current_entry = 0;
List<HeapEntry*> nodes_to_visit;
nodes_to_visit.Add(snapshot_->root());
- snapshot_->root()->paint_reachable();
+ snapshot_->root()->paint();
while (!nodes_to_visit.is_empty()) {
HeapEntry* entry = nodes_to_visit.last();
Vector<HeapGraphEdge> children = entry->children();
for (int i = 0; i < children.length(); ++i) {
if (children[i].type() == HeapGraphEdge::kShortcut) continue;
HeapEntry* child = children[i].to();
- if (!child->painted_reachable()) {
+ if (!child->painted()) {
nodes_to_visit.Add(child);
- child->paint_reachable();
+ child->paint();
has_new_edges = true;
}
}
for (int i = 0; i < root_index; ++i) (*dominators)[i] = kNoDominator;
(*dominators)[root_index] = root_index;
- // The affected array is used to mark those entries that may
- // be affected because of dominators change among their retainers.
- ScopedVector<bool> affected(entries_length);
- for (int i = 0; i < entries_length; ++i) affected[i] = false;
+ // The painted flag is used to mark entries that need to be recalculated
+ // because of dominators change among their retainers.
+ for (int i = 0; i < entries_length; ++i) entries[i]->clear_paint();
+
+ // Mark the root direct children as affected.
Vector<HeapGraphEdge> children = entries[root_index]->children();
- for (int i = 0; i < children.length(); ++i) {
- // Mark the root direct children as affected.
- affected[children[i].to()->ordered_index()] = true;
- }
+ for (int i = 0; i < children.length(); ++i) children[i].to()->paint();
bool changed = true;
while (changed) {
// If dominator of the entry has already been set to root,
// then it can't propagate any further.
if ((*dominators)[i] == root_index) continue;
- if (!affected[i]) continue;
- affected[i] = false;
+ HeapEntry* entry = entries[i];
+ if (!entry->painted()) continue;
+ entry->clear_paint();
int new_idom_index = kNoDominator;
- Vector<HeapGraphEdge*> rets = entries[i]->retainers();
+ Vector<HeapGraphEdge*> rets = entry->retainers();
for (int j = 0; j < rets.length(); ++j) {
if (rets[j]->type() == HeapGraphEdge::kShortcut) continue;
int ret_index = rets[j]->From()->ordered_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()->ordered_index()] = true;
- }
+ for (int j = 0; j < children.length(); ++j) children[j].to()->paint();
}
}
}
}
-bool HeapSnapshotGenerator::ApproximateRetainedSizes() {
+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.
GetStringId(entry->name()),
entry->id(),
entry->self_size(),
- entry->RetainedSize(false),
+ entry->retained_size(),
GetNodeId(entry->dominator()),
children.length());
USE(result);
ASSERT(entry != NULL);
dominator_ = entry;
}
-
- void clear_paint() { painted_ = kUnpainted; }
- bool painted_reachable() { return painted_ == kPainted; }
- void paint_reachable() {
- ASSERT(painted_ == kUnpainted);
- painted_ = kPainted;
- }
- bool not_painted_reachable_from_others() {
- return painted_ != kPaintedReachableFromOthers;
- }
- void paint_reachable_from_others() {
- painted_ = kPaintedReachableFromOthers;
- }
- template<class Visitor>
- void ApplyAndPaintAllReachable(Visitor* visitor);
- void PaintAllReachable();
+ void clear_paint() { painted_ = false; }
+ bool painted() { return painted_; }
+ void paint() { painted_ = true; }
void SetIndexedReference(HeapGraphEdge::Type type,
int child_index,
void SetUnidirElementReference(int child_index, int index, HeapEntry* entry);
int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
- int RetainedSize(bool exact);
void Print(
const char* prefix, const char* edge_name, int max_depth, int indent);
HeapGraphEdge** retainers_arr() {
return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
}
- void CalculateExactRetainedSize();
const char* TypeAsString();
- unsigned painted_: 2;
+ unsigned painted_: 1;
unsigned type_: 4;
- int children_count_: 26;
+ int children_count_: 27;
int retainers_count_;
int self_size_;
union {
} id_; // This is to avoid extra padding of 64-bit value.
const char* name_;
- // Paints used for exact retained sizes calculation.
- static const unsigned kUnpainted = 0;
- static const unsigned kPainted = 1;
- static const unsigned kPaintedReachableFromOthers = 2;
-
- static const int kExactRetainedSizeTag = 1;
-
DISALLOW_COPY_AND_ASSIGN(HeapEntry);
};
bool GenerateSnapshot();
private:
- bool ApproximateRetainedSizes();
bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
Vector<int>* dominators);
+ bool CalculateRetainedSizes();
bool CountEntriesAndReferences();
bool FillReferences();
void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
: has_A2(false), has_B2(false), has_C2(false) {
}
- void Apply(i::HeapEntry** entry_ptr) {
- if (IsReachableNodeWithName(*entry_ptr, "A2")) has_A2 = true;
- if (IsReachableNodeWithName(*entry_ptr, "B2")) has_B2 = true;
- if (IsReachableNodeWithName(*entry_ptr, "C2")) has_C2 = true;
+ void CheckEntry(i::HeapEntry* entry) {
+ if (strcmp(entry->name(), "A2") == 0) has_A2 = true;
+ if (strcmp(entry->name(), "B2") == 0) has_B2 = true;
+ if (strcmp(entry->name(), "C2") == 0) has_C2 = true;
}
- static bool IsReachableNodeWithName(i::HeapEntry* entry, const char* name) {
- return strcmp(name, entry->name()) == 0 && entry->painted_reachable();
+ void CheckAllReachables(i::HeapEntry* root) {
+ i::List<i::HeapEntry*> list(10);
+ list.Add(root);
+ root->paint();
+ CheckEntry(root);
+ while (!list.is_empty()) {
+ i::HeapEntry* entry = list.RemoveLast();
+ i::Vector<i::HeapGraphEdge> children = entry->children();
+ for (int i = 0; i < children.length(); ++i) {
+ if (children[i].type() == i::HeapGraphEdge::kShortcut) continue;
+ i::HeapEntry* child = children[i].to();
+ if (!child->painted()) {
+ list.Add(child);
+ child->paint();
+ CheckEntry(child);
+ }
+ }
+ }
}
bool has_A2;
const_cast<i::HeapSnapshot*>(
reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
- // Paint all nodes reachable from global object.
- i_snapshot_env2->ClearPaint();
- const_cast<i::HeapEntry*>(
- reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
// Verify, that JS global object of env2 has '..2' properties.
const v8::HeapGraphNode* a2_node =
NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
+ // Paint all nodes reachable from global object.
NamedEntriesDetector det;
- i_snapshot_env2->IterateEntries(&det);
+ i_snapshot_env2->ClearPaint();
+ det.CheckAllReachables(const_cast<i::HeapEntry*>(
+ reinterpret_cast<const i::HeapEntry*>(global_env2)));
CHECK(det.has_A2);
CHECK(det.has_B2);
CHECK(det.has_C2);
GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
CHECK_NE(NULL, x2);
- // Test approximate sizes.
- CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(false));
- CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(false));
- CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(false));
- // Test exact sizes.
- CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(true));
- CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(true));
- CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(true));
+ // Test sizes.
+ CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize());
+ CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize());
+ CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize());
}