Reviewers: alph, Yury Semikhatsky, Yang,
Message:
On 2013/09/10 08:47:56, Yang wrote:
Having the string content appear as name seems valuable. How about
setting a
certain limit so that we stringify only strings with lengths below that
limit?
That way, whether to show string content would not depend on the string
type.
we have had 1k limit for the strings but
it doesn't solve the problem because the cons string uses only 40 bytes.
So in our case we use 25 times more memory.
I will reconstruct and show the content of the cons and sliced strings on
DevTools front-end side.
Usually we show only 100 strings at a time. So it wouldn't be a performance
issue.
Description:
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
Please review this at https://codereview.chromium.org/23460027/
SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge
Affected files (+75, -13 lines):
M include/v8-profiler.h
M src/heap-snapshot-generator.h
M src/heap-snapshot-generator.cc
M test/cctest/test-heap-profiler.cc
Index: include/v8-profiler.h
diff --git a/include/v8-profiler.h b/include/v8-profiler.h
index
d7350db9f372006208a5227ad195cd0595636bf7..217a938329eee70f9483f8d84ef8654c59907a1d
100644
--- a/include/v8-profiler.h
+++ b/include/v8-profiler.h
@@ -246,17 +246,19 @@ class V8_EXPORT HeapGraphEdge {
class V8_EXPORT HeapGraphNode {
public:
enum Type {
- kHidden = 0, // Hidden node, may be filtered when shown to user.
- kArray = 1, // An array of elements.
- kString = 2, // A string.
- kObject = 3, // A JS object (except for arrays and strings).
- kCode = 4, // Compiled code.
- kClosure = 5, // Function closure.
- kRegExp = 6, // RegExp.
- kHeapNumber = 7, // Number stored in the heap.
- kNative = 8, // Native object (not from V8 heap).
- kSynthetic = 9 // Synthetic object, usualy used for grouping
- // snapshot items together.
+ kHidden = 0, // Hidden node, may be filtered when shown to user.
+ kArray = 1, // An array of elements.
+ kString = 2, // A string.
+ kObject = 3, // A JS object (except for arrays and strings).
+ kCode = 4, // Compiled code.
+ kClosure = 5, // Function closure.
+ kRegExp = 6, // RegExp.
+ kHeapNumber = 7, // Number stored in the heap.
+ kNative = 8, // Native object (not from V8 heap).
+ kSynthetic = 9, // Synthetic object, usualy used for grouping
+ // 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). */
Index: src/heap-snapshot-generator.cc
diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc
index
6a5bb63a0ea2a50e5ee737a31bd52ddd9b116db3..99c20404f00b5418f5d53ccda30f0d52dde0fc47
100644
--- a/src/heap-snapshot-generator.cc
+++ b/src/heap-snapshot-generator.cc
@@ -175,6 +175,8 @@ const char* HeapEntry::TypeAsString() {
case kHeapNumber: return "/number/";
case kNative: return "/native/";
case kSynthetic: return "/synthetic/";
+ case kConsString: return "/concatenated string/";
+ case kSlicedString: return "/sliced string/";
default: return "???";
}
}
@@ -782,6 +784,15 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject*
object) {
}
return AddEntry(object, HeapEntry::kObject, name);
} 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,
HeapEntry::kString,
collection_->names()->GetName(String::cast(object)));
@@ -2585,7 +2596,9 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
JSON_S("regexp") ","
JSON_S("number") ","
JSON_S("native") ","
- JSON_S("synthetic")) ","
+ JSON_S("synthetic") ","
+ JSON_S("concatenated string") ","
+ JSON_S("sliced string")) ","
JSON_S("string") ","
JSON_S("number") ","
JSON_S("number") ","
Index: src/heap-snapshot-generator.h
diff --git a/src/heap-snapshot-generator.h b/src/heap-snapshot-generator.h
index
ccdcab4a36e820ec14aedab842051f030ec1d397..52cfafd2c186fb0b26ef245066ccaf6c6de2abb1
100644
--- a/src/heap-snapshot-generator.h
+++ b/src/heap-snapshot-generator.h
@@ -100,7 +100,9 @@ class HeapEntry BASE_EMBEDDED {
kRegExp = v8::HeapGraphNode::kRegExp,
kHeapNumber = v8::HeapGraphNode::kHeapNumber,
kNative = v8::HeapGraphNode::kNative,
- kSynthetic = v8::HeapGraphNode::kSynthetic
+ kSynthetic = v8::HeapGraphNode::kSynthetic,
+ kConsString = v8::HeapGraphNode::kConsString,
+ kSlicedString = v8::HeapGraphNode::kSlicedString
};
static const int kNoEntry;
Index: test/cctest/test-heap-profiler.cc
diff --git a/test/cctest/test-heap-profiler.cc
b/test/cctest/test-heap-profiler.cc
index
04f6e0fa130b996bc32b1bc4347b215111628558..0cf9cdaedf58d51c14ce094d1592f3f03dce00c3
100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -404,12 +404,57 @@ TEST(HeapSnapshotSlicedString) {
const v8::HeapGraphNode* child_string =
GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string");
CHECK_NE(NULL, child_string);
+ CHECK_EQ(v8::HeapGraphNode::kSlicedString, child_string->GetType());
const v8::HeapGraphNode* parent =
GetProperty(child_string, v8::HeapGraphEdge::kInternal, "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) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.