diff --git a/src/inspector/js_protocol.json b/src/inspector/js_protocol.json index 39ea5cf915..3476a51f9e 100644 --- a/src/inspector/js_protocol.json +++ b/src/inspector/js_protocol.json @@ -1144,6 +1144,12 @@ "returns": [ { "name": "profile", "$ref": "SamplingHeapProfile", "description": "Recorded sampling heap profile." } ] + }, + { + "name": "getSamplingProfile", + "returns": [ + { "name": "profile", "$ref": "SamplingHeapProfile", "description": "Return the sampling profile being collected." } + ] } ], "events": [ diff --git a/src/inspector/v8-heap-profiler-agent-impl.cc b/src/inspector/v8-heap-profiler-agent-impl.cc index b3e3d11f51..8af3edf7e1 100644 --- a/src/inspector/v8-heap-profiler-agent-impl.cc +++ b/src/inspector/v8-heap-profiler-agent-impl.cc @@ -363,17 +363,24 @@ buildSampingHeapProfileNode(const v8::AllocationProfile::Node* node) { Response V8HeapProfilerAgentImpl::stopSampling( std::unique_ptr* profile) { + Response result = getSamplingProfile(profile); + if (result.isSuccess()) { + m_isolate->GetHeapProfiler()->StopSamplingHeapProfiler(); + m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled, + false); + } + return result; +} + +Response V8HeapProfilerAgentImpl::getSamplingProfile( + std::unique_ptr* profile) { v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); - if (!profiler) return Response::Error("Cannot access v8 heap profiler"); v8::HandleScope scope( - m_isolate); // Allocation profile contains Local handles. + m_isolate); // v8::AllocationProfile contains Local handles. std::unique_ptr v8Profile( profiler->GetAllocationProfile()); - profiler->StopSamplingHeapProfiler(); - m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled, - false); if (!v8Profile) - return Response::Error("Cannot access v8 sampled heap profile."); + return Response::Error("V8 sampling heap profiler was not started."); v8::AllocationProfile::Node* root = v8Profile->GetRootNode(); *profile = protocol::HeapProfiler::SamplingHeapProfile::create() .setHead(buildSampingHeapProfileNode(root)) diff --git a/src/inspector/v8-heap-profiler-agent-impl.h b/src/inspector/v8-heap-profiler-agent-impl.h index e0e244715f..7491a80f10 100644 --- a/src/inspector/v8-heap-profiler-agent-impl.h +++ b/src/inspector/v8-heap-profiler-agent-impl.h @@ -46,6 +46,8 @@ class V8HeapProfilerAgentImpl : public protocol::HeapProfiler::Backend { Response startSampling(Maybe samplingInterval) override; Response stopSampling( std::unique_ptr*) override; + Response getSamplingProfile( + std::unique_ptr*) override; private: void startTrackingHeapObjectsInternal(bool trackAllocations); diff --git a/test/inspector/heap-profiler/sampling-heap-profiler-expected.txt b/test/inspector/heap-profiler/sampling-heap-profiler-expected.txt new file mode 100644 index 0000000000..2b14f901b6 --- /dev/null +++ b/test/inspector/heap-profiler/sampling-heap-profiler-expected.txt @@ -0,0 +1,7 @@ +Checks sampling heap profiler methods. +Expected error: V8 sampling heap profiler was not started. +Allocated size is zero in the beginning: true +Allocated size is more than 100KB after a chunk is allocated: true +Allocated size increased after one more chunk is allocated: true +Allocated size did not change after stopping: true +Successfully finished diff --git a/test/inspector/heap-profiler/sampling-heap-profiler.js b/test/inspector/heap-profiler/sampling-heap-profiler.js new file mode 100644 index 0000000000..1b82a46fa2 --- /dev/null +++ b/test/inspector/heap-profiler/sampling-heap-profiler.js @@ -0,0 +1,48 @@ +// Copyright 2017 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --sampling-heap-profiler-suppress-randomness + +(async function() { + let {contextGroup, Protocol} = InspectorTest.start('Checks sampling heap profiler methods.'); + + contextGroup.addScript(` + var holder = []; + function allocateChunk() { + holder.push(new Array(100000).fill(42)); + } + //# sourceURL=test.js`); + + Protocol.HeapProfiler.enable(); + + const profile0 = await Protocol.HeapProfiler.getSamplingProfile(); + InspectorTest.log('Expected error: ' + profile0.error.message); + + await Protocol.HeapProfiler.startSampling(); + const profile1 = await Protocol.HeapProfiler.getSamplingProfile(); + const size1 = nodeSize(profile1.result.profile.head); + InspectorTest.log('Allocated size is zero in the beginning:', size1 === 0); + + await Protocol.Runtime.evaluate({ expression: 'allocateChunk()' }); + const profile2 = await Protocol.HeapProfiler.getSamplingProfile(); + const size2 = nodeSize(profile2.result.profile.head); + InspectorTest.log('Allocated size is more than 100KB after a chunk is allocated:', size2 > 100000); + + await Protocol.Runtime.evaluate({ expression: 'allocateChunk()' }); + const profile3 = await Protocol.HeapProfiler.getSamplingProfile(); + const size3 = nodeSize(profile3.result.profile.head); + InspectorTest.log('Allocated size increased after one more chunk is allocated:', size3 > size2); + + const profile4 = await Protocol.HeapProfiler.stopSampling(); + const size4 = nodeSize(profile4.result.profile.head); + InspectorTest.log('Allocated size did not change after stopping:', size4 === size3); + + InspectorTest.log('Successfully finished'); + InspectorTest.completeTest(); + + function nodeSize(node) { + return node.children.reduce((res, child) => res + nodeSize(child), + node.callFrame.functionName === 'allocateChunk' ? node.selfSize : 0); + } +})();