Index: src/profile-generator.cc |
diff --git a/src/profile-generator.cc b/src/profile-generator.cc |
index 538a9ce931786555acb98c2424777b9c1ef12021..4e0cb7111ba5dffba88e5e79c04ba95f97314349 100644 |
--- a/src/profile-generator.cc |
+++ b/src/profile-generator.cc |
@@ -181,8 +181,6 @@ void ProfileNode::Print(int indent) { |
} |
-namespace { |
- |
class DeleteNodesCallback { |
public: |
void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } |
@@ -194,8 +192,6 @@ class DeleteNodesCallback { |
void AfterChildTraversed(ProfileNode*, ProfileNode*) { } |
}; |
-} // namespace |
- |
ProfileTree::ProfileTree() |
: root_entry_(Logger::FUNCTION_TAG, |
@@ -240,8 +236,6 @@ void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) { |
} |
-namespace { |
- |
struct NodesPair { |
NodesPair(ProfileNode* src, ProfileNode* dst) |
: src(src), dst(dst) { } |
@@ -294,8 +288,6 @@ class FilteredCloneCallback { |
int security_token_id_; |
}; |
-} // namespace |
- |
void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) { |
ms_to_ticks_scale_ = src->ms_to_ticks_scale_; |
FilteredCloneCallback cb(root_, security_token_id); |
@@ -309,8 +301,6 @@ void ProfileTree::SetTickRatePerMs(double ticks_per_ms) { |
} |
-namespace { |
- |
class Position { |
public: |
explicit Position(ProfileNode* node) |
@@ -328,8 +318,6 @@ class Position { |
int child_idx_; |
}; |
-} // namespace |
- |
// Non-recursive implementation of a depth-first post-order tree traversal. |
template <typename Callback> |
@@ -355,8 +343,6 @@ void ProfileTree::TraverseDepthFirst(Callback* callback) { |
} |
-namespace { |
- |
class CalculateTotalTicksCallback { |
public: |
void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } |
@@ -370,8 +356,6 @@ class CalculateTotalTicksCallback { |
} |
}; |
-} // namespace |
- |
void ProfileTree::CalculateTotalTicks() { |
CalculateTotalTicksCallback cb; |
@@ -877,6 +861,11 @@ void HeapEntry::SetAutoIndexReference(HeapEntry* entry) { |
} |
+void HeapEntry::SetUnidirAutoIndexReference(HeapEntry* entry) { |
+ children_.Add(new HeapGraphEdge(next_auto_index_++, this, entry)); |
+} |
+ |
+ |
int HeapEntry::TotalSize() { |
return total_size_ != kUnknownSize ? total_size_ : CalculateTotalSize(); |
} |
@@ -888,12 +877,12 @@ int HeapEntry::NonSharedTotalSize() { |
} |
-int HeapEntry::CalculateTotalSize() { |
- snapshot_->ClearPaint(); |
+template<class Visitor> |
+void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) { |
List<HeapEntry*> list(10); |
list.Add(this); |
- total_size_ = self_size_; |
this->PaintReachable(); |
+ visitor->Apply(this); |
while (!list.is_empty()) { |
HeapEntry* entry = list.RemoveLast(); |
const int children_count = entry->children_.length(); |
@@ -902,15 +891,48 @@ int HeapEntry::CalculateTotalSize() { |
if (!child->painted_reachable()) { |
list.Add(child); |
child->PaintReachable(); |
- total_size_ += child->self_size_; |
+ visitor->Apply(child); |
} |
} |
} |
- return total_size_; |
} |
-namespace { |
+class NullClass { |
+ public: |
+ void Apply(HeapEntry* entry) { } |
+}; |
+ |
+void HeapEntry::PaintAllReachable() { |
+ NullClass null; |
+ ApplyAndPaintAllReachable(&null); |
+} |
+ |
+ |
+class TotalSizeCalculator { |
+ public: |
+ TotalSizeCalculator() |
+ : total_size_(0) { |
+ } |
+ |
+ int total_size() const { return total_size_; } |
+ |
+ void Apply(HeapEntry* entry) { |
+ total_size_ += entry->self_size(); |
+ } |
+ |
+ private: |
+ int total_size_; |
+}; |
+ |
+int HeapEntry::CalculateTotalSize() { |
+ snapshot_->ClearPaint(); |
+ TotalSizeCalculator calc; |
+ ApplyAndPaintAllReachable(&calc); |
+ total_size_ = calc.total_size(); |
+ return total_size_; |
+} |
+ |
class NonSharedSizeCalculator { |
public: |
@@ -930,41 +952,26 @@ class NonSharedSizeCalculator { |
int non_shared_total_size_; |
}; |
-} // namespace |
- |
int HeapEntry::CalculateNonSharedTotalSize() { |
// To calculate non-shared total size, first we paint all reachable |
// nodes in one color, then we paint all nodes reachable from other |
// nodes with a different color. Then we consider only nodes painted |
- // with the first color for caclulating the total size. |
+ // with the first color for calculating the total size. |
snapshot_->ClearPaint(); |
- List<HeapEntry*> list(10); |
- list.Add(this); |
- this->PaintReachable(); |
- while (!list.is_empty()) { |
- HeapEntry* entry = list.RemoveLast(); |
- const int children_count = entry->children_.length(); |
- for (int i = 0; i < children_count; ++i) { |
- HeapEntry* child = entry->children_[i]->to(); |
- if (!child->painted_reachable()) { |
- list.Add(child); |
- child->PaintReachable(); |
- } |
- } |
- } |
+ PaintAllReachable(); |
- List<HeapEntry*> list2(10); |
+ List<HeapEntry*> list(10); |
if (this != snapshot_->root()) { |
- list2.Add(snapshot_->root()); |
+ list.Add(snapshot_->root()); |
snapshot_->root()->PaintReachableFromOthers(); |
} |
- while (!list2.is_empty()) { |
- HeapEntry* entry = list2.RemoveLast(); |
+ while (!list.is_empty()) { |
+ HeapEntry* entry = list.RemoveLast(); |
const int children_count = entry->children_.length(); |
for (int i = 0; i < children_count; ++i) { |
HeapEntry* child = entry->children_[i]->to(); |
if (child != this && child->not_painted_reachable_from_others()) { |
- list2.Add(child); |
+ list.Add(child); |
child->PaintReachableFromOthers(); |
} |
} |
@@ -972,7 +979,8 @@ int HeapEntry::CalculateNonSharedTotalSize() { |
NonSharedSizeCalculator calculator; |
snapshot_->IterateEntries(&calculator); |
- return calculator.non_shared_total_size(); |
+ non_shared_total_size_ = calculator.non_shared_total_size(); |
+ return non_shared_total_size_; |
} |
@@ -1078,7 +1086,8 @@ void HeapEntry::CutEdges() { |
void HeapEntry::Print(int max_depth, int indent) { |
- OS::Print("%6d %6d %6d ", self_size_, TotalSize(), NonSharedTotalSize()); |
+ OS::Print("%6d %6d %6d [%ld] ", |
+ self_size_, TotalSize(), NonSharedTotalSize(), id_); |
if (type_ != STRING) { |
OS::Print("%s %.40s\n", TypeAsString(), name_); |
} else { |
@@ -1244,7 +1253,13 @@ HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
: collection_(collection), |
title_(title), |
uid_(uid), |
- root_(this) { |
+ root_(this), |
+ sorted_entries_(NULL) { |
+} |
+ |
+ |
+HeapSnapshot::~HeapSnapshot() { |
+ delete sorted_entries_; |
} |
@@ -1355,6 +1370,7 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
HeapEntry* entry = new HeapEntry(this, |
type, |
name, |
+ collection_->GetObjectId(object->address()), |
GetObjectSize(object), |
GetObjectSecurityToken(object)); |
entries_.Pair(object, entry); |
@@ -1381,8 +1397,6 @@ HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
} |
-namespace { |
- |
class EdgesCutter { |
public: |
explicit EdgesCutter(int global_security_token) |
@@ -1400,8 +1414,6 @@ class EdgesCutter { |
const int global_security_token_; |
}; |
-} // namespace |
- |
void HeapSnapshot::CutObjectsFromForeignSecurityContexts() { |
EdgesCutter cutter(GetGlobalSecurityToken()); |
entries_.Apply(&cutter); |
@@ -1454,13 +1466,125 @@ int HeapSnapshot::CalculateNetworkSize(JSObject* obj) { |
} |
+class EntriesCollector { |
+ public: |
+ explicit EntriesCollector(List<HeapEntry*>* list) : list_(list) { } |
+ void Apply(HeapEntry* entry) { |
+ list_->Add(entry); |
+ } |
+ private: |
+ List<HeapEntry*>* list_; |
+}; |
+ |
+template<class T> |
+static int SortByIds(const T* entry1_ptr, |
+ const T* entry2_ptr) { |
+ if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; |
+ return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; |
+} |
+ |
+List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
+ if (sorted_entries_ != NULL) return sorted_entries_; |
+ sorted_entries_ = new List<HeapEntry*>(entries_.capacity()); |
+ EntriesCollector collector(sorted_entries_); |
+ entries_.Apply(&collector); |
+ sorted_entries_->Sort(SortByIds); |
+ return sorted_entries_; |
+} |
+ |
+ |
+HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) { |
+ return collection_->CompareSnapshots(this, snapshot); |
+} |
+ |
+ |
void HeapSnapshot::Print(int max_depth) { |
root_.Print(max_depth, 0); |
} |
+HeapObjectsMap::HeapObjectsMap() |
+ : initial_fill_mode_(true), |
+ next_id_(1), |
+ entries_map_(AddressesMatch), |
+ entries_(new List<EntryInfo>()) { } |
+ |
+ |
+HeapObjectsMap::~HeapObjectsMap() { |
+ delete entries_; |
+} |
+ |
+ |
+void HeapObjectsMap::SnapshotGenerationFinished() { |
+ initial_fill_mode_ = false; |
+ RemoveDeadEntries(); |
+} |
+ |
+ |
+uint64_t HeapObjectsMap::FindObject(Address addr) { |
+ if (!initial_fill_mode_) { |
+ uint64_t existing = FindEntry(addr); |
+ if (existing != 0) return existing; |
+ } |
+ uint64_t id = next_id_++; |
+ AddEntry(addr, id); |
+ return id; |
+} |
+ |
+ |
+void HeapObjectsMap::MoveObject(Address from, Address to) { |
+ HashMap::Entry* entry = entries_map_.Lookup(from, AddressHash(from), false); |
+ if (entry != NULL) { |
+ void* value = entry->value; |
+ entries_map_.Remove(from, AddressHash(from)); |
+ entry = entries_map_.Lookup(to, AddressHash(to), true); |
+ ASSERT(entry->value == NULL); |
+ entry->value = value; |
+ } |
+} |
+ |
+ |
+void HeapObjectsMap::AddEntry(Address addr, uint64_t id) { |
+ HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true); |
+ ASSERT(entry->value == NULL); |
+ entry->value = reinterpret_cast<void*>(entries_->length()); |
+ entries_->Add(EntryInfo(id)); |
+} |
+ |
+ |
+uint64_t HeapObjectsMap::FindEntry(Address addr) { |
+ HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false); |
+ if (entry != NULL) { |
+ int entry_index = reinterpret_cast<intptr_t>(entry->value); |
+ EntryInfo& entry_info = entries_->at(entry_index); |
+ entry_info.accessed = true; |
+ return entry_info.id; |
+ } else { |
+ return 0; |
+ } |
+} |
+ |
+ |
+void HeapObjectsMap::RemoveDeadEntries() { |
+ List<EntryInfo>* new_entries = new List<EntryInfo>(); |
+ for (HashMap::Entry* entry = entries_map_.Start(); |
+ entry != NULL; |
+ entry = entries_map_.Next(entry)) { |
+ int entry_index = reinterpret_cast<intptr_t>(entry->value); |
+ EntryInfo& entry_info = entries_->at(entry_index); |
+ if (entry_info.accessed) { |
+ entry->value = reinterpret_cast<void*>(new_entries->length()); |
+ new_entries->Add(EntryInfo(entry_info.id, false)); |
+ } |
+ } |
+ delete entries_; |
+ entries_ = new_entries; |
+} |
+ |
+ |
HeapSnapshotsCollection::HeapSnapshotsCollection() |
- : snapshots_uids_(HeapSnapshotsMatch), |
+ : is_tracking_objects_(false), |
+ snapshots_uids_(HeapSnapshotsMatch), |
token_enumerator_(new TokenEnumerator()) { |
} |
@@ -1478,6 +1602,7 @@ HeapSnapshotsCollection::~HeapSnapshotsCollection() { |
HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(const char* name, |
unsigned uid) { |
+ is_tracking_objects_ = true; // Start watching for heap objects moves. |
HeapSnapshot* snapshot = new HeapSnapshot(this, name, uid); |
snapshots_.Add(snapshot); |
HashMap::Entry* entry = |
@@ -1498,6 +1623,13 @@ HeapSnapshot* HeapSnapshotsCollection::GetSnapshot(unsigned uid) { |
} |
+HeapSnapshotsDiff* HeapSnapshotsCollection::CompareSnapshots( |
+ HeapSnapshot* snapshot1, |
+ HeapSnapshot* snapshot2) { |
+ return comparator_.Compare(snapshot1, snapshot2); |
+} |
+ |
+ |
HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot) |
: snapshot_(snapshot) { |
} |
@@ -1630,6 +1762,64 @@ void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj, |
} |
} |
+ |
+static void DeleteHeapSnapshotsDiff(HeapSnapshotsDiff** diff_ptr) { |
+ delete *diff_ptr; |
+} |
+ |
+HeapSnapshotsComparator::~HeapSnapshotsComparator() { |
+ diffs_.Iterate(DeleteHeapSnapshotsDiff); |
+} |
+ |
+ |
+HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1, |
+ HeapSnapshot* snapshot2) { |
+ HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2); |
+ diffs_.Add(diff); |
+ List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList(); |
+ List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList(); |
+ int i = 0, j = 0; |
+ List<HeapEntry*> added_entries, deleted_entries; |
+ while (i < entries1->length() && j < entries2->length()) { |
+ uint64_t id1 = entries1->at(i)->id(); |
+ uint64_t id2 = entries2->at(j)->id(); |
+ if (id1 == id2) { |
+ i++; |
+ j++; |
+ } else if (id1 < id2) { |
+ HeapEntry* entry = entries1->at(i++); |
+ deleted_entries.Add(entry); |
+ } else { |
+ HeapEntry* entry = entries2->at(j++); |
+ added_entries.Add(entry); |
+ } |
+ } |
+ while (i < entries1->length()) { |
+ HeapEntry* entry = entries1->at(i++); |
+ deleted_entries.Add(entry); |
+ } |
+ while (j < entries2->length()) { |
+ HeapEntry* entry = entries2->at(j++); |
+ added_entries.Add(entry); |
+ } |
+ |
+ snapshot1->ClearPaint(); |
+ snapshot1->root()->PaintAllReachable(); |
+ for (int i = 0; i < deleted_entries.length(); ++i) { |
+ HeapEntry* entry = deleted_entries[i]; |
+ if (entry->painted_reachable()) |
+ diff->AddDeletedEntry(entry); |
+ } |
+ snapshot2->ClearPaint(); |
+ snapshot2->root()->PaintAllReachable(); |
+ for (int i = 0; i < added_entries.length(); ++i) { |
+ HeapEntry* entry = added_entries[i]; |
+ if (entry->painted_reachable()) |
+ diff->AddAddedEntry(entry); |
+ } |
+ return diff; |
+} |
+ |
} } // namespace v8::internal |
#endif // ENABLE_LOGGING_AND_PROFILING |