Index: test/cctest/test-heap-profiler.cc |
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc |
index 65432173e3500466e805fadc8ae886955ffe7c29..e720d92109ca13d23d08f42cde1edf79cf98fc9e 100644 |
--- a/test/cctest/test-heap-profiler.cc |
+++ b/test/cctest/test-heap-profiler.cc |
@@ -2852,3 +2852,155 @@ TEST(AddressToTraceMap) { |
CHECK_EQ(0u, map.size()); |
CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x400))); |
} |
+ |
+ |
+static const v8::AllocationProfile::Node* FindAllocationProfileNode( |
+ v8::AllocationProfile& profile, const Vector<const char*>& names) { |
+ v8::AllocationProfile::Node* node = profile.GetRootNode(); |
+ for (int i = 0; node != nullptr && i < names.length(); ++i) { |
+ const char* name = names[i]; |
+ auto children = node->children; |
+ node = nullptr; |
+ for (v8::AllocationProfile::Node* child : children) { |
+ v8::String::Utf8Value child_name(child->name); |
+ if (strcmp(*child_name, name) == 0) { |
+ node = child; |
+ break; |
+ } |
+ } |
+ } |
+ return node; |
+} |
+ |
+ |
+TEST(SamplingHeapProfiler) { |
+ v8::HandleScope scope(v8::Isolate::GetCurrent()); |
+ LocalContext env; |
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
+ |
+ // Turn off always_opt. Inlining can cause stack traces to be shorter than |
+ // what we expect in this test. |
+ v8::internal::FLAG_always_opt = false; |
+ |
+ // Suppress randomness to avoid flakiness in tests. |
+ v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true; |
+ |
+ const char* script_source = |
+ "var A = [];\n" |
+ "function bar(size) { return new Array(size); }\n" |
+ "var foo = function() {\n" |
+ " for (var i = 0; i < 1024; ++i) {\n" |
+ " A[i] = bar(1024);\n" |
+ " }\n" |
+ "}\n" |
+ "foo();"; |
+ |
+ // Sample should be empty if requested before sampling has started. |
+ { |
+ v8::AllocationProfile* profile = heap_profiler->GetAllocationProfile(); |
+ CHECK(profile == nullptr); |
+ } |
+ |
+ int count_512kb = 0; |
+ { |
+ heap_profiler->StartSamplingHeapProfiler(512 * 1024); |
+ CompileRun(script_source); |
+ |
+ v8::base::SmartPointer<v8::AllocationProfile> profile( |
+ heap_profiler->GetAllocationProfile()); |
+ CHECK(!profile.is_empty()); |
+ |
+ const char* names[] = {"", "foo", "bar"}; |
+ auto node_bar = FindAllocationProfileNode( |
+ *profile, Vector<const char*>(names, arraysize(names))); |
+ CHECK(node_bar); |
+ |
+ // Count the number of allocations we sampled from bar. |
+ for (auto allocation : node_bar->allocations) { |
+ count_512kb += allocation.count; |
+ } |
+ |
+ heap_profiler->StopSamplingHeapProfiler(); |
+ } |
+ |
+ // Samples should get cleared once sampling is stopped. |
+ { |
+ v8::AllocationProfile* profile = heap_profiler->GetAllocationProfile(); |
+ CHECK(profile == nullptr); |
+ } |
+ |
+ // Sampling at a higher rate should give us more sampled objects. |
+ { |
+ heap_profiler->StartSamplingHeapProfiler(32 * 1024); |
+ CompileRun(script_source); |
+ |
+ v8::base::SmartPointer<v8::AllocationProfile> profile( |
+ heap_profiler->GetAllocationProfile()); |
+ CHECK(!profile.is_empty()); |
+ |
+ const char* names[] = {"", "foo", "bar"}; |
+ auto node_bar = FindAllocationProfileNode( |
+ *profile, Vector<const char*>(names, arraysize(names))); |
+ CHECK(node_bar); |
+ |
+ // Count the number of allocations we sampled from bar. |
+ int count_32kb = 0; |
+ for (auto allocation : node_bar->allocations) { |
+ count_32kb += allocation.count; |
+ } |
+ |
+ // We should have roughly 16x as many sampled allocations. However, |
+ // alignment and boundaries might tweak the numbers slightly. We use a |
+ // slightly weaker test to account for this. |
+ CHECK_GT(count_32kb, 8 * count_512kb); |
+ |
+ heap_profiler->StopSamplingHeapProfiler(); |
+ } |
+ |
+ // A more complicated test cases with deeper call graph and dynamically |
+ // generated function names. |
+ { |
+ heap_profiler->StartSamplingHeapProfiler(64); |
+ CompileRun(record_trace_tree_source); |
+ |
+ v8::base::SmartPointer<v8::AllocationProfile> profile( |
+ heap_profiler->GetAllocationProfile()); |
+ CHECK(!profile.is_empty()); |
+ |
+ const char* names1[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"}; |
+ auto node1 = FindAllocationProfileNode( |
+ *profile, Vector<const char*>(names1, arraysize(names1))); |
+ CHECK(node1); |
+ |
+ const char* names2[] = {"", "generateFunctions"}; |
+ auto node2 = FindAllocationProfileNode( |
+ *profile, Vector<const char*>(names2, arraysize(names2))); |
+ CHECK(node2); |
+ |
+ heap_profiler->StopSamplingHeapProfiler(); |
+ } |
+} |
+ |
+ |
+TEST(SamplingHeapProfilerApiAllocation) { |
+ v8::HandleScope scope(v8::Isolate::GetCurrent()); |
+ LocalContext env; |
+ v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
+ |
+ // Suppress randomness to avoid flakiness in tests. |
+ v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true; |
+ |
+ heap_profiler->StartSamplingHeapProfiler(256); |
+ |
+ for (int i = 0; i < 8 * 1024; ++i) v8::Object::New(env->GetIsolate()); |
+ |
+ v8::base::SmartPointer<v8::AllocationProfile> profile( |
+ heap_profiler->GetAllocationProfile()); |
+ CHECK(!profile.is_empty()); |
+ const char* names[] = {"(V8 API)"}; |
+ auto node = FindAllocationProfileNode( |
+ *profile, Vector<const char*>(names, arraysize(names))); |
+ CHECK(node); |
+ |
+ heap_profiler->StopSamplingHeapProfiler(); |
+} |