5 #include "src/inspector/v8-heap-profiler-agent-impl.h" 7 #include "src/inspector/injected-script.h" 8 #include "src/inspector/inspected-context.h" 9 #include "src/inspector/protocol/Protocol.h" 10 #include "src/inspector/string-util.h" 11 #include "src/inspector/v8-debugger.h" 12 #include "src/inspector/v8-inspector-impl.h" 13 #include "src/inspector/v8-inspector-session-impl.h" 15 #include "include/v8-inspector.h" 16 #include "include/v8-profiler.h" 17 #include "include/v8-version.h" 23 namespace HeapProfilerAgentState {
24 static const char heapProfilerEnabled[] =
"heapProfilerEnabled";
25 static const char heapObjectsTrackingEnabled[] =
"heapObjectsTrackingEnabled";
26 static const char allocationTrackingEnabled[] =
"allocationTrackingEnabled";
27 static const char samplingHeapProfilerEnabled[] =
"samplingHeapProfilerEnabled";
28 static const char samplingHeapProfilerInterval[] =
29 "samplingHeapProfilerInterval";
34 explicit HeapSnapshotProgress(protocol::HeapProfiler::Frontend* frontend)
35 : m_frontend(frontend) {}
36 ControlOption ReportProgressValue(
int done,
int total)
override {
37 m_frontend->reportHeapSnapshotProgress(done, total,
38 protocol::Maybe<bool>());
40 m_frontend->reportHeapSnapshotProgress(total, total,
true);
47 protocol::HeapProfiler::Frontend* m_frontend;
50 class GlobalObjectNameResolver final
53 explicit GlobalObjectNameResolver(V8InspectorSessionImpl* session)
54 : m_offset(0), m_strings(10000), m_session(session) {}
57 InspectedContext* context = m_session->inspector()->getContext(
58 m_session->contextGroupId(),
60 if (!context)
return "";
61 String16 name = context->origin();
62 size_t length = name.length();
63 if (m_offset + length + 1 >= m_strings.size())
return "";
64 for (
size_t i = 0;
i < length; ++
i) {
66 m_strings[m_offset +
i] = ch > 0xFF ?
'?' :
static_cast<char>(ch);
68 m_strings[m_offset + length] =
'\0';
69 char* result = &*m_strings.begin() + m_offset;
70 m_offset += length + 1;
76 std::vector<char> m_strings;
77 V8InspectorSessionImpl* m_session;
82 explicit HeapSnapshotOutputStream(protocol::HeapProfiler::Frontend* frontend)
83 : m_frontend(frontend) {}
84 void EndOfStream()
override {}
85 int GetChunkSize()
override {
return 102400; }
86 WriteResult WriteAsciiChunk(
char* data,
int size)
override {
87 m_frontend->addHeapSnapshotChunk(String16(data, size));
93 protocol::HeapProfiler::Frontend* m_frontend;
103 class InspectableHeapObject final :
public V8InspectorSession::Inspectable {
105 explicit InspectableHeapObject(
int heapObjectId)
106 : m_heapObjectId(heapObjectId) {}
108 return objectByHeapObjectId(context->GetIsolate(), m_heapObjectId);
117 explicit HeapStatsStream(protocol::HeapProfiler::Frontend* frontend)
118 : m_frontend(frontend) {}
120 void EndOfStream()
override {}
122 WriteResult WriteAsciiChunk(
char* data,
int size)
override {
128 int count)
override {
130 std::unique_ptr<protocol::Array<int>> statsDiff =
131 protocol::Array<int>::create();
132 for (
int i = 0;
i < count; ++
i) {
133 statsDiff->addItem(updateData[
i].index);
134 statsDiff->addItem(updateData[
i].count);
135 statsDiff->addItem(updateData[
i].size);
137 m_frontend->heapStatsUpdate(std::move(statsDiff));
142 protocol::HeapProfiler::Frontend* m_frontend;
147 V8HeapProfilerAgentImpl::V8HeapProfilerAgentImpl(
148 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
149 protocol::DictionaryValue* state)
150 : m_session(session),
151 m_isolate(session->inspector()->isolate()),
152 m_frontend(frontendChannel),
156 V8HeapProfilerAgentImpl::~V8HeapProfilerAgentImpl() =
default;
158 void V8HeapProfilerAgentImpl::restore() {
159 if (m_state->booleanProperty(HeapProfilerAgentState::heapProfilerEnabled,
161 m_frontend.resetProfiles();
162 if (m_state->booleanProperty(
163 HeapProfilerAgentState::heapObjectsTrackingEnabled,
false))
164 startTrackingHeapObjectsInternal(m_state->booleanProperty(
165 HeapProfilerAgentState::allocationTrackingEnabled,
false));
166 if (m_state->booleanProperty(
167 HeapProfilerAgentState::samplingHeapProfilerEnabled,
false)) {
168 double samplingInterval = m_state->doubleProperty(
169 HeapProfilerAgentState::samplingHeapProfilerInterval, -1);
170 DCHECK_GE(samplingInterval, 0);
171 startSampling(Maybe<double>(samplingInterval));
175 Response V8HeapProfilerAgentImpl::collectGarbage() {
176 m_isolate->LowMemoryNotification();
177 return Response::OK();
180 Response V8HeapProfilerAgentImpl::startTrackingHeapObjects(
181 Maybe<bool> trackAllocations) {
182 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled,
true);
183 bool allocationTrackingEnabled = trackAllocations.fromMaybe(
false);
184 m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled,
185 allocationTrackingEnabled);
186 startTrackingHeapObjectsInternal(allocationTrackingEnabled);
187 return Response::OK();
190 Response V8HeapProfilerAgentImpl::stopTrackingHeapObjects(
191 Maybe<bool> reportProgress) {
192 requestHeapStatsUpdate();
193 takeHeapSnapshot(std::move(reportProgress));
194 stopTrackingHeapObjectsInternal();
195 return Response::OK();
198 Response V8HeapProfilerAgentImpl::enable() {
199 m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled,
true);
200 return Response::OK();
203 Response V8HeapProfilerAgentImpl::disable() {
204 stopTrackingHeapObjectsInternal();
205 if (m_state->booleanProperty(
206 HeapProfilerAgentState::samplingHeapProfilerEnabled,
false)) {
208 if (profiler) profiler->StopSamplingHeapProfiler();
210 m_isolate->GetHeapProfiler()->ClearObjectIds();
211 m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled,
false);
212 return Response::OK();
215 Response V8HeapProfilerAgentImpl::takeHeapSnapshot(Maybe<bool> reportProgress) {
217 if (!profiler)
return Response::Error(
"Cannot access v8 heap profiler");
218 std::unique_ptr<HeapSnapshotProgress> progress;
219 if (reportProgress.fromMaybe(
false))
220 progress.reset(
new HeapSnapshotProgress(&m_frontend));
222 GlobalObjectNameResolver resolver(m_session);
224 profiler->TakeHeapSnapshot(progress.get(), &resolver);
225 if (!snapshot)
return Response::Error(
"Failed to take heap snapshot");
226 HeapSnapshotOutputStream stream(&m_frontend);
229 return Response::OK();
232 Response V8HeapProfilerAgentImpl::getObjectByHeapObjectId(
233 const String16& heapSnapshotObjectId, Maybe<String16> objectGroup,
234 std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
236 int id = heapSnapshotObjectId.toInteger(&ok);
237 if (!ok)
return Response::Error(
"Invalid heap snapshot object id");
241 if (heapObject.
IsEmpty())
return Response::Error(
"Object is not available");
243 if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject))
244 return Response::Error(
"Object is not available");
246 *result = m_session->wrapObject(heapObject->
CreationContext(), heapObject,
247 objectGroup.fromMaybe(
""),
false);
248 if (!*result)
return Response::Error(
"Object is not available");
249 return Response::OK();
252 Response V8HeapProfilerAgentImpl::addInspectedHeapObject(
253 const String16& inspectedHeapObjectId) {
255 int id = inspectedHeapObjectId.toInteger(&ok);
256 if (!ok)
return Response::Error(
"Invalid heap snapshot object id");
260 if (heapObject.
IsEmpty())
return Response::Error(
"Object is not available");
262 if (!m_session->inspector()->client()->isInspectableHeapObject(heapObject))
263 return Response::Error(
"Object is not available");
264 m_session->addInspectedObject(
265 std::unique_ptr<InspectableHeapObject>(
new InspectableHeapObject(
id)));
266 return Response::OK();
269 Response V8HeapProfilerAgentImpl::getHeapObjectId(
270 const String16& objectId, String16* heapSnapshotObjectId) {
275 m_session->unwrapObject(objectId, &value, &context,
nullptr);
276 if (!response.isSuccess())
return response;
277 if (value->IsUndefined())
return Response::InternalError();
280 *heapSnapshotObjectId = String16::fromInteger(static_cast<size_t>(
id));
281 return Response::OK();
284 void V8HeapProfilerAgentImpl::requestHeapStatsUpdate() {
285 HeapStatsStream stream(&m_frontend);
287 m_isolate->GetHeapProfiler()->GetHeapStats(&stream);
288 m_frontend.lastSeenObjectId(
289 lastSeenObjectId, m_session->inspector()->client()->currentTimeMS());
293 void V8HeapProfilerAgentImpl::onTimer(
void* data) {
294 reinterpret_cast<V8HeapProfilerAgentImpl*
>(data)->requestHeapStatsUpdate();
297 void V8HeapProfilerAgentImpl::startTrackingHeapObjectsInternal(
298 bool trackAllocations) {
299 m_isolate->GetHeapProfiler()->StartTrackingHeapObjects(trackAllocations);
302 m_session->inspector()->client()->startRepeatingTimer(
303 0.05, &V8HeapProfilerAgentImpl::onTimer, reinterpret_cast<void*>(
this));
307 void V8HeapProfilerAgentImpl::stopTrackingHeapObjectsInternal() {
309 m_session->inspector()->client()->cancelTimer(
310 reinterpret_cast<void*>(
this));
313 m_isolate->GetHeapProfiler()->StopTrackingHeapObjects();
314 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled,
316 m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled,
false);
319 Response V8HeapProfilerAgentImpl::startSampling(
320 Maybe<double> samplingInterval) {
322 if (!profiler)
return Response::Error(
"Cannot access v8 heap profiler");
323 const unsigned defaultSamplingInterval = 1 << 15;
324 double samplingIntervalValue =
325 samplingInterval.fromMaybe(defaultSamplingInterval);
326 m_state->setDouble(HeapProfilerAgentState::samplingHeapProfilerInterval,
327 samplingIntervalValue);
328 m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
330 profiler->StartSamplingHeapProfiler(
331 static_cast<uint64_t>(samplingIntervalValue), 128,
332 v8::HeapProfiler::kSamplingForceGC);
333 return Response::OK();
337 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode>
338 buildSampingHeapProfileNode(v8::Isolate* isolate,
340 auto children = protocol::Array<
341 protocol::HeapProfiler::SamplingHeapProfileNode>::create();
342 for (
const auto* child : node->children)
343 children->addItem(buildSampingHeapProfileNode(isolate, child));
345 for (
const auto& allocation : node->allocations)
346 selfSize += allocation.size * allocation.count;
347 std::unique_ptr<protocol::Runtime::CallFrame> callFrame =
348 protocol::Runtime::CallFrame::create()
349 .setFunctionName(toProtocolString(isolate, node->name))
350 .setScriptId(String16::fromInteger(node->script_id))
351 .setUrl(toProtocolString(isolate, node->script_name))
352 .setLineNumber(node->line_number - 1)
353 .setColumnNumber(node->column_number - 1)
355 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode> result =
356 protocol::HeapProfiler::SamplingHeapProfileNode::create()
357 .setCallFrame(std::move(callFrame))
358 .setSelfSize(selfSize)
359 .setChildren(std::move(children))
360 .setId(node->node_id)
366 Response V8HeapProfilerAgentImpl::stopSampling(
367 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) {
368 Response result = getSamplingProfile(profile);
369 if (result.isSuccess()) {
370 m_isolate->GetHeapProfiler()->StopSamplingHeapProfiler();
371 m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
377 Response V8HeapProfilerAgentImpl::getSamplingProfile(
378 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) {
382 std::unique_ptr<v8::AllocationProfile> v8Profile(
383 profiler->GetAllocationProfile());
385 return Response::Error(
"V8 sampling heap profiler was not started.");
387 auto samples = protocol::Array<
388 protocol::HeapProfiler::SamplingHeapProfileSample>::create();
389 for (
const auto& sample : v8Profile->GetSamples()) {
390 samples->addItem(protocol::HeapProfiler::SamplingHeapProfileSample::create()
391 .setSize(sample.size * sample.count)
392 .setNodeId(sample.node_id)
393 .setOrdinal(static_cast<double>(sample.sample_id))
396 *profile = protocol::HeapProfiler::SamplingHeapProfile::create()
397 .setHead(buildSampingHeapProfileNode(m_isolate, root))
398 .setSamples(std::move(samples))
400 return Response::OK();
V8_INLINE bool IsEmpty() const
Local< Context > CreationContext()
void Serialize(OutputStream *stream, SerializationFormat format=kJSON) const