Heap profiler: reduce heap snapshots size.

The size of a snapshot is now 65-80% of the JS heap size (tested on
GMail and Wave), previously it was >200%.

BUG=783

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5211 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c3833657
...@@ -194,10 +194,10 @@ class HeapGraphNode; ...@@ -194,10 +194,10 @@ class HeapGraphNode;
class V8EXPORT HeapGraphEdge { class V8EXPORT HeapGraphEdge {
public: public:
enum Type { enum Type {
CONTEXT_VARIABLE = 0, // A variable from a function context. kContextVariable = 0, // A variable from a function context.
ELEMENT = 1, // An element of an array. kElement = 1, // An element of an array.
PROPERTY = 2, // A named object property. kProperty = 2, // A named object property.
INTERNAL = 3 // A link that can't be accessed from JS, kInternal = 3 // A link that can't be accessed from JS,
// thus, its name isn't a real property name. // thus, its name isn't a real property name.
}; };
...@@ -240,12 +240,12 @@ class V8EXPORT HeapGraphPath { ...@@ -240,12 +240,12 @@ class V8EXPORT HeapGraphPath {
class V8EXPORT HeapGraphNode { class V8EXPORT HeapGraphNode {
public: public:
enum Type { enum Type {
INTERNAL = 0, // Internal node, a virtual one, for housekeeping. kInternal = 0, // Internal node, a virtual one, for housekeeping.
ARRAY = 1, // An array of elements. kArray = 1, // An array of elements.
STRING = 2, // A string. kString = 2, // A string.
OBJECT = 3, // A JS object (except for arrays and strings). kObject = 3, // A JS object (except for arrays and strings).
CODE = 4, // Compiled code. kCode = 4, // Compiled code.
CLOSURE = 5 // Function closure. kClosure = 5 // Function closure.
}; };
/** Returns node type (see HeapGraphNode::Type). */ /** Returns node type (see HeapGraphNode::Type). */
...@@ -268,13 +268,15 @@ class V8EXPORT HeapGraphNode { ...@@ -268,13 +268,15 @@ class V8EXPORT HeapGraphNode {
int GetSelfSize() const; int GetSelfSize() const;
/** Returns node's network (self + reachable nodes) size, in bytes. */ /** Returns node's network (self + reachable nodes) size, in bytes. */
int GetTotalSize() const; int GetReachableSize() const;
/** /**
* Returns node's private size, in bytes. That is, the size of memory * Returns node's retained size, in bytes. That is, self + sizes of
* that will be reclaimed having this node collected. * the objects that are reachable only from this object. In other
* words, the size of memory that will be reclaimed having this node
* collected.
*/ */
int GetPrivateSize() const; int GetRetainedSize() const;
/** Returns child nodes count of the node. */ /** Returns child nodes count of the node. */
int GetChildrenCount() const; int GetChildrenCount() const;
......
...@@ -4491,24 +4491,27 @@ const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title, ...@@ -4491,24 +4491,27 @@ const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title,
} }
static i::HeapGraphEdge* ToInternal(const HeapGraphEdge* edge) {
return const_cast<i::HeapGraphEdge*>(
reinterpret_cast<const i::HeapGraphEdge*>(edge));
}
HeapGraphEdge::Type HeapGraphEdge::GetType() const { HeapGraphEdge::Type HeapGraphEdge::GetType() const {
IsDeadCheck("v8::HeapGraphEdge::GetType"); IsDeadCheck("v8::HeapGraphEdge::GetType");
return static_cast<HeapGraphEdge::Type>( return static_cast<HeapGraphEdge::Type>(ToInternal(this)->type());
reinterpret_cast<const i::HeapGraphEdge*>(this)->type());
} }
Handle<Value> HeapGraphEdge::GetName() const { Handle<Value> HeapGraphEdge::GetName() const {
IsDeadCheck("v8::HeapGraphEdge::GetName"); IsDeadCheck("v8::HeapGraphEdge::GetName");
const i::HeapGraphEdge* edge = i::HeapGraphEdge* edge = ToInternal(this);
reinterpret_cast<const i::HeapGraphEdge*>(this);
switch (edge->type()) { switch (edge->type()) {
case i::HeapGraphEdge::CONTEXT_VARIABLE: case i::HeapGraphEdge::kContextVariable:
case i::HeapGraphEdge::INTERNAL: case i::HeapGraphEdge::kInternal:
case i::HeapGraphEdge::PROPERTY: case i::HeapGraphEdge::kProperty:
return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol( return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
edge->name()))); edge->name())));
case i::HeapGraphEdge::ELEMENT: case i::HeapGraphEdge::kElement:
return Handle<Number>(ToApi<Number>(i::Factory::NewNumberFromInt( return Handle<Number>(ToApi<Number>(i::Factory::NewNumberFromInt(
edge->index()))); edge->index())));
default: UNREACHABLE(); default: UNREACHABLE();
...@@ -4519,28 +4522,32 @@ Handle<Value> HeapGraphEdge::GetName() const { ...@@ -4519,28 +4522,32 @@ Handle<Value> HeapGraphEdge::GetName() const {
const HeapGraphNode* HeapGraphEdge::GetFromNode() const { const HeapGraphNode* HeapGraphEdge::GetFromNode() const {
IsDeadCheck("v8::HeapGraphEdge::GetFromNode"); IsDeadCheck("v8::HeapGraphEdge::GetFromNode");
const i::HeapEntry* from = const i::HeapEntry* from = ToInternal(this)->From();
reinterpret_cast<const i::HeapGraphEdge*>(this)->from();
return reinterpret_cast<const HeapGraphNode*>(from); return reinterpret_cast<const HeapGraphNode*>(from);
} }
const HeapGraphNode* HeapGraphEdge::GetToNode() const { const HeapGraphNode* HeapGraphEdge::GetToNode() const {
IsDeadCheck("v8::HeapGraphEdge::GetToNode"); IsDeadCheck("v8::HeapGraphEdge::GetToNode");
const i::HeapEntry* to = const i::HeapEntry* to = ToInternal(this)->to();
reinterpret_cast<const i::HeapGraphEdge*>(this)->to();
return reinterpret_cast<const HeapGraphNode*>(to); return reinterpret_cast<const HeapGraphNode*>(to);
} }
static i::HeapGraphPath* ToInternal(const HeapGraphPath* path) {
return const_cast<i::HeapGraphPath*>(
reinterpret_cast<const i::HeapGraphPath*>(path));
}
int HeapGraphPath::GetEdgesCount() const { int HeapGraphPath::GetEdgesCount() const {
return reinterpret_cast<const i::HeapGraphPath*>(this)->path()->length(); return ToInternal(this)->path()->length();
} }
const HeapGraphEdge* HeapGraphPath::GetEdge(int index) const { const HeapGraphEdge* HeapGraphPath::GetEdge(int index) const {
return reinterpret_cast<const HeapGraphEdge*>( return reinterpret_cast<const HeapGraphEdge*>(
reinterpret_cast<const i::HeapGraphPath*>(this)->path()->at(index)); ToInternal(this)->path()->at(index));
} }
...@@ -4555,137 +4562,136 @@ const HeapGraphNode* HeapGraphPath::GetToNode() const { ...@@ -4555,137 +4562,136 @@ const HeapGraphNode* HeapGraphPath::GetToNode() const {
} }
static i::HeapEntry* ToInternal(const HeapGraphNode* entry) {
return const_cast<i::HeapEntry*>(
reinterpret_cast<const i::HeapEntry*>(entry));
}
HeapGraphNode::Type HeapGraphNode::GetType() const { HeapGraphNode::Type HeapGraphNode::GetType() const {
IsDeadCheck("v8::HeapGraphNode::GetType"); IsDeadCheck("v8::HeapGraphNode::GetType");
return static_cast<HeapGraphNode::Type>( return static_cast<HeapGraphNode::Type>(ToInternal(this)->type());
reinterpret_cast<const i::HeapEntry*>(this)->type());
} }
Handle<String> HeapGraphNode::GetName() const { Handle<String> HeapGraphNode::GetName() const {
IsDeadCheck("v8::HeapGraphNode::GetName"); IsDeadCheck("v8::HeapGraphNode::GetName");
return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol( return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
reinterpret_cast<const i::HeapEntry*>(this)->name()))); ToInternal(this)->name())));
} }
uint64_t HeapGraphNode::GetId() const { uint64_t HeapGraphNode::GetId() const {
IsDeadCheck("v8::HeapGraphNode::GetId"); IsDeadCheck("v8::HeapGraphNode::GetId");
return reinterpret_cast<const i::HeapEntry*>(this)->id(); return ToInternal(this)->id();
} }
int HeapGraphNode::GetSelfSize() const { int HeapGraphNode::GetSelfSize() const {
IsDeadCheck("v8::HeapGraphNode::GetSelfSize"); IsDeadCheck("v8::HeapGraphNode::GetSelfSize");
return reinterpret_cast<const i::HeapEntry*>(this)->self_size(); return ToInternal(this)->self_size();
} }
int HeapGraphNode::GetTotalSize() const { int HeapGraphNode::GetReachableSize() const {
IsDeadCheck("v8::HeapSnapshot::GetHead"); IsDeadCheck("v8::HeapSnapshot::GetReachableSize");
return const_cast<i::HeapEntry*>( return ToInternal(this)->ReachableSize();
reinterpret_cast<const i::HeapEntry*>(this))->TotalSize();
} }
int HeapGraphNode::GetPrivateSize() const { int HeapGraphNode::GetRetainedSize() const {
IsDeadCheck("v8::HeapSnapshot::GetPrivateSize"); IsDeadCheck("v8::HeapSnapshot::GetRetainedSize");
return const_cast<i::HeapEntry*>( return ToInternal(this)->RetainedSize();
reinterpret_cast<const i::HeapEntry*>(this))->NonSharedTotalSize();
} }
int HeapGraphNode::GetChildrenCount() const { int HeapGraphNode::GetChildrenCount() const {
IsDeadCheck("v8::HeapSnapshot::GetChildrenCount"); IsDeadCheck("v8::HeapSnapshot::GetChildrenCount");
return reinterpret_cast<const i::HeapEntry*>(this)->children()->length(); return ToInternal(this)->children().length();
} }
const HeapGraphEdge* HeapGraphNode::GetChild(int index) const { const HeapGraphEdge* HeapGraphNode::GetChild(int index) const {
IsDeadCheck("v8::HeapSnapshot::GetChild"); IsDeadCheck("v8::HeapSnapshot::GetChild");
return reinterpret_cast<const HeapGraphEdge*>( return reinterpret_cast<const HeapGraphEdge*>(
reinterpret_cast<const i::HeapEntry*>(this)->children()->at(index)); &ToInternal(this)->children()[index]);
} }
int HeapGraphNode::GetRetainersCount() const { int HeapGraphNode::GetRetainersCount() const {
IsDeadCheck("v8::HeapSnapshot::GetRetainersCount"); IsDeadCheck("v8::HeapSnapshot::GetRetainersCount");
return reinterpret_cast<const i::HeapEntry*>(this)->retainers()->length(); return ToInternal(this)->retainers().length();
} }
const HeapGraphEdge* HeapGraphNode::GetRetainer(int index) const { const HeapGraphEdge* HeapGraphNode::GetRetainer(int index) const {
IsDeadCheck("v8::HeapSnapshot::GetRetainer"); IsDeadCheck("v8::HeapSnapshot::GetRetainer");
return reinterpret_cast<const HeapGraphEdge*>( return reinterpret_cast<const HeapGraphEdge*>(
reinterpret_cast<const i::HeapEntry*>(this)->retainers()->at(index)); ToInternal(this)->retainers()[index]);
} }
int HeapGraphNode::GetRetainingPathsCount() const { int HeapGraphNode::GetRetainingPathsCount() const {
IsDeadCheck("v8::HeapSnapshot::GetRetainingPathsCount"); IsDeadCheck("v8::HeapSnapshot::GetRetainingPathsCount");
return const_cast<i::HeapEntry*>( return ToInternal(this)->GetRetainingPaths()->length();
reinterpret_cast<const i::HeapEntry*>(
this))->GetRetainingPaths()->length();
} }
const HeapGraphPath* HeapGraphNode::GetRetainingPath(int index) const { const HeapGraphPath* HeapGraphNode::GetRetainingPath(int index) const {
IsDeadCheck("v8::HeapSnapshot::GetRetainingPath"); IsDeadCheck("v8::HeapSnapshot::GetRetainingPath");
return reinterpret_cast<const HeapGraphPath*>( return reinterpret_cast<const HeapGraphPath*>(
const_cast<i::HeapEntry*>( ToInternal(this)->GetRetainingPaths()->at(index));
reinterpret_cast<const i::HeapEntry*>(
this))->GetRetainingPaths()->at(index));
} }
const HeapGraphNode* HeapSnapshotsDiff::GetAdditionsRoot() const { const HeapGraphNode* HeapSnapshotsDiff::GetAdditionsRoot() const {
IsDeadCheck("v8::HeapSnapshotsDiff::GetAdditionsRoot"); IsDeadCheck("v8::HeapSnapshotsDiff::GetAdditionsRoot");
const i::HeapSnapshotsDiff* diff = i::HeapSnapshotsDiff* diff =
reinterpret_cast<const i::HeapSnapshotsDiff*>(this); const_cast<i::HeapSnapshotsDiff*>(
reinterpret_cast<const i::HeapSnapshotsDiff*>(this));
return reinterpret_cast<const HeapGraphNode*>(diff->additions_root()); return reinterpret_cast<const HeapGraphNode*>(diff->additions_root());
} }
const HeapGraphNode* HeapSnapshotsDiff::GetDeletionsRoot() const { const HeapGraphNode* HeapSnapshotsDiff::GetDeletionsRoot() const {
IsDeadCheck("v8::HeapSnapshotsDiff::GetDeletionsRoot"); IsDeadCheck("v8::HeapSnapshotsDiff::GetDeletionsRoot");
const i::HeapSnapshotsDiff* diff = i::HeapSnapshotsDiff* diff =
reinterpret_cast<const i::HeapSnapshotsDiff*>(this); const_cast<i::HeapSnapshotsDiff*>(
reinterpret_cast<const i::HeapSnapshotsDiff*>(this));
return reinterpret_cast<const HeapGraphNode*>(diff->deletions_root()); return reinterpret_cast<const HeapGraphNode*>(diff->deletions_root());
} }
static i::HeapSnapshot* ToInternal(const HeapSnapshot* snapshot) {
return const_cast<i::HeapSnapshot*>(
reinterpret_cast<const i::HeapSnapshot*>(snapshot));
}
unsigned HeapSnapshot::GetUid() const { unsigned HeapSnapshot::GetUid() const {
IsDeadCheck("v8::HeapSnapshot::GetUid"); IsDeadCheck("v8::HeapSnapshot::GetUid");
return reinterpret_cast<const i::HeapSnapshot*>(this)->uid(); return ToInternal(this)->uid();
} }
Handle<String> HeapSnapshot::GetTitle() const { Handle<String> HeapSnapshot::GetTitle() const {
IsDeadCheck("v8::HeapSnapshot::GetTitle"); IsDeadCheck("v8::HeapSnapshot::GetTitle");
const i::HeapSnapshot* snapshot =
reinterpret_cast<const i::HeapSnapshot*>(this);
return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol( return Handle<String>(ToApi<String>(i::Factory::LookupAsciiSymbol(
snapshot->title()))); ToInternal(this)->title())));
} }
const HeapGraphNode* HeapSnapshot::GetRoot() const { const HeapGraphNode* HeapSnapshot::GetRoot() const {
IsDeadCheck("v8::HeapSnapshot::GetHead"); IsDeadCheck("v8::HeapSnapshot::GetHead");
const i::HeapSnapshot* snapshot = return reinterpret_cast<const HeapGraphNode*>(ToInternal(this)->root());
reinterpret_cast<const i::HeapSnapshot*>(this);
return reinterpret_cast<const HeapGraphNode*>(snapshot->const_root());
} }
const HeapSnapshotsDiff* HeapSnapshot::CompareWith( const HeapSnapshotsDiff* HeapSnapshot::CompareWith(
const HeapSnapshot* snapshot) const { const HeapSnapshot* snapshot) const {
IsDeadCheck("v8::HeapSnapshot::CompareWith"); IsDeadCheck("v8::HeapSnapshot::CompareWith");
i::HeapSnapshot* snapshot1 = const_cast<i::HeapSnapshot*>(
reinterpret_cast<const i::HeapSnapshot*>(this));
i::HeapSnapshot* snapshot2 = const_cast<i::HeapSnapshot*>(
reinterpret_cast<const i::HeapSnapshot*>(snapshot));
return reinterpret_cast<const HeapSnapshotsDiff*>( return reinterpret_cast<const HeapSnapshotsDiff*>(
snapshot1->CompareWith(snapshot2)); ToInternal(this)->CompareWith(ToInternal(snapshot)));
} }
......
...@@ -126,6 +126,13 @@ void List<T, P>::Iterate(void (*callback)(T* x)) { ...@@ -126,6 +126,13 @@ void List<T, P>::Iterate(void (*callback)(T* x)) {
} }
template<typename T, class P>
template<class Visitor>
void List<T, P>::Iterate(Visitor* visitor) {
for (int i = 0; i < length_; i++) visitor->Apply(&data_[i]);
}
template<typename T, class P> template<typename T, class P>
bool List<T, P>::Contains(const T& elm) { bool List<T, P>::Contains(const T& elm) {
for (int i = 0; i < length_; i++) { for (int i = 0; i < length_; i++) {
......
...@@ -117,6 +117,8 @@ class List { ...@@ -117,6 +117,8 @@ class List {
// Iterate through all list entries, starting at index 0. // Iterate through all list entries, starting at index 0.
void Iterate(void (*callback)(T* x)); void Iterate(void (*callback)(T* x));
template<class Visitor>
void Iterate(Visitor* visitor);
// Sort all list entries (using QuickSort) // Sort all list entries (using QuickSort)
void Sort(int (*cmp)(const T* x, const T* y)); void Sort(int (*cmp)(const T* x, const T* y));
......
...@@ -130,17 +130,6 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { ...@@ -130,17 +130,6 @@ CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
} }
} }
template<class Visitor>
void HeapEntriesMap::Apply(Visitor* visitor) {
for (HashMap::Entry* p = entries_.Start();
p != NULL;
p = entries_.Next(p)) {
if (!IsAlias(p->value))
visitor->Apply(reinterpret_cast<HeapEntry*>(p->value));
}
}
} } // namespace v8::internal } } // namespace v8::internal
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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