From 3989b5c84a796a5ee8df8a68692ad5beabd7e09e Mon Sep 17 00:00:00 2001 From: Alexei Filippov Date: Thu, 2 Nov 2017 10:47:27 -0700 Subject: [PATCH] [heap-profiler] Allow intermediate sampling heap profile retrieval during recording. The sampling heap profiles can now be retrieved without stopping the profiler. BUG=v8:6887 Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel Change-Id: I491206d0bafd7d4e198622117c12aab0057e6bc6 Reviewed-on: https://chromium-review.googlesource.com/749700 Reviewed-by: Pavel Feldman Reviewed-by: Aleksey Kozyatinskiy Commit-Queue: Alexei Filippov Cr-Commit-Position: refs/heads/master@{#49160} --- src/inspector/js_protocol.json | 6 +++ src/inspector/v8-heap-profiler-agent-impl.cc | 19 +++++--- src/inspector/v8-heap-profiler-agent-impl.h | 2 + .../sampling-heap-profiler-expected.txt | 7 +++ .../heap-profiler/sampling-heap-profiler.js | 48 +++++++++++++++++++ 5 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 test/inspector/heap-profiler/sampling-heap-profiler-expected.txt create mode 100644 test/inspector/heap-profiler/sampling-heap-profiler.js 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); + } +})();