Refactor heap profiler's code to make possible including

into heap snapshots non-HeapObjects. This is needed as a
preparation for adding DOM subtrees tracking.

BUG=none
TEST=none

Review URL: http://codereview.chromium.org/6596073

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7004 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mikhail.naganov@gmail.com 2011-03-01 17:38:49 +00:00
parent 63beeed358
commit 60711c074f
5 changed files with 594 additions and 490 deletions

View File

@ -911,22 +911,27 @@ static JSObjectsCluster HeapObjectAsCluster(HeapObject* object) {
class CountingRetainersIterator { class CountingRetainersIterator {
public: public:
CountingRetainersIterator(const JSObjectsCluster& child_cluster, CountingRetainersIterator(const JSObjectsCluster& child_cluster,
HeapEntriesAllocator* allocator,
HeapEntriesMap* map) HeapEntriesMap* map)
: child_(ClusterAsHeapObject(child_cluster)), map_(map) { : child_(ClusterAsHeapObject(child_cluster)),
allocator_(allocator),
map_(map) {
if (map_->Map(child_) == NULL) if (map_->Map(child_) == NULL)
map_->Pair(child_, HeapEntriesMap::kHeapEntryPlaceholder); map_->Pair(child_, allocator_, HeapEntriesMap::kHeapEntryPlaceholder);
} }
void Call(const JSObjectsCluster& cluster, void Call(const JSObjectsCluster& cluster,
const NumberAndSizeInfo& number_and_size) { const NumberAndSizeInfo& number_and_size) {
if (map_->Map(ClusterAsHeapObject(cluster)) == NULL) if (map_->Map(ClusterAsHeapObject(cluster)) == NULL)
map_->Pair(ClusterAsHeapObject(cluster), map_->Pair(ClusterAsHeapObject(cluster),
allocator_,
HeapEntriesMap::kHeapEntryPlaceholder); HeapEntriesMap::kHeapEntryPlaceholder);
map_->CountReference(ClusterAsHeapObject(cluster), child_); map_->CountReference(ClusterAsHeapObject(cluster), child_);
} }
private: private:
HeapObject* child_; HeapObject* child_;
HeapEntriesAllocator* allocator_;
HeapEntriesMap* map_; HeapEntriesMap* map_;
}; };
@ -934,6 +939,7 @@ class CountingRetainersIterator {
class AllocatingRetainersIterator { class AllocatingRetainersIterator {
public: public:
AllocatingRetainersIterator(const JSObjectsCluster& child_cluster, AllocatingRetainersIterator(const JSObjectsCluster& child_cluster,
HeapEntriesAllocator*,
HeapEntriesMap* map) HeapEntriesMap* map)
: child_(ClusterAsHeapObject(child_cluster)), map_(map) { : child_(ClusterAsHeapObject(child_cluster)), map_(map) {
child_entry_ = map_->Map(child_); child_entry_ = map_->Map(child_);
@ -966,8 +972,9 @@ template<class RetainersIterator>
class AggregatingRetainerTreeIterator { class AggregatingRetainerTreeIterator {
public: public:
explicit AggregatingRetainerTreeIterator(ClustersCoarser* coarser, explicit AggregatingRetainerTreeIterator(ClustersCoarser* coarser,
HeapEntriesAllocator* allocator,
HeapEntriesMap* map) HeapEntriesMap* map)
: coarser_(coarser), map_(map) { : coarser_(coarser), allocator_(allocator), map_(map) {
} }
void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree) { void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree) {
@ -981,25 +988,28 @@ class AggregatingRetainerTreeIterator {
tree->ForEach(&retainers_aggregator); tree->ForEach(&retainers_aggregator);
tree_to_iterate = &dest_tree_; tree_to_iterate = &dest_tree_;
} }
RetainersIterator iterator(cluster, map_); RetainersIterator iterator(cluster, allocator_, map_);
tree_to_iterate->ForEach(&iterator); tree_to_iterate->ForEach(&iterator);
} }
private: private:
ClustersCoarser* coarser_; ClustersCoarser* coarser_;
HeapEntriesAllocator* allocator_;
HeapEntriesMap* map_; HeapEntriesMap* map_;
}; };
class AggregatedRetainerTreeAllocator { class AggregatedRetainerTreeAllocator : public HeapEntriesAllocator {
public: public:
AggregatedRetainerTreeAllocator(HeapSnapshot* snapshot, AggregatedRetainerTreeAllocator(HeapSnapshot* snapshot,
int* root_child_index) int* root_child_index)
: snapshot_(snapshot), root_child_index_(root_child_index) { : snapshot_(snapshot), root_child_index_(root_child_index) {
} }
~AggregatedRetainerTreeAllocator() { }
HeapEntry* GetEntry( HeapEntry* AllocateEntry(
HeapObject* obj, int children_count, int retainers_count) { HeapThing ptr, int children_count, int retainers_count) {
HeapObject* obj = reinterpret_cast<HeapObject*>(ptr);
JSObjectsCluster cluster = HeapObjectAsCluster(obj); JSObjectsCluster cluster = HeapObjectAsCluster(obj);
const char* name = cluster.GetSpecialCaseName(); const char* name = cluster.GetSpecialCaseName();
if (name == NULL) { if (name == NULL) {
@ -1018,12 +1028,13 @@ class AggregatedRetainerTreeAllocator {
template<class Iterator> template<class Iterator>
void AggregatedHeapSnapshotGenerator::IterateRetainers( void AggregatedHeapSnapshotGenerator::IterateRetainers(
HeapEntriesMap* entries_map) { HeapEntriesAllocator* allocator, HeapEntriesMap* entries_map) {
RetainerHeapProfile* p = agg_snapshot_->js_retainer_profile(); RetainerHeapProfile* p = agg_snapshot_->js_retainer_profile();
AggregatingRetainerTreeIterator<Iterator> agg_ret_iter_1( AggregatingRetainerTreeIterator<Iterator> agg_ret_iter_1(
p->coarser(), entries_map); p->coarser(), allocator, entries_map);
p->retainers_tree()->ForEach(&agg_ret_iter_1); p->retainers_tree()->ForEach(&agg_ret_iter_1);
AggregatingRetainerTreeIterator<Iterator> agg_ret_iter_2(NULL, entries_map); AggregatingRetainerTreeIterator<Iterator> agg_ret_iter_2(
NULL, allocator, entries_map);
p->aggregator()->output_tree().ForEach(&agg_ret_iter_2); p->aggregator()->output_tree().ForEach(&agg_ret_iter_2);
} }
@ -1042,7 +1053,9 @@ void AggregatedHeapSnapshotGenerator::FillHeapSnapshot(HeapSnapshot* snapshot) {
agg_snapshot_->js_cons_profile()->ForEach(&counting_cons_iter); agg_snapshot_->js_cons_profile()->ForEach(&counting_cons_iter);
histogram_entities_count += counting_cons_iter.entities_count(); histogram_entities_count += counting_cons_iter.entities_count();
HeapEntriesMap entries_map; HeapEntriesMap entries_map;
IterateRetainers<CountingRetainersIterator>(&entries_map); int root_child_index = 0;
AggregatedRetainerTreeAllocator allocator(snapshot, &root_child_index);
IterateRetainers<CountingRetainersIterator>(&allocator, &entries_map);
histogram_entities_count += entries_map.entries_count(); histogram_entities_count += entries_map.entries_count();
histogram_children_count += entries_map.total_children_count(); histogram_children_count += entries_map.total_children_count();
histogram_retainers_count += entries_map.total_retainers_count(); histogram_retainers_count += entries_map.total_retainers_count();
@ -1056,10 +1069,7 @@ void AggregatedHeapSnapshotGenerator::FillHeapSnapshot(HeapSnapshot* snapshot) {
snapshot->AllocateEntries(histogram_entities_count, snapshot->AllocateEntries(histogram_entities_count,
histogram_children_count, histogram_children_count,
histogram_retainers_count); histogram_retainers_count);
snapshot->AddEntry(HeapSnapshot::kInternalRootObject, snapshot->AddRootEntry(root_children_count);
root_children_count,
0);
int root_child_index = 0;
for (int i = FIRST_NONSTRING_TYPE; i <= kAllStringsType; ++i) { for (int i = FIRST_NONSTRING_TYPE; i <= kAllStringsType; ++i) {
if (agg_snapshot_->info()[i].bytes() > 0) { if (agg_snapshot_->info()[i].bytes() > 0) {
AddEntryFromAggregatedSnapshot(snapshot, AddEntryFromAggregatedSnapshot(snapshot,
@ -1075,11 +1085,10 @@ void AggregatedHeapSnapshotGenerator::FillHeapSnapshot(HeapSnapshot* snapshot) {
AllocatingConstructorHeapProfileIterator alloc_cons_iter( AllocatingConstructorHeapProfileIterator alloc_cons_iter(
snapshot, &root_child_index); snapshot, &root_child_index);
agg_snapshot_->js_cons_profile()->ForEach(&alloc_cons_iter); agg_snapshot_->js_cons_profile()->ForEach(&alloc_cons_iter);
AggregatedRetainerTreeAllocator allocator(snapshot, &root_child_index); entries_map.AllocateEntries();
entries_map.UpdateEntries(&allocator);
// Fill up references. // Fill up references.
IterateRetainers<AllocatingRetainersIterator>(&entries_map); IterateRetainers<AllocatingRetainersIterator>(&allocator, &entries_map);
snapshot->SetDominatorsToSelf(); snapshot->SetDominatorsToSelf();
} }

View File

@ -340,6 +340,7 @@ class AggregatedHeapSnapshot {
class HeapEntriesMap; class HeapEntriesMap;
class HeapEntriesAllocator;
class HeapSnapshot; class HeapSnapshot;
class AggregatedHeapSnapshotGenerator { class AggregatedHeapSnapshotGenerator {
@ -354,7 +355,8 @@ class AggregatedHeapSnapshotGenerator {
void CalculateStringsStats(); void CalculateStringsStats();
void CollectStats(HeapObject* obj); void CollectStats(HeapObject* obj);
template<class Iterator> template<class Iterator>
void IterateRetainers(HeapEntriesMap* entries_map); void IterateRetainers(
HeapEntriesAllocator* allocator, HeapEntriesMap* entries_map);
AggregatedHeapSnapshot* agg_snapshot_; AggregatedHeapSnapshot* agg_snapshot_;
}; };

View File

@ -121,34 +121,6 @@ uint64_t HeapEntry::id() {
return id_adaptor.returned_id; return id_adaptor.returned_id;
} }
template<class Visitor>
void HeapEntriesMap::UpdateEntries(Visitor* visitor) {
for (HashMap::Entry* p = entries_.Start();
p != NULL;
p = entries_.Next(p)) {
EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value);
entry_info->entry = visitor->GetEntry(
reinterpret_cast<HeapObject*>(p->key),
entry_info->children_count,
entry_info->retainers_count);
entry_info->children_count = 0;
entry_info->retainers_count = 0;
}
}
bool HeapSnapshotGenerator::ReportProgress(bool force) {
const int kProgressReportGranularity = 10000;
if (control_ != NULL
&& (force || progress_counter_ % kProgressReportGranularity == 0)) {
return
control_->ReportProgressValue(progress_counter_, progress_total_) ==
v8::ActivityControl::kContinue;
}
return true;
}
} } // namespace v8::internal } } // namespace v8::internal
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING

File diff suppressed because it is too large Load Diff

View File

@ -681,14 +681,14 @@ class HeapSnapshot {
void AllocateEntries( void AllocateEntries(
int entries_count, int children_count, int retainers_count); int entries_count, int children_count, int retainers_count);
HeapEntry* AddEntry(
HeapObject* object, int children_count, int retainers_count);
HeapEntry* AddEntry(HeapEntry::Type type, HeapEntry* AddEntry(HeapEntry::Type type,
const char* name, const char* name,
uint64_t id, uint64_t id,
int size, int size,
int children_count, int children_count,
int retainers_count); int retainers_count);
HeapEntry* AddRootEntry(int children_count);
HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
void ClearPaint(); void ClearPaint();
HeapSnapshotsDiff* CompareWith(HeapSnapshot* snapshot); HeapSnapshotsDiff* CompareWith(HeapSnapshot* snapshot);
HeapEntry* GetEntryById(uint64_t id); HeapEntry* GetEntryById(uint64_t id);
@ -701,15 +701,7 @@ class HeapSnapshot {
void Print(int max_depth); void Print(int max_depth);
void PrintEntriesSize(); void PrintEntriesSize();
static HeapObject* const kInternalRootObject;
static HeapObject* const kGcRootsObject;
private: private:
HeapEntry* AddEntry(HeapObject* object,
HeapEntry::Type type,
const char* name,
int children_count,
int retainers_count);
HeapEntry* GetNextEntryToInit(); HeapEntry* GetNextEntryToInit();
HeapSnapshotsCollection* collection_; HeapSnapshotsCollection* collection_;
@ -873,6 +865,20 @@ class HeapSnapshotsCollection {
}; };
// A typedef for referencing anything that can be snapshotted living
// in any kind of heap memory.
typedef void* HeapThing;
// An interface that creates HeapEntries by HeapThings.
class HeapEntriesAllocator {
public:
virtual ~HeapEntriesAllocator() { }
virtual HeapEntry* AllocateEntry(
HeapThing ptr, int children_count, int retainers_count) = 0;
};
// The HeapEntriesMap instance is used to track a mapping between // The HeapEntriesMap instance is used to track a mapping between
// real heap objects and their representations in heap snapshots. // real heap objects and their representations in heap snapshots.
class HeapEntriesMap { class HeapEntriesMap {
@ -880,13 +886,12 @@ class HeapEntriesMap {
HeapEntriesMap(); HeapEntriesMap();
~HeapEntriesMap(); ~HeapEntriesMap();
HeapEntry* Map(HeapObject* object); void AllocateEntries();
void Pair(HeapObject* object, HeapEntry* entry); HeapEntry* Map(HeapThing thing);
void CountReference(HeapObject* from, HeapObject* to, void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry);
void CountReference(HeapThing from, HeapThing to,
int* prev_children_count = NULL, int* prev_children_count = NULL,
int* prev_retainers_count = NULL); int* prev_retainers_count = NULL);
template<class Visitor>
void UpdateEntries(Visitor* visitor);
int entries_count() { return entries_count_; } int entries_count() { return entries_count_; }
int total_children_count() { return total_children_count_; } int total_children_count() { return total_children_count_; }
@ -896,18 +901,25 @@ class HeapEntriesMap {
private: private:
struct EntryInfo { struct EntryInfo {
explicit EntryInfo(HeapEntry* entry) EntryInfo(HeapEntry* entry, HeapEntriesAllocator* allocator)
: entry(entry), children_count(0), retainers_count(0) { } : entry(entry),
allocator(allocator),
children_count(0),
retainers_count(0) {
}
HeapEntry* entry; HeapEntry* entry;
HeapEntriesAllocator* allocator;
int children_count; int children_count;
int retainers_count; int retainers_count;
}; };
static uint32_t Hash(HeapObject* object) { static uint32_t Hash(HeapThing thing) {
return ComputeIntegerHash( return ComputeIntegerHash(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object))); static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)));
}
static bool HeapThingsMatch(HeapThing key1, HeapThing key2) {
return key1 == key2;
} }
static bool HeapObjectsMatch(void* key1, void* key2) { return key1 == key2; }
HashMap entries_; HashMap entries_;
int entries_count_; int entries_count_;
@ -934,52 +946,70 @@ class HeapObjectsSet {
}; };
class HeapSnapshotGenerator { // An interface used to populate a snapshot with nodes and edges.
class SnapshotFillerInterface {
public: public:
class SnapshotFillerInterface { virtual ~SnapshotFillerInterface() { }
public: virtual HeapEntry* AddEntry(HeapThing ptr) = 0;
virtual ~SnapshotFillerInterface() { } virtual HeapEntry* FindOrAddEntry(HeapThing ptr) = 0;
virtual HeapEntry* AddEntry(HeapObject* obj) = 0; virtual void SetIndexedReference(HeapGraphEdge::Type type,
virtual void SetIndexedReference(HeapGraphEdge::Type type, HeapThing parent_ptr,
HeapObject* parent_obj,
HeapEntry* parent_entry,
int index,
Object* child_obj,
HeapEntry* child_entry) = 0;
virtual void SetNamedReference(HeapGraphEdge::Type type,
HeapObject* parent_obj,
HeapEntry* parent_entry, HeapEntry* parent_entry,
const char* reference_name, int index,
Object* child_obj, HeapThing child_ptr,
HeapEntry* child_entry) = 0; HeapEntry* child_entry) = 0;
virtual void SetRootGcRootsReference() = 0; virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
virtual void SetRootShortcutReference(Object* child_obj, HeapThing parent_ptr,
HeapEntry* parent_entry,
HeapThing child_ptr,
HeapEntry* child_entry) = 0;
virtual void SetNamedReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
const char* reference_name,
HeapThing child_ptr,
HeapEntry* child_entry) = 0;
virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
HeapThing parent_ptr,
HeapEntry* parent_entry,
HeapThing child_ptr,
HeapEntry* child_entry) = 0; HeapEntry* child_entry) = 0;
virtual void SetStrongRootReference(Object* child_obj, };
HeapEntry* child_entry) = 0;
};
HeapSnapshotGenerator(HeapSnapshot* snapshot,
v8::ActivityControl* control); class SnapshottingProgressReportingInterface {
bool GenerateSnapshot(); public:
virtual ~SnapshottingProgressReportingInterface() { }
virtual void ProgressStep() = 0;
virtual bool ProgressReport(bool force) = 0;
};
// An implementation of V8 heap graph extractor.
class V8HeapExplorer : public HeapEntriesAllocator {
public:
V8HeapExplorer(HeapSnapshot* snapshot,
SnapshottingProgressReportingInterface* progress);
~V8HeapExplorer();
virtual HeapEntry* AllocateEntry(
HeapThing ptr, int children_count, int retainers_count);
void AddRootEntries(SnapshotFillerInterface* filler);
int EstimateObjectsCount();
bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
private: private:
bool ApproximateRetainedSizes(); HeapEntry* AddEntry(
bool BuildDominatorTree(const Vector<HeapEntry*>& entries, HeapObject* object, int children_count, int retainers_count);
Vector<HeapEntry*>* dominators); HeapEntry* AddEntry(HeapObject* object,
bool CountEntriesAndReferences(); HeapEntry::Type type,
HeapEntry* GetEntry(Object* obj); const char* name,
void IncProgressCounter() { ++progress_counter_; } int children_count,
int retainers_count);
void ExtractReferences(HeapObject* obj); void ExtractReferences(HeapObject* obj);
void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry); void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry); void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
bool FillReferences();
void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
bool IterateAndExtractReferences();
inline bool ReportProgress(bool force = false);
bool SetEntriesDominators();
void SetClosureReference(HeapObject* parent_obj, void SetClosureReference(HeapObject* parent_obj,
HeapEntry* parent, HeapEntry* parent,
String* reference_name, String* reference_name,
@ -1011,24 +1041,54 @@ class HeapSnapshotGenerator {
void SetRootShortcutReference(Object* child); void SetRootShortcutReference(Object* child);
void SetRootGcRootsReference(); void SetRootGcRootsReference();
void SetGcRootsReference(Object* child); void SetGcRootsReference(Object* child);
HeapEntry* GetEntry(Object* obj);
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
SnapshottingProgressReportingInterface* progress_;
// Used during references extraction to mark heap objects that
// are references via non-hidden properties.
HeapObjectsSet known_references_;
SnapshotFillerInterface* filler_;
static HeapObject* const kInternalRootObject;
static HeapObject* const kGcRootsObject;
friend class IndexedReferencesExtractor;
friend class RootsReferencesExtractor;
DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
};
class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
public:
HeapSnapshotGenerator(HeapSnapshot* snapshot,
v8::ActivityControl* control);
bool GenerateSnapshot();
private:
bool ApproximateRetainedSizes();
bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
Vector<HeapEntry*>* dominators);
bool CountEntriesAndReferences();
bool FillReferences();
void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
void ProgressStep();
bool ProgressReport(bool force = false);
bool SetEntriesDominators();
void SetProgressTotal(int iterations_count); void SetProgressTotal(int iterations_count);
HeapSnapshot* snapshot_; HeapSnapshot* snapshot_;
v8::ActivityControl* control_; v8::ActivityControl* control_;
HeapSnapshotsCollection* collection_; V8HeapExplorer v8_heap_explorer_;
// Mapping from HeapObject* pointers to HeapEntry* pointers. // Mapping from HeapThing pointers to HeapEntry* pointers.
HeapEntriesMap entries_; HeapEntriesMap entries_;
SnapshotFillerInterface* filler_;
// Used during references extraction to mark heap objects that
// are references via non-hidden properties.
HeapObjectsSet known_references_;
// Used during snapshot generation. // Used during snapshot generation.
int progress_counter_; int progress_counter_;
int progress_total_; int progress_total_;
friend class IndexedReferencesExtractor;
friend class RootsReferencesExtractor;
DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator); DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
}; };