Commit f6b7ec4d authored by loislo@chromium.org's avatar loislo@chromium.org

HeapProfiler: very slow ~4min "take snapshot time" for 80MB gmail heap.

The reason of that is a number of cons strings in the app.
The app constructs a json string and as a result v8 heap has
a very long chain of cons strings.

Profiler counts all these strings as plain String objects and
assign the content of the strings as node names.

It required O(n^2) time and O(n^2) memory.

Solution: I introduced two new types, kConsString and kSliced string.
They do not use the content of the string for names. So the problem disappeared.

The heap profiler usability problem will be solved on Blink side.

BUG=285770
R=yangguo@chromium.org

Review URL: https://codereview.chromium.org/23460027

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16611 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8b280df4
...@@ -246,17 +246,19 @@ class V8_EXPORT HeapGraphEdge { ...@@ -246,17 +246,19 @@ class V8_EXPORT HeapGraphEdge {
class V8_EXPORT HeapGraphNode { class V8_EXPORT HeapGraphNode {
public: public:
enum Type { enum Type {
kHidden = 0, // Hidden node, may be filtered when shown to user. kHidden = 0, // Hidden node, may be filtered when shown to user.
kArray = 1, // An array of elements. kArray = 1, // An array of elements.
kString = 2, // A string. kString = 2, // A string.
kObject = 3, // A JS object (except for arrays and strings). kObject = 3, // A JS object (except for arrays and strings).
kCode = 4, // Compiled code. kCode = 4, // Compiled code.
kClosure = 5, // Function closure. kClosure = 5, // Function closure.
kRegExp = 6, // RegExp. kRegExp = 6, // RegExp.
kHeapNumber = 7, // Number stored in the heap. kHeapNumber = 7, // Number stored in the heap.
kNative = 8, // Native object (not from V8 heap). kNative = 8, // Native object (not from V8 heap).
kSynthetic = 9 // Synthetic object, usualy used for grouping kSynthetic = 9, // Synthetic object, usualy used for grouping
// snapshot items together. // snapshot items together.
kConsString = 10, // Concatenated string. A pair of pointers to strings.
kSlicedString = 11 // Sliced string. A fragment of another string.
}; };
/** Returns node type (see HeapGraphNode::Type). */ /** Returns node type (see HeapGraphNode::Type). */
......
...@@ -175,6 +175,8 @@ const char* HeapEntry::TypeAsString() { ...@@ -175,6 +175,8 @@ const char* HeapEntry::TypeAsString() {
case kHeapNumber: return "/number/"; case kHeapNumber: return "/number/";
case kNative: return "/native/"; case kNative: return "/native/";
case kSynthetic: return "/synthetic/"; case kSynthetic: return "/synthetic/";
case kConsString: return "/concatenated string/";
case kSlicedString: return "/sliced string/";
default: return "???"; default: return "???";
} }
} }
...@@ -782,6 +784,15 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { ...@@ -782,6 +784,15 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) {
} }
return AddEntry(object, HeapEntry::kObject, name); return AddEntry(object, HeapEntry::kObject, name);
} else if (object->IsString()) { } else if (object->IsString()) {
String* string = String::cast(object);
if (string->IsConsString())
return AddEntry(object,
HeapEntry::kConsString,
"(concatenated string)");
if (string->IsSlicedString())
return AddEntry(object,
HeapEntry::kSlicedString,
"(sliced string)");
return AddEntry(object, return AddEntry(object,
HeapEntry::kString, HeapEntry::kString,
collection_->names()->GetName(String::cast(object))); collection_->names()->GetName(String::cast(object)));
...@@ -2585,7 +2596,9 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() { ...@@ -2585,7 +2596,9 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
JSON_S("regexp") "," JSON_S("regexp") ","
JSON_S("number") "," JSON_S("number") ","
JSON_S("native") "," JSON_S("native") ","
JSON_S("synthetic")) "," JSON_S("synthetic") ","
JSON_S("concatenated string") ","
JSON_S("sliced string")) ","
JSON_S("string") "," JSON_S("string") ","
JSON_S("number") "," JSON_S("number") ","
JSON_S("number") "," JSON_S("number") ","
......
...@@ -100,7 +100,9 @@ class HeapEntry BASE_EMBEDDED { ...@@ -100,7 +100,9 @@ class HeapEntry BASE_EMBEDDED {
kRegExp = v8::HeapGraphNode::kRegExp, kRegExp = v8::HeapGraphNode::kRegExp,
kHeapNumber = v8::HeapGraphNode::kHeapNumber, kHeapNumber = v8::HeapGraphNode::kHeapNumber,
kNative = v8::HeapGraphNode::kNative, kNative = v8::HeapGraphNode::kNative,
kSynthetic = v8::HeapGraphNode::kSynthetic kSynthetic = v8::HeapGraphNode::kSynthetic,
kConsString = v8::HeapGraphNode::kConsString,
kSlicedString = v8::HeapGraphNode::kSlicedString
}; };
static const int kNoEntry; static const int kNoEntry;
......
...@@ -404,12 +404,57 @@ TEST(HeapSnapshotSlicedString) { ...@@ -404,12 +404,57 @@ TEST(HeapSnapshotSlicedString) {
const v8::HeapGraphNode* child_string = const v8::HeapGraphNode* child_string =
GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string"); GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string");
CHECK_NE(NULL, child_string); CHECK_NE(NULL, child_string);
CHECK_EQ(v8::HeapGraphNode::kSlicedString, child_string->GetType());
const v8::HeapGraphNode* parent = const v8::HeapGraphNode* parent =
GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent"); GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
CHECK_EQ(parent_string, parent); CHECK_EQ(parent_string, parent);
heap_profiler->DeleteAllHeapSnapshots();
} }
TEST(HeapSnapshotConsString) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
global_template->SetInternalFieldCount(1);
LocalContext env(NULL, global_template);
v8::Handle<v8::Object> global_proxy = env->Global();
v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
CHECK_EQ(1, global->InternalFieldCount());
i::Factory* factory = i::Isolate::Current()->factory();
i::Handle<i::String> first =
factory->NewStringFromAscii(i::CStrVector("0123456789"));
i::Handle<i::String> second =
factory->NewStringFromAscii(i::CStrVector("0123456789"));
i::Handle<i::String> cons_string = factory->NewConsString(first, second);
global->SetInternalField(0, v8::ToApiHandle<v8::String>(cons_string));
v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
const v8::HeapSnapshot* snapshot =
heap_profiler->TakeHeapSnapshot(v8_str("cons_strings"));
CHECK(ValidateSnapshot(snapshot));
const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
const v8::HeapGraphNode* string_node =
GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0");
CHECK_NE(NULL, string_node);
CHECK_EQ(v8::HeapGraphNode::kConsString, string_node->GetType());
const v8::HeapGraphNode* first_node =
GetProperty(string_node, v8::HeapGraphEdge::kInternal, "first");
CHECK_EQ(v8::HeapGraphNode::kString, first_node->GetType());
const v8::HeapGraphNode* second_node =
GetProperty(string_node, v8::HeapGraphEdge::kInternal, "second");
CHECK_EQ(v8::HeapGraphNode::kString, second_node->GetType());
heap_profiler->DeleteAllHeapSnapshots();
}
TEST(HeapSnapshotInternalReferences) { TEST(HeapSnapshotInternalReferences) {
v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate); v8::HandleScope scope(isolate);
......
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