Revision f230a1cf deps/v8/test/cctest/test-heap-profiler.cc
deps/v8/test/cctest/test-heap-profiler.cc | ||
---|---|---|
31 | 31 |
|
32 | 32 |
#include "v8.h" |
33 | 33 |
|
34 |
#include "allocation-tracker.h" |
|
34 | 35 |
#include "cctest.h" |
35 | 36 |
#include "hashmap.h" |
36 | 37 |
#include "heap-profiler.h" |
... | ... | |
39 | 40 |
#include "utils-inl.h" |
40 | 41 |
#include "../include/v8-profiler.h" |
41 | 42 |
|
43 |
using i::AllocationTraceNode; |
|
44 |
using i::AllocationTraceTree; |
|
45 |
using i::AllocationTracker; |
|
46 |
using i::HashMap; |
|
47 |
using i::Vector; |
|
48 |
|
|
42 | 49 |
namespace { |
43 | 50 |
|
44 | 51 |
class NamedEntriesDetector { |
... | ... | |
413 | 420 |
|
414 | 421 |
|
415 | 422 |
TEST(HeapSnapshotConsString) { |
416 |
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
423 |
v8::Isolate* isolate = CcTest::isolate();
|
|
417 | 424 |
v8::HandleScope scope(isolate); |
418 | 425 |
v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); |
419 | 426 |
global_template->SetInternalFieldCount(1); |
... | ... | |
422 | 429 |
v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); |
423 | 430 |
CHECK_EQ(1, global->InternalFieldCount()); |
424 | 431 |
|
425 |
i::Factory* factory = i::Isolate::Current()->factory();
|
|
432 |
i::Factory* factory = CcTest::i_isolate()->factory();
|
|
426 | 433 |
i::Handle<i::String> first = |
427 | 434 |
factory->NewStringFromAscii(i::CStrVector("0123456789")); |
428 | 435 |
i::Handle<i::String> second = |
... | ... | |
456 | 463 |
|
457 | 464 |
|
458 | 465 |
TEST(HeapSnapshotInternalReferences) { |
459 |
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
466 |
v8::Isolate* isolate = CcTest::isolate();
|
|
460 | 467 |
v8::HandleScope scope(isolate); |
461 | 468 |
v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); |
462 | 469 |
global_template->SetInternalFieldCount(2); |
... | ... | |
505 | 512 |
CompileRun( |
506 | 513 |
"for (var i = 0; i < 10000; ++i)\n" |
507 | 514 |
" a[i] = new A();\n"); |
508 |
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
515 |
CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
509 | 516 |
|
510 | 517 |
const v8::HeapSnapshot* snapshot2 = |
511 | 518 |
heap_profiler->TakeHeapSnapshot(v8_str("snapshot2")); |
... | ... | |
549 | 556 |
"for (var i = 0; i < 1; ++i)\n" |
550 | 557 |
" a.shift();\n"); |
551 | 558 |
|
552 |
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
559 |
CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
553 | 560 |
|
554 | 561 |
const v8::HeapSnapshot* snapshot2 = |
555 | 562 |
heap_profiler->TakeHeapSnapshot(v8_str("s2")); |
... | ... | |
594 | 601 |
heap_profiler->TakeHeapSnapshot(s1_str); |
595 | 602 |
CHECK(ValidateSnapshot(snapshot1)); |
596 | 603 |
|
597 |
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
604 |
CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
598 | 605 |
|
599 | 606 |
const v8::HeapSnapshot* snapshot2 = |
600 | 607 |
heap_profiler->TakeHeapSnapshot(s2_str); |
... | ... | |
901 | 908 |
// We have to call GC 6 times. In other case the garbage will be |
902 | 909 |
// the reason of flakiness. |
903 | 910 |
for (int i = 0; i < 6; ++i) { |
904 |
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
911 |
CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
|
|
905 | 912 |
} |
906 | 913 |
|
907 | 914 |
v8::SnapshotObjectId initial_id; |
... | ... | |
1482 | 1489 |
CompileRun("document = { URL:\"abcdefgh\" };"); |
1483 | 1490 |
|
1484 | 1491 |
v8::Handle<v8::String> name(v8_str("leakz")); |
1485 |
i::Isolate* isolate = i::Isolate::Current();
|
|
1492 |
i::Isolate* isolate = CcTest::i_isolate();
|
|
1486 | 1493 |
int count_before = i::HandleScope::NumberOfHandles(isolate); |
1487 | 1494 |
heap_profiler->TakeHeapSnapshot(name); |
1488 | 1495 |
int count_after = i::HandleScope::NumberOfHandles(isolate); |
... | ... | |
1738 | 1745 |
|
1739 | 1746 |
|
1740 | 1747 |
bool HasWeakGlobalHandle() { |
1741 |
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
1748 |
v8::Isolate* isolate = CcTest::isolate();
|
|
1742 | 1749 |
v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); |
1743 | 1750 |
const v8::HeapSnapshot* snapshot = |
1744 | 1751 |
heap_profiler->TakeHeapSnapshot(v8_str("weaks")); |
... | ... | |
1800 | 1807 |
v8::HandleScope scope(env->GetIsolate()); |
1801 | 1808 |
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
1802 | 1809 |
|
1803 |
v8::internal::Isolate::Current()->debug()->Load();
|
|
1810 |
CcTest::i_isolate()->debug()->Load();
|
|
1804 | 1811 |
CompileRun("foo = {};"); |
1805 | 1812 |
const v8::HeapSnapshot* snapshot = |
1806 | 1813 |
heap_profiler->TakeHeapSnapshot(v8_str("snapshot")); |
... | ... | |
2005 | 2012 |
GetProperty(foo_func, v8::HeapGraphEdge::kInternal, "code"); |
2006 | 2013 |
CHECK_NE(NULL, code); |
2007 | 2014 |
} |
2015 |
|
|
2016 |
|
|
2017 |
|
|
2018 |
class HeapProfilerExtension : public v8::Extension { |
|
2019 |
public: |
|
2020 |
static const char* kName; |
|
2021 |
HeapProfilerExtension() : v8::Extension(kName, kSource) { } |
|
2022 |
virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
|
2023 |
v8::Handle<v8::String> name); |
|
2024 |
static void FindUntrackedObjects( |
|
2025 |
const v8::FunctionCallbackInfo<v8::Value>& args); |
|
2026 |
private: |
|
2027 |
static const char* kSource; |
|
2028 |
}; |
|
2029 |
|
|
2030 |
const char* HeapProfilerExtension::kName = "v8/heap-profiler"; |
|
2031 |
|
|
2032 |
|
|
2033 |
const char* HeapProfilerExtension::kSource = |
|
2034 |
"native function findUntrackedObjects();"; |
|
2035 |
|
|
2036 |
|
|
2037 |
v8::Handle<v8::FunctionTemplate> HeapProfilerExtension::GetNativeFunction( |
|
2038 |
v8::Handle<v8::String> name) { |
|
2039 |
if (name->Equals(v8::String::New("findUntrackedObjects"))) { |
|
2040 |
return v8::FunctionTemplate::New( |
|
2041 |
HeapProfilerExtension::FindUntrackedObjects); |
|
2042 |
} else { |
|
2043 |
CHECK(false); |
|
2044 |
return v8::Handle<v8::FunctionTemplate>(); |
|
2045 |
} |
|
2046 |
} |
|
2047 |
|
|
2048 |
|
|
2049 |
void HeapProfilerExtension::FindUntrackedObjects( |
|
2050 |
const v8::FunctionCallbackInfo<v8::Value>& args) { |
|
2051 |
i::HeapProfiler* heap_profiler = |
|
2052 |
reinterpret_cast<i::HeapProfiler*>(args.GetIsolate()->GetHeapProfiler()); |
|
2053 |
int untracked_objects = heap_profiler->FindUntrackedObjects(); |
|
2054 |
args.GetReturnValue().Set(untracked_objects); |
|
2055 |
CHECK_EQ(0, untracked_objects); |
|
2056 |
} |
|
2057 |
|
|
2058 |
|
|
2059 |
static HeapProfilerExtension kHeapProfilerExtension; |
|
2060 |
v8::DeclareExtension kHeapProfilerExtensionDeclaration( |
|
2061 |
&kHeapProfilerExtension); |
|
2062 |
|
|
2063 |
|
|
2064 |
// This is an example of using checking of JS allocations tracking in a test. |
|
2065 |
TEST(HeapObjectsTracker) { |
|
2066 |
const char* extensions[] = { HeapProfilerExtension::kName }; |
|
2067 |
v8::ExtensionConfiguration config(1, extensions); |
|
2068 |
LocalContext env(&config); |
|
2069 |
v8::HandleScope scope(env->GetIsolate()); |
|
2070 |
HeapObjectsTracker tracker; |
|
2071 |
CompileRun("var a = 1.2"); |
|
2072 |
CompileRun("var a = 1.2; var b = 1.0; var c = 1.0;"); |
|
2073 |
CompileRun( |
|
2074 |
"var a = [];\n" |
|
2075 |
"for (var i = 0; i < 5; ++i)\n" |
|
2076 |
" a[i] = i;\n" |
|
2077 |
"findUntrackedObjects();\n" |
|
2078 |
"for (var i = 0; i < 3; ++i)\n" |
|
2079 |
" a.shift();\n" |
|
2080 |
"findUntrackedObjects();\n"); |
|
2081 |
} |
|
2082 |
|
|
2083 |
|
|
2084 |
static const char* record_trace_tree_source = |
|
2085 |
"var topFunctions = [];\n" |
|
2086 |
"var global = this;\n" |
|
2087 |
"function generateFunctions(width, depth) {\n" |
|
2088 |
" var script = [];\n" |
|
2089 |
" for (var i = 0; i < width; i++) {\n" |
|
2090 |
" for (var j = 0; j < depth; j++) {\n" |
|
2091 |
" script.push('function f_' + i + '_' + j + '(x) {\\n');\n" |
|
2092 |
" script.push(' try {\\n');\n" |
|
2093 |
" if (j < depth-2) {\n" |
|
2094 |
" script.push(' return f_' + i + '_' + (j+1) + '(x+1);\\n');\n" |
|
2095 |
" } else if (j == depth - 2) {\n" |
|
2096 |
" script.push(' return new f_' + i + '_' + (depth - 1) + '();\\n');\n" |
|
2097 |
" } else if (j == depth - 1) {\n" |
|
2098 |
" script.push(' this.ts = Date.now();\\n');\n" |
|
2099 |
" }\n" |
|
2100 |
" script.push(' } catch (e) {}\\n');\n" |
|
2101 |
" script.push('}\\n');\n" |
|
2102 |
" \n" |
|
2103 |
" }\n" |
|
2104 |
" }\n" |
|
2105 |
" var script = script.join('');\n" |
|
2106 |
" // throw script;\n" |
|
2107 |
" global.eval(script);\n" |
|
2108 |
" for (var i = 0; i < width; i++) {\n" |
|
2109 |
" topFunctions.push(this['f_' + i + '_0']);\n" |
|
2110 |
" }\n" |
|
2111 |
"}\n" |
|
2112 |
"\n" |
|
2113 |
"var width = 3;\n" |
|
2114 |
"var depth = 3;\n" |
|
2115 |
"generateFunctions(width, depth);\n" |
|
2116 |
"var instances = [];\n" |
|
2117 |
"function start() {\n" |
|
2118 |
" for (var i = 0; i < width; i++) {\n" |
|
2119 |
" instances.push(topFunctions[i](0));\n" |
|
2120 |
" }\n" |
|
2121 |
"}\n" |
|
2122 |
"\n" |
|
2123 |
"for (var i = 0; i < 100; i++) start();\n"; |
|
2124 |
|
|
2125 |
|
|
2126 |
static i::HeapSnapshot* ToInternal(const v8::HeapSnapshot* snapshot) { |
|
2127 |
return const_cast<i::HeapSnapshot*>( |
|
2128 |
reinterpret_cast<const i::HeapSnapshot*>(snapshot)); |
|
2129 |
} |
|
2130 |
|
|
2131 |
|
|
2132 |
static AllocationTraceNode* FindNode( |
|
2133 |
AllocationTracker* tracker, const Vector<const char*>& names) { |
|
2134 |
AllocationTraceNode* node = tracker->trace_tree()->root(); |
|
2135 |
for (int i = 0; node != NULL && i < names.length(); i++) { |
|
2136 |
const char* name = names[i]; |
|
2137 |
Vector<AllocationTraceNode*> children = node->children(); |
|
2138 |
node = NULL; |
|
2139 |
for (int j = 0; j < children.length(); j++) { |
|
2140 |
v8::SnapshotObjectId id = children[j]->function_id(); |
|
2141 |
AllocationTracker::FunctionInfo* info = tracker->GetFunctionInfo(id); |
|
2142 |
if (info && strcmp(info->name, name) == 0) { |
|
2143 |
node = children[j]; |
|
2144 |
break; |
|
2145 |
} |
|
2146 |
} |
|
2147 |
} |
|
2148 |
return node; |
|
2149 |
} |
|
2150 |
|
|
2151 |
|
|
2152 |
TEST(TrackHeapAllocations) { |
|
2153 |
v8::HandleScope scope(v8::Isolate::GetCurrent()); |
|
2154 |
LocalContext env; |
|
2155 |
|
|
2156 |
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
|
2157 |
heap_profiler->StartRecordingHeapAllocations(); |
|
2158 |
|
|
2159 |
CompileRun(record_trace_tree_source); |
|
2160 |
|
|
2161 |
const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot( |
|
2162 |
v8::String::New("Test")); |
|
2163 |
i::HeapSnapshotsCollection* collection = ToInternal(snapshot)->collection(); |
|
2164 |
AllocationTracker* tracker = collection->allocation_tracker(); |
|
2165 |
CHECK_NE(NULL, tracker); |
|
2166 |
// Resolve all function locations. |
|
2167 |
tracker->PrepareForSerialization(); |
|
2168 |
// Print for better diagnostics in case of failure. |
|
2169 |
tracker->trace_tree()->Print(tracker); |
|
2170 |
|
|
2171 |
const char* names[] = |
|
2172 |
{ "(anonymous function)", "start", "f_0_0", "f_0_1", "f_0_2" }; |
|
2173 |
AllocationTraceNode* node = |
|
2174 |
FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names))); |
|
2175 |
CHECK_NE(NULL, node); |
|
2176 |
CHECK_GE(node->allocation_count(), 100); |
|
2177 |
CHECK_GE(node->allocation_size(), 4 * node->allocation_count()); |
|
2178 |
heap_profiler->StopRecordingHeapAllocations(); |
|
2179 |
} |
Also available in: Unified diff