| Index: test/cctest/test-heap-profiler.cc
|
| diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
|
| index a2fd09e9f59d4edd27b4c6ca1c0b3800648e8729..ea385743f2e35d9d9038cffd6ddae231ef52ec09 100644
|
| --- a/test/cctest/test-heap-profiler.cc
|
| +++ b/test/cctest/test-heap-profiler.cc
|
| @@ -2852,3 +2852,148 @@ 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;
|
| +
|
| + 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, since
|
| + // sampling is a randomized process, we use a weaker test.
|
| + CHECK_GT(count_32kb, count_512kb);
|
| +
|
| + heap_profiler->StopSamplingHeapProfiler();
|
| + }
|
| +
|
| + // A more complicated test cases with deeper call graph and dynamically
|
| + // generated function names.
|
| + {
|
| + heap_profiler->StartSamplingHeapProfiler(128);
|
| + 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();
|
| +
|
| + 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();
|
| +}
|
|
|