Commit 07d720ec authored by loislo@chromium.org's avatar loislo@chromium.org

Detailed heap snapshot usability improvement.

The detailed heap snapshot has two groups of nodes. The first one
is the group for v8 heap nodes and the second one is the group for
native objects. At the moment we have two different sets of native
objects. There are 'Detached DOM trees' and 'Document DOM trees' type of objects.

I think it'd be nice to replace one group containing all native objects with
separate groups for different types of native objects.

BUG=none
TEST=HeapSnapshotRetainedObjectInfo

Review URL: https://chromiumcodereview.appspot.com/9223009

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10528 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a890d245
......@@ -476,11 +476,22 @@ class V8EXPORT RetainedObjectInfo { // NOLINT
virtual intptr_t GetHash() = 0;
/**
* Returns human-readable label. It must be a NUL-terminated UTF-8
* Returns human-readable label. It must be a null-terminated UTF-8
* encoded string. V8 copies its contents during a call to GetLabel.
*/
virtual const char* GetLabel() = 0;
/**
* Returns human-readable group label. It must be a null-terminated UTF-8
* encoded string. V8 copies its contents during a call to GetGroupLabel.
* Heap snapshot generator will collect all the group names, create
* top level entries with these names and attach the objects to the
* corresponding top level group objects. There is a default
* implementation which is required because embedders don't have their
* own implementation yet.
*/
virtual const char* GetGroupLabel() { return GetLabel(); }
/**
* Returns element count in case if a global handle retains
* a subgraph by holding one of its nodes.
......
......@@ -1308,19 +1308,6 @@ HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag,
}
HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count,
int retainers_count) {
ASSERT(natives_root_entry_ == NULL);
return (natives_root_entry_ = AddEntry(
HeapEntry::kObject,
"(Native objects)",
HeapObjectsMap::kNativesRootObjectId,
0,
children_count,
retainers_count));
}
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
const char* name,
uint64_t id,
......@@ -1402,10 +1389,8 @@ void HeapSnapshot::Print(int max_depth) {
const uint64_t HeapObjectsMap::kInternalRootObjectId = 1;
const uint64_t HeapObjectsMap::kGcRootsObjectId =
HeapObjectsMap::kInternalRootObjectId + HeapObjectsMap::kObjectIdStep;
const uint64_t HeapObjectsMap::kNativesRootObjectId =
HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
const uint64_t HeapObjectsMap::kGcRootsFirstSubrootId =
HeapObjectsMap::kNativesRootObjectId + HeapObjectsMap::kObjectIdStep;
HeapObjectsMap::kGcRootsObjectId + HeapObjectsMap::kObjectIdStep;
const uint64_t HeapObjectsMap::kFirstAvailableObjectId =
HeapObjectsMap::kGcRootsFirstSubrootId +
VisitorSynchronization::kNumberOfSyncTags * HeapObjectsMap::kObjectIdStep;
......@@ -2712,11 +2697,6 @@ class GlobalHandlesExtractor : public ObjectVisitor {
NativeObjectsExplorer* explorer_;
};
HeapThing const NativeObjectsExplorer::kNativesRootObject =
reinterpret_cast<HeapThing>(
static_cast<intptr_t>(HeapObjectsMap::kNativesRootObjectId));
NativeObjectsExplorer::NativeObjectsExplorer(
HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress)
: snapshot_(snapshot),
......@@ -2724,6 +2704,7 @@ NativeObjectsExplorer::NativeObjectsExplorer(
progress_(progress),
embedder_queried_(false),
objects_by_info_(RetainedInfosMatch),
native_groups_(StringsMatch),
filler_(NULL) {
}
......@@ -2744,32 +2725,22 @@ NativeObjectsExplorer::~NativeObjectsExplorer() {
HeapEntry* NativeObjectsExplorer::AllocateEntry(
HeapThing ptr, int children_count, int retainers_count) {
if (ptr == kNativesRootObject) {
return snapshot_->AddNativesRootEntry(children_count, retainers_count);
} else {
v8::RetainedObjectInfo* info =
reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
intptr_t elements = info->GetElementCount();
intptr_t size = info->GetSizeInBytes();
return snapshot_->AddEntry(
HeapEntry::kNative,
elements != -1 ?
collection_->names()->GetFormatted(
"%s / %" V8_PTR_PREFIX "d entries",
info->GetLabel(),
info->GetElementCount()) :
collection_->names()->GetCopy(info->GetLabel()),
HeapObjectsMap::GenerateId(info),
size != -1 ? static_cast<int>(size) : 0,
children_count,
retainers_count);
}
}
void NativeObjectsExplorer::AddRootEntries(SnapshotFillerInterface* filler) {
if (EstimateObjectsCount() <= 0) return;
filler->AddEntry(kNativesRootObject, this);
v8::RetainedObjectInfo* info =
reinterpret_cast<v8::RetainedObjectInfo*>(ptr);
intptr_t elements = info->GetElementCount();
intptr_t size = info->GetSizeInBytes();
return snapshot_->AddEntry(
HeapEntry::kNative,
elements != -1 ?
collection_->names()->GetFormatted(
"%s / %" V8_PTR_PREFIX "d entries",
info->GetLabel(),
info->GetElementCount()) :
collection_->names()->GetCopy(info->GetLabel()),
HeapObjectsMap::GenerateId(info),
size != -1 ? static_cast<int>(size) : 0,
children_count,
retainers_count);
}
......@@ -2835,19 +2806,61 @@ bool NativeObjectsExplorer::IterateAndExtractReferences(
SetWrapperNativeReferences(objects->at(i), info);
}
}
SetRootNativesRootReference();
SetRootNativeRootsReference();
filler_ = NULL;
return true;
}
class NativeGroupRetainedObjectInfo : public v8::RetainedObjectInfo {
public:
explicit NativeGroupRetainedObjectInfo(const char* label)
: disposed_(false),
hash_(reinterpret_cast<intptr_t>(label)),
label_(label) {
}
virtual ~NativeGroupRetainedObjectInfo() {}
virtual void Dispose() {
CHECK(!disposed_);
disposed_ = true;
}
virtual bool IsEquivalent(RetainedObjectInfo* other) {
return hash_ == other->GetHash() && !strcmp(label_, other->GetLabel());
}
virtual intptr_t GetHash() { return hash_; }
virtual const char* GetLabel() { return label_; }
private:
bool disposed_;
int hash_;
const char* label_;
};
NativeGroupRetainedObjectInfo* NativeObjectsExplorer::FindOrAddGroupInfo(
const char* label) {
const char* label_copy = collection_->names()->GetCopy(label);
intptr_t hash = HashSequentialString(label_copy, strlen(label_copy),
HEAP->HashSeed());
HashMap::Entry* entry = native_groups_.Lookup(const_cast<char*>(label_copy),
hash, true);
if (entry->value == NULL)
entry->value = new NativeGroupRetainedObjectInfo(label);
return static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
}
void NativeObjectsExplorer::SetNativeRootReference(
v8::RetainedObjectInfo* info) {
HeapEntry* child_entry = filler_->FindOrAddEntry(info, this);
ASSERT(child_entry != NULL);
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
kNativesRootObject, snapshot_->natives_root(),
NativeGroupRetainedObjectInfo* group_info =
FindOrAddGroupInfo(info->GetGroupLabel());
HeapEntry* group_entry = filler_->FindOrAddEntry(group_info, this);
filler_->SetNamedAutoIndexReference(
HeapGraphEdge::kInternal,
group_info, group_entry,
info, child_entry);
}
......@@ -2868,11 +2881,19 @@ void NativeObjectsExplorer::SetWrapperNativeReferences(
}
void NativeObjectsExplorer::SetRootNativesRootReference() {
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
V8HeapExplorer::kInternalRootObject, snapshot_->root(),
kNativesRootObject, snapshot_->natives_root());
void NativeObjectsExplorer::SetRootNativeRootsReference() {
for (HashMap::Entry* entry = native_groups_.Start();
entry;
entry = native_groups_.Next(entry)) {
NativeGroupRetainedObjectInfo* group_info =
static_cast<NativeGroupRetainedObjectInfo*>(entry->value);
HeapEntry* group_entry = filler_->FindOrAddEntry(group_info, this);
ASSERT(group_entry != NULL);
filler_->SetIndexedAutoIndexReference(
HeapGraphEdge::kElement,
V8HeapExplorer::kInternalRootObject, snapshot_->root(),
group_info, group_entry);
}
}
......@@ -3107,7 +3128,6 @@ void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
bool HeapSnapshotGenerator::CountEntriesAndReferences() {
SnapshotCounter counter(&entries_);
v8_heap_explorer_.AddRootEntries(&counter);
dom_explorer_.AddRootEntries(&counter);
return
v8_heap_explorer_.IterateAndExtractReferences(&counter) &&
dom_explorer_.IterateAndExtractReferences(&counter);
......
......@@ -1026,6 +1026,7 @@ class V8HeapExplorer : public HeapEntriesAllocator {
DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
};
class NativeGroupRetainedObjectInfo;
// An implementation of retained native objects extractor.
class NativeObjectsExplorer : public HeapEntriesAllocator {
......@@ -1043,7 +1044,7 @@ class NativeObjectsExplorer : public HeapEntriesAllocator {
void FillRetainedObjects();
List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
void SetNativeRootReference(v8::RetainedObjectInfo* info);
void SetRootNativesRootReference();
void SetRootNativeRootsReference();
void SetWrapperNativeReferences(HeapObject* wrapper,
v8::RetainedObjectInfo* info);
void VisitSubtreeWrapper(Object** p, uint16_t class_id);
......@@ -1057,6 +1058,12 @@ class NativeObjectsExplorer : public HeapEntriesAllocator {
(reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
reinterpret_cast<v8::RetainedObjectInfo*>(key2));
}
INLINE(static bool StringsMatch(void* key1, void* key2)) {
return strcmp(reinterpret_cast<char*>(key1),
reinterpret_cast<char*>(key2)) == 0;
}
NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
HeapSnapshot* snapshot_;
HeapSnapshotsCollection* collection_;
......@@ -1065,6 +1072,7 @@ class NativeObjectsExplorer : public HeapEntriesAllocator {
HeapObjectsSet in_groups_;
// RetainedObjectInfo* -> List<HeapObject*>*
HashMap objects_by_info_;
HashMap native_groups_;
// Used during references extraction.
SnapshotFillerInterface* filler_;
......
......@@ -666,11 +666,13 @@ namespace {
class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
public:
TestRetainedObjectInfo(int hash,
const char* group_label,
const char* label,
intptr_t element_count = -1,
intptr_t size = -1)
: disposed_(false),
hash_(hash),
group_label_(group_label),
label_(label),
element_count_(element_count),
size_(size) {
......@@ -685,6 +687,7 @@ class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
return GetHash() == other->GetHash();
}
virtual intptr_t GetHash() { return hash_; }
virtual const char* GetGroupLabel() { return group_label_; }
virtual const char* GetLabel() { return label_; }
virtual intptr_t GetElementCount() { return element_count_; }
virtual intptr_t GetSizeInBytes() { return size_; }
......@@ -696,15 +699,15 @@ class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
if (wrapper->IsString()) {
v8::String::AsciiValue ascii(wrapper);
if (strcmp(*ascii, "AAA") == 0)
return new TestRetainedObjectInfo(1, "aaa", 100);
return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
else if (strcmp(*ascii, "BBB") == 0)
return new TestRetainedObjectInfo(1, "aaa", 100);
return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
}
} else if (class_id == 2) {
if (wrapper->IsString()) {
v8::String::AsciiValue ascii(wrapper);
if (strcmp(*ascii, "CCC") == 0)
return new TestRetainedObjectInfo(2, "ccc");
return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
}
}
CHECK(false);
......@@ -717,6 +720,7 @@ class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
bool disposed_;
int category_;
int hash_;
const char* group_label_;
const char* label_;
intptr_t element_count_;
intptr_t size_;
......@@ -769,18 +773,21 @@ TEST(HeapSnapshotRetainedObjectInfo) {
delete TestRetainedObjectInfo::instances[i];
}
const v8::HeapGraphNode* natives = GetNode(
snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(Native objects)");
CHECK_NE(NULL, natives);
CHECK_EQ(2, natives->GetChildrenCount());
const v8::HeapGraphNode* native_group_aaa = GetNode(
snapshot->GetRoot(), v8::HeapGraphNode::kNative, "aaa-group");
CHECK_NE(NULL, native_group_aaa);
CHECK_EQ(1, native_group_aaa->GetChildrenCount());
const v8::HeapGraphNode* aaa = GetNode(
natives, v8::HeapGraphNode::kNative, "aaa / 100 entries");
native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
CHECK_NE(NULL, aaa);
CHECK_EQ(2, aaa->GetChildrenCount());
const v8::HeapGraphNode* native_group_ccc = GetNode(
snapshot->GetRoot(), v8::HeapGraphNode::kNative, "ccc-group");
const v8::HeapGraphNode* ccc = GetNode(
natives, v8::HeapGraphNode::kNative, "ccc");
native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
CHECK_NE(NULL, ccc);
CHECK_EQ(2, aaa->GetChildrenCount());
const v8::HeapGraphNode* n_AAA = GetNode(
aaa, v8::HeapGraphNode::kString, "AAA");
CHECK_NE(NULL, n_AAA);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment