Revision: 5635
Author: [email protected]
Date: Mon Oct 18 02:15:38 2010
Log: New Heap profiler: add dumping HeapNumbers and InternalFields to
snapshot.
HeapNumbers do consume memory, so it's worth dumping them. However, we
don't dump their values, as they are not as self-descriptive as values
of strings, and they will increase snapshot size. Storing heap numbers
values can be added if we will feel a sufficient demand for that.
InternalFields are used, e.g. for storing references to DOM nodes
event handlers.
Review URL: http://codereview.chromium.org/3769007
http://code.google.com/p/v8/source/detail?r=5635
Modified:
/branches/bleeding_edge/include/v8-profiler.h
/branches/bleeding_edge/src/profile-generator.cc
/branches/bleeding_edge/src/profile-generator.h
/branches/bleeding_edge/test/cctest/test-heap-profiler.cc
=======================================
--- /branches/bleeding_edge/include/v8-profiler.h Wed Oct 13 07:57:00 2010
+++ /branches/bleeding_edge/include/v8-profiler.h Mon Oct 18 02:15:38 2010
@@ -246,7 +246,8 @@
kObject = 3, // A JS object (except for arrays and strings).
kCode = 4, // Compiled code.
kClosure = 5, // Function closure.
- kRegExp = 6 // RegExp.
+ kRegExp = 6, // RegExp.
+ kHeapNumber = 7 // Number stored in the heap.
};
/** Returns node type (see HeapGraphNode::Type). */
=======================================
--- /branches/bleeding_edge/src/profile-generator.cc Wed Oct 13 07:57:00
2010
+++ /branches/bleeding_edge/src/profile-generator.cc Mon Oct 18 02:15:38
2010
@@ -92,6 +92,11 @@
StringsStorage::StringsStorage()
: names_(StringsMatch) {
}
+
+
+static void DeleteIndexName(char** name_ptr) {
+ DeleteArray(*name_ptr);
+}
StringsStorage::~StringsStorage() {
@@ -100,6 +105,7 @@
p = names_.Next(p)) {
DeleteArray(reinterpret_cast<const char*>(p->value));
}
+ index_names_.Iterate(DeleteIndexName);
}
@@ -118,6 +124,22 @@
}
return "";
}
+
+
+const char* StringsStorage::GetName(int index) {
+ ASSERT(index >= 0);
+ if (index_names_.length() <= index) {
+ index_names_.AddBlock(
+ NULL, index - index_names_.length() + 1);
+ }
+ if (index_names_[index] == NULL) {
+ const int kMaximumNameLength = 32;
+ char* name = NewArray<char>(kMaximumNameLength);
+ OS::SNPrintF(Vector<char>(name, kMaximumNameLength), "%d", index);
+ index_names_[index] = name;
+ }
+ return index_names_[index];
+}
const char* CodeEntry::kEmptyNamePrefix = "";
@@ -483,11 +505,6 @@
// Create list of unabridged profiles.
profiles_by_token_.Add(new List<CpuProfile*>());
}
-
-
-static void DeleteArgsCountName(char** name_ptr) {
- DeleteArray(*name_ptr);
-}
static void DeleteCodeEntry(CodeEntry** entry_ptr) {
@@ -508,7 +525,6 @@
current_profiles_.Iterate(DeleteCpuProfile);
profiles_by_token_.Iterate(DeleteProfilesList);
code_entries_.Iterate(DeleteCodeEntry);
- args_count_names_.Iterate(DeleteArgsCountName);
}
@@ -704,22 +720,6 @@
code_entries_.Add(entry);
return entry;
}
-
-
-const char* CpuProfilesCollection::GetName(int args_count) {
- ASSERT(args_count >= 0);
- if (args_count_names_.length() <= args_count) {
- args_count_names_.AddBlock(
- NULL, args_count - args_count_names_.length() + 1);
- }
- if (args_count_names_[args_count] == NULL) {
- const int kMaximumNameLength = 32;
- char* name = NewArray<char>(kMaximumNameLength);
- OS::SNPrintF(Vector<char>(name, kMaximumNameLength), "%d", args_count);
- args_count_names_[args_count] = name;
- }
- return args_count_names_[args_count];
-}
void CpuProfilesCollection::AddPathToCurrentProfiles(
@@ -1002,6 +1002,7 @@
case kCode: return "/code/";
case kArray: return "/array/";
case kRegExp: return "/regexp/";
+ case kHeapNumber: return "/number/";
default: return "???";
}
}
@@ -1337,6 +1338,12 @@
return AddEntry(object,
HeapEntry::kArray,
"",
+ children_count,
+ retainers_count);
+ } else if (object->IsHeapNumber()) {
+ return AddEntry(object,
+ HeapEntry::kHeapNumber,
+ "number",
children_count,
retainers_count);
}
@@ -1354,7 +1361,8 @@
|| object->IsCode()
|| object->IsSharedFunctionInfo()
|| object->IsScript()
- || object->IsFixedArray();
+ || object->IsFixedArray()
+ || object->IsHeapNumber();
}
@@ -1911,6 +1919,7 @@
ExtractClosureReferences(js_obj, entry);
ExtractPropertyReferences(js_obj, entry);
ExtractElementReferences(js_obj, entry);
+ ExtractInternalReferences(js_obj, entry);
SetPropertyReference(
obj, entry, Heap::Proto_symbol(), js_obj->GetPrototype());
if (obj->IsJSFunction()) {
@@ -2017,6 +2026,16 @@
}
}
}
+
+
+void HeapSnapshotGenerator::ExtractInternalReferences(JSObject* js_obj,
+ HeapEntry* entry) {
+ int length = js_obj->GetInternalFieldCount();
+ for (int i = 0; i < length; ++i) {
+ Object* o = js_obj->GetInternalField(i);
+ SetInternalReference(js_obj, entry, i, o);
+ }
+}
void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj,
@@ -2061,6 +2080,22 @@
child_entry);
}
}
+
+
+void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj,
+ HeapEntry* parent_entry,
+ int index,
+ Object* child_obj) {
+ HeapEntry* child_entry = GetEntry(child_obj);
+ if (child_entry != NULL) {
+ filler_->SetNamedReference(HeapGraphEdge::kInternal,
+ parent_obj,
+ parent_entry,
+ collection_->GetName(index),
+ child_obj,
+ child_entry);
+ }
+}
void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj,
@@ -2368,7 +2403,8 @@
"," JSON_S("object")
"," JSON_S("code")
"," JSON_S("closure")
- "," JSON_S("regexp"))
+ "," JSON_S("regexp")
+ "," JSON_S("number"))
"," JSON_S("string")
"," JSON_S("number")
"," JSON_S("number")
=======================================
--- /branches/bleeding_edge/src/profile-generator.h Wed Oct 13 07:57:00 2010
+++ /branches/bleeding_edge/src/profile-generator.h Mon Oct 18 02:15:38 2010
@@ -67,6 +67,7 @@
~StringsStorage();
const char* GetName(String* name);
+ const char* GetName(int index);
inline const char* GetFunctionName(String* name);
inline const char* GetFunctionName(const char* name);
@@ -78,6 +79,8 @@
// Mapping of strings by String::Hash to const char* strings.
HashMap names_;
+ // Mapping from ints to char* strings.
+ List<char*> index_names_;
DISALLOW_COPY_AND_ASSIGN(StringsStorage);
};
@@ -284,6 +287,9 @@
const char* GetName(String* name) {
return function_and_resource_names_.GetName(name);
}
+ const char* GetName(int args_count) {
+ return function_and_resource_names_.GetName(args_count);
+ }
CpuProfile* GetProfile(int security_token_id, unsigned uid);
bool IsLastProfile(const char* title);
@@ -302,7 +308,6 @@
static const int kMaxSimultaneousProfiles = 100;
private:
- const char* GetName(int args_count);
const char* GetFunctionName(String* name) {
return function_and_resource_names_.GetFunctionName(name);
}
@@ -317,8 +322,6 @@
}
StringsStorage function_and_resource_names_;
- // Mapping from args_count (int) to char* strings.
- List<char*> args_count_names_;
List<CodeEntry*> code_entries_;
List<List<CpuProfile*>* > profiles_by_token_;
// Mapping from profiles' uids to indexes in the second nested list
@@ -503,7 +506,8 @@
kObject = v8::HeapGraphNode::kObject,
kCode = v8::HeapGraphNode::kCode,
kClosure = v8::HeapGraphNode::kClosure,
- kRegExp = v8::HeapGraphNode::kRegExp
+ kRegExp = v8::HeapGraphNode::kRegExp,
+ kHeapNumber = v8::HeapGraphNode::kHeapNumber
};
HeapEntry() { }
@@ -825,6 +829,7 @@
HeapSnapshot* GetSnapshot(unsigned uid);
const char* GetName(String* name) { return names_.GetName(name); }
+ const char* GetName(int index) { return names_.GetName(index); }
const char* GetFunctionName(String* name) {
return names_.GetFunctionName(name);
}
@@ -949,6 +954,7 @@
void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
+ void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
void SetClosureReference(HeapObject* parent_obj,
HeapEntry* parent,
String* reference_name,
@@ -960,6 +966,10 @@
void SetInternalReference(HeapObject* parent_obj,
HeapEntry* parent,
const char* reference_name,
+ Object* child);
+ void SetInternalReference(HeapObject* parent_obj,
+ HeapEntry* parent,
+ int index,
Object* child);
void SetPropertyReference(HeapObject* parent_obj,
HeapEntry* parent,
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Wed Oct 13
07:57:00 2010
+++ /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Mon Oct 18
02:15:38 2010
@@ -20,11 +20,6 @@
using i::RetainerHeapProfile;
-static void CompileAndRunScript(const char *src) {
- v8::Script::Compile(v8::String::New(src))->Run();
-}
-
-
namespace {
class ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
@@ -58,7 +53,7 @@
v8::HandleScope scope;
LocalContext env;
- CompileAndRunScript(
+ CompileRun(
"function F() {} // A constructor\n"
"var f1 = new F();\n"
"var f2 = new F();\n");
@@ -359,7 +354,7 @@
v8::HandleScope scope;
LocalContext env;
- CompileAndRunScript(
+ CompileRun(
"function A() {}\n"
"function B(x) { this.x = x; }\n"
"function C(x) { this.x1 = x; this.x2 = x; }\n"
@@ -473,7 +468,7 @@
LocalContext env1;
env1->SetSecurityToken(token1);
- CompileAndRunScript(
+ CompileRun(
"function A1() {}\n"
"function B1(x) { this.x = x; }\n"
"function C1(x) { this.x1 = x; this.x2 = x; }\n"
@@ -485,7 +480,7 @@
LocalContext env2;
env2->SetSecurityToken(token2);
- CompileAndRunScript(
+ CompileRun(
"function A2() {}\n"
"function B2(x) { return function() { return typeof x; }; }\n"
"function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
@@ -583,7 +578,7 @@
// -a-> X1 --a
// x -b-> X2 <-|
- CompileAndRunScript(
+ CompileRun(
"function X(a, b) { this.a = a; this.b = b; }\n"
"x = new X(new X(), new X());\n"
"x.a.a = x.b;");
@@ -624,7 +619,7 @@
v8::HandleScope scope;
LocalContext env;
- CompileAndRunScript(
+ CompileRun(
"function A() { }\n"
"a = new A;");
const v8::HeapSnapshot* snapshot =
@@ -648,7 +643,7 @@
v8::HandleScope scope;
LocalContext env;
- CompileAndRunScript(
+ CompileRun(
"function lazy(x) { return x - 1; }\n"
"function compiled(x) { return x + 1; }\n"
"var anonymous = (function() { return function() { return 0; }
})();\n"
@@ -707,6 +702,44 @@
CHECK(compiled_references_x);
CHECK(!lazy_references_x);
}
+
+
+TEST(HeapSnapshotHeapNumbers) {
+ v8::HandleScope scope;
+ LocalContext env;
+ CompileRun(
+ "a = 1; // a is Smi\n"
+ "b = 2.5; // b is HeapNumber");
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("numbers"));
+ const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+ CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a"));
+ const v8::HeapGraphNode* b =
+ GetProperty(global, v8::HeapGraphEdge::kProperty, "b");
+ CHECK_NE(NULL, b);
+ CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
+}
+
+
+TEST(HeapSnapshotInternalReferences) {
+ v8::HandleScope scope;
+ v8::Local<v8::ObjectTemplate> global_template =
v8::ObjectTemplate::New();
+ global_template->SetInternalFieldCount(2);
+ 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(2, global->InternalFieldCount());
+ v8::Local<v8::Object> obj = v8::Object::New();
+ global->SetInternalField(0, v8_num(17));
+ global->SetInternalField(1, obj);
+ const v8::HeapSnapshot* snapshot =
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("internals"));
+ const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
+ // The first reference will not present, because it's a Smi.
+ CHECK_EQ(NULL, GetProperty(global_node,
v8::HeapGraphEdge::kInternal, "0"));
+ // The second reference is to an object.
+ CHECK_NE(NULL, GetProperty(global_node,
v8::HeapGraphEdge::kInternal, "1"));
+}
// Trying to introduce a check helper for uint64_t causes many
@@ -721,7 +754,7 @@
v8::HandleScope scope;
LocalContext env;
- CompileAndRunScript(
+ CompileRun(
"function A() {}\n"
"function B(x) { this.x = x; }\n"
"var a = new A();\n"
@@ -777,7 +810,7 @@
v8::HandleScope scope;
LocalContext env;
- CompileAndRunScript(
+ CompileRun(
"function A() {}\n"
"function B(x) { this.x = x; }\n"
"function A2(a) { for (var i = 0; i < a; ++i) this[i] = i; }\n"
@@ -786,7 +819,7 @@
const v8::HeapSnapshot* snapshot1 =
v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
- CompileAndRunScript(
+ CompileRun(
"delete a;\n"
"b.x = null;\n"
"var a = new A2(20);\n"
@@ -921,7 +954,7 @@
v8::HandleScope scope;
LocalContext env;
- CompileAndRunScript(
+ CompileRun(
"function A() {}\n"
"function B(x) { this.x = x; }\n"
"var a = new A();\n"
@@ -1042,7 +1075,7 @@
#define STRING_LITERAL_FOR_TEST \
"\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
- CompileAndRunScript(
+ CompileRun(
"function A(s) { this.s = s; }\n"
"function B(x) { this.x = x; }\n"
"var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev