Heap profiler improvements.

- account code objects in retainers profile;
- differentiate between function boilerplates and closures;
- simplify code;

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3124 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8a1fdd35
...@@ -78,6 +78,10 @@ JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) { ...@@ -78,6 +78,10 @@ JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) {
} }
} else if (obj->IsString()) { } else if (obj->IsString()) {
return JSObjectsCluster(Heap::String_symbol()); return JSObjectsCluster(Heap::String_symbol());
} else if (obj->IsJSGlobalPropertyCell()) {
return JSObjectsCluster(JSObjectsCluster::GLOBAL_PROPERTY);
} else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) {
return JSObjectsCluster(JSObjectsCluster::CODE);
} }
return JSObjectsCluster(); return JSObjectsCluster();
} }
...@@ -112,6 +116,16 @@ int Clusterizer::CalculateNetworkSize(JSObject* obj) { ...@@ -112,6 +116,16 @@ int Clusterizer::CalculateNetworkSize(JSObject* obj) {
if (FixedArray::cast(obj->elements())->length() != 0) { if (FixedArray::cast(obj->elements())->length() != 0) {
size += obj->elements()->Size(); size += obj->elements()->Size();
} }
// For functions, also account non-empty context and literals sizes.
if (obj->IsJSFunction()) {
JSFunction* f = JSFunction::cast(obj);
if (f->unchecked_context()->IsContext()) {
size += f->context()->Size();
}
if (f->literals()->length() != 0) {
size += f->literals()->Size();
}
}
return size; return size;
} }
...@@ -127,15 +141,15 @@ class ReferencesExtractor : public ObjectVisitor { ...@@ -127,15 +141,15 @@ class ReferencesExtractor : public ObjectVisitor {
} }
void VisitPointer(Object** o) { void VisitPointer(Object** o) {
if ((*o)->IsJSObject() || (*o)->IsString()) { if ((*o)->IsFixedArray() && !inside_array_) {
profile_->StoreReference(cluster_, HeapObject::cast(*o));
} else if ((*o)->IsFixedArray() && !inside_array_) {
// Traverse one level deep for data members that are fixed arrays. // Traverse one level deep for data members that are fixed arrays.
// This covers the case of 'elements' and 'properties' of JSObject, // This covers the case of 'elements' and 'properties' of JSObject,
// and function contexts. // and function contexts.
inside_array_ = true; inside_array_ = true;
FixedArray::cast(*o)->Iterate(this); FixedArray::cast(*o)->Iterate(this);
inside_array_ = false; inside_array_ = false;
} else {
profile_->StoreReference(cluster_, HeapObject::cast(*o));
} }
} }
...@@ -340,6 +354,8 @@ void JSObjectsCluster::Print(StringStream* accumulator) const { ...@@ -340,6 +354,8 @@ void JSObjectsCluster::Print(StringStream* accumulator) const {
accumulator->Add("(roots)"); accumulator->Add("(roots)");
} else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) { } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) {
accumulator->Add("(global property)"); accumulator->Add("(global property)");
} else if (constructor_ == FromSpecialCase(CODE)) {
accumulator->Add("(code)");
} else if (constructor_ == FromSpecialCase(SELF)) { } else if (constructor_ == FromSpecialCase(SELF)) {
accumulator->Add("(self)"); accumulator->Add("(self)");
} else { } else {
...@@ -527,6 +543,7 @@ RetainerHeapProfile::RetainerHeapProfile() ...@@ -527,6 +543,7 @@ RetainerHeapProfile::RetainerHeapProfile()
void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster, void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
HeapObject* ref) { HeapObject* ref) {
JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref); JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref);
if (ref_cluster.is_null()) return;
JSObjectsRetainerTree::Locator ref_loc; JSObjectsRetainerTree::Locator ref_loc;
if (retainers_tree_.Insert(ref_cluster, &ref_loc)) { if (retainers_tree_.Insert(ref_cluster, &ref_loc)) {
ref_loc.set_value(new JSObjectsClusterTree()); ref_loc.set_value(new JSObjectsClusterTree());
...@@ -537,15 +554,10 @@ void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster, ...@@ -537,15 +554,10 @@ void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
void RetainerHeapProfile::CollectStats(HeapObject* obj) { void RetainerHeapProfile::CollectStats(HeapObject* obj) {
if (obj->IsJSObject()) { const JSObjectsCluster cluster = Clusterizer::Clusterize(obj);
const JSObjectsCluster cluster = Clusterizer::Clusterize(obj); if (cluster.is_null()) return;
ReferencesExtractor extractor(cluster, this); ReferencesExtractor extractor(cluster, this);
obj->Iterate(&extractor); obj->Iterate(&extractor);
} else if (obj->IsJSGlobalPropertyCell()) {
JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY);
ReferencesExtractor extractor(global_prop, this);
obj->Iterate(&extractor);
}
} }
......
...@@ -54,7 +54,8 @@ class JSObjectsCluster BASE_EMBEDDED { ...@@ -54,7 +54,8 @@ class JSObjectsCluster BASE_EMBEDDED {
enum SpecialCase { enum SpecialCase {
ROOTS = 1, ROOTS = 1,
GLOBAL_PROPERTY = 2, GLOBAL_PROPERTY = 2,
SELF = 3 // This case is used in ClustersCoarser only. CODE = 3,
SELF = 100 // This case is used in ClustersCoarser only.
}; };
JSObjectsCluster() : constructor_(NULL), instance_(NULL) {} JSObjectsCluster() : constructor_(NULL), instance_(NULL) {}
...@@ -97,6 +98,7 @@ class JSObjectsCluster BASE_EMBEDDED { ...@@ -97,6 +98,7 @@ class JSObjectsCluster BASE_EMBEDDED {
switch (special) { switch (special) {
case ROOTS: return Heap::result_symbol(); case ROOTS: return Heap::result_symbol();
case GLOBAL_PROPERTY: return Heap::code_symbol(); case GLOBAL_PROPERTY: return Heap::code_symbol();
case CODE: return Heap::arguments_shadow_symbol();
case SELF: return Heap::catch_var_symbol(); case SELF: return Heap::catch_var_symbol();
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -221,7 +221,8 @@ namespace internal { ...@@ -221,7 +221,8 @@ namespace internal {
V(exec_symbol, "exec") \ V(exec_symbol, "exec") \
V(zero_symbol, "0") \ V(zero_symbol, "0") \
V(global_eval_symbol, "GlobalEval") \ V(global_eval_symbol, "GlobalEval") \
V(identity_hash_symbol, "v8::IdentityHash") V(identity_hash_symbol, "v8::IdentityHash") \
V(closure_symbol, "(closure)")
// Forward declaration of the GCTracer class. // Forward declaration of the GCTracer class.
......
...@@ -1251,7 +1251,8 @@ String* JSObject::class_name() { ...@@ -1251,7 +1251,8 @@ String* JSObject::class_name() {
String* JSObject::constructor_name() { String* JSObject::constructor_name() {
if (IsJSFunction()) { if (IsJSFunction()) {
return Heap::function_class_symbol(); return JSFunction::cast(this)->IsBoilerplate() ?
Heap::function_class_symbol() : Heap::closure_symbol();
} }
if (map()->constructor()->IsJSFunction()) { if (map()->constructor()->IsJSFunction()) {
JSFunction* constructor = JSFunction::cast(map()->constructor()); JSFunction* constructor = JSFunction::cast(map()->constructor());
......
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