15#include "src/inspector/protocol/Protocol.h"
25namespace HeapProfilerAgentState {
26static const char heapProfilerEnabled[] =
"heapProfilerEnabled";
27static const char heapObjectsTrackingEnabled[] =
"heapObjectsTrackingEnabled";
28static const char allocationTrackingEnabled[] =
"allocationTrackingEnabled";
29static const char samplingHeapProfilerEnabled[] =
"samplingHeapProfilerEnabled";
30static const char samplingHeapProfilerInterval[] =
31 "samplingHeapProfilerInterval";
32static const char samplingHeapProfilerFlags[] =
"samplingHeapProfilerFlags";
37 explicit HeapSnapshotProgress(protocol::HeapProfiler::Frontend* frontend)
39 ControlOption ReportProgressValue(uint32_t done, uint32_t total)
override {
40 m_frontend->reportHeapSnapshotProgress(done, total, std::nullopt);
42 m_frontend->reportHeapSnapshotProgress(total, total,
true);
52class GlobalObjectNameResolver final
55 explicit GlobalObjectNameResolver(V8InspectorSessionImpl* session)
60 if (!object->GetCreationContext(
m_session->inspector()->isolate())
61 .ToLocal(&creationContext)) {
64 InspectedContext* context =
m_session->inspector()->getContext(
67 if (!context)
return "";
68 String16 name = context->origin();
69 size_t length = name.length();
70 if (m_offset + length + 1 >=
m_strings.size())
return "";
89 explicit HeapSnapshotOutputStream(protocol::HeapProfiler::Frontend* frontend)
91 void EndOfStream()
override {}
93 WriteResult WriteAsciiChunk(
char* data,
int size)
override {
94 m_frontend->addHeapSnapshotChunk(String16(data, size));
110class InspectableHeapObject final :
public V8InspectorSession::Inspectable {
112 explicit InspectableHeapObject(
int heapObjectId)
115 return objectByHeapObjectId(context->GetIsolate(), m_heapObjectId);
124 explicit HeapStatsStream(protocol::HeapProfiler::Frontend* frontend)
127 void EndOfStream()
override {}
129 WriteResult WriteAsciiChunk(
char* data,
int size)
override {
135 int count)
override {
137 auto statsDiff = std::make_unique<protocol::Array<int>>();
139 statsDiff->emplace_back(updateData[
i].index);
140 statsDiff->emplace_back(updateData[
i].count);
141 statsDiff->emplace_back(updateData[
i].size);
143 m_frontend->heapStatsUpdate(std::move(statsDiff));
167 if (!asyncCallbacks)
return;
169 if (asyncCallbacks->m_canceled)
return;
171 v8::StackState::kNoHeapPointers);
172 for (
auto&
callback : asyncCallbacks->m_gcCallbacks) {
175 asyncCallbacks->m_gcCallbacks.clear();
185 std::optional<bool> treatGlobalObjectsAsRoots,
186 std::optional<bool> captureNumericValue,
187 std::optional<bool> exposeInternals)
201 std::shared_ptr<AsyncCallbacks> asyncCallbacks,
203 std::unique_ptr<TakeHeapSnapshotCallback>
callback)
212 Response response = Response::Success();
218 if (!asyncCallbacks)
return;
220 if (asyncCallbacks->m_canceled)
return;
222 auto& heapSnapshotTasks = asyncCallbacks->m_heapSnapshotTasks;
224 std::find(heapSnapshotTasks.begin(), heapSnapshotTasks.end(),
this);
225 if (it == heapSnapshotTasks.end()) {
231 heapSnapshotTasks.erase(it);
242 if (response.IsSuccess()) {
258 protocol::DictionaryValue* state)
260 m_isolate(session->inspector()->isolate()),
274 if (
m_state->booleanProperty(HeapProfilerAgentState::heapProfilerEnabled,
278 HeapProfilerAgentState::heapObjectsTrackingEnabled,
false))
280 HeapProfilerAgentState::allocationTrackingEnabled,
false));
282 HeapProfilerAgentState::samplingHeapProfilerEnabled,
false)) {
283 double samplingInterval =
m_state->doubleProperty(
284 HeapProfilerAgentState::samplingHeapProfilerInterval, -1);
286 int flags =
m_state->integerProperty(
287 HeapProfilerAgentState::samplingHeapProfilerFlags, 0);
296 std::unique_ptr<CollectGarbageCallback>
callback) {
306 std::optional<bool> trackAllocations) {
307 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled,
true);
308 bool allocationTrackingEnabled = trackAllocations.value_or(
false);
309 m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled,
310 allocationTrackingEnabled);
312 return Response::Success();
316 std::optional<bool> reportProgress,
317 std::optional<bool> treatGlobalObjectsAsRoots,
318 std::optional<bool> captureNumericValue,
319 std::optional<bool> exposeInternals) {
323 std::move(reportProgress), std::move(treatGlobalObjectsAsRoots),
324 std::move(captureNumericValue), std::move(exposeInternals)),
327 return Response::Success();
331 m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled,
true);
332 return Response::Success();
340 HeapProfilerAgentState::samplingHeapProfilerEnabled,
false)) {
341 profiler->StopSamplingHeapProfiler();
343 profiler->ClearObjectIds();
344 m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled,
false);
345 return Response::Success();
349 std::optional<bool> reportProgress,
350 std::optional<bool> treatGlobalObjectsAsRoots,
351 std::optional<bool> captureNumericValue,
352 std::optional<bool> exposeInternals,
353 std::unique_ptr<TakeHeapSnapshotCallback>
callback) {
355 std::move(reportProgress), std::move(treatGlobalObjectsAsRoots),
356 std::move(captureNumericValue), std::move(exposeInternals));
357 std::shared_ptr<v8::TaskRunner> task_runner =
366 !task_runner->NonNestableTasksEnabled()) {
369 if (response.IsSuccess()) {
372 callback->sendFailure(std::move(response));
377 std::unique_ptr<HeapSnapshotTask> task = std::make_unique<HeapSnapshotTask>(
380 task_runner->PostNonNestableTask(std::move(task));
388 std::unique_ptr<HeapSnapshotProgress> progress;
390 progress.reset(
new HeapSnapshotProgress(&
m_frontend));
392 GlobalObjectNameResolver resolver(
m_session);
395 options.control = progress.get();
396 options.snapshot_mode =
403 options.numerics_mode =
407 options.stack_state = stackState;
409 if (!snapshot)
return Response::ServerError(
"Failed to take heap snapshot");
411 snapshot->Serialize(&stream);
413 return Response::Success();
417 const String16& heapSnapshotObjectId, std::optional<String16> objectGroup,
418 std::unique_ptr<protocol::Runtime::RemoteObject>*
result) {
420 int id = heapSnapshotObjectId.
toInteger(&ok);
421 if (!ok)
return Response::ServerError(
"Invalid heap snapshot object id");
426 return Response::ServerError(
"Object is not available");
429 return Response::ServerError(
"Object is not available");
432 if (!heapObject->GetCreationContext(
m_isolate).ToLocal(&creationContext)) {
433 return Response::ServerError(
"Object is not available");
436 objectGroup.value_or(
""),
false);
437 if (!*
result)
return Response::ServerError(
"Object is not available");
438 return Response::Success();
450 const String16& inspectedHeapObjectId) {
452 int id = inspectedHeapObjectId.
toInteger(&ok);
453 if (!ok)
return Response::ServerError(
"Invalid heap snapshot object id");
458 return Response::ServerError(
"Object is not available");
461 return Response::ServerError(
"Object is not available");
463 std::unique_ptr<InspectableHeapObject>(
new InspectableHeapObject(
id)));
464 return Response::Success();
474 if (!response.IsSuccess())
return response;
475 if (value->IsUndefined())
return Response::InternalError();
479 return Response::Success();
517 reinterpret_cast<void*
>(
this));
521 reinterpret_cast<void*
>(
this));
527 bool trackAllocations) {
534 reinterpret_cast<void*
>(
this));
541 reinterpret_cast<void*
>(
this));
545 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled,
547 m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled,
false);
551 std::optional<double> samplingInterval,
552 std::optional<bool> includeObjectsCollectedByMajorGC,
553 std::optional<bool> includeObjectsCollectedByMinorGC) {
556 const unsigned defaultSamplingInterval = 1 << 15;
557 double samplingIntervalValue =
558 samplingInterval.value_or(defaultSamplingInterval);
559 if (samplingIntervalValue <= 0.0) {
560 return Response::ServerError(
"Invalid sampling interval");
562 m_state->setDouble(HeapProfilerAgentState::samplingHeapProfilerInterval,
563 samplingIntervalValue);
564 m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
567 if (includeObjectsCollectedByMajorGC.value_or(
false)) {
570 if (includeObjectsCollectedByMinorGC.value_or(
false)) {
573 m_state->setInteger(HeapProfilerAgentState::samplingHeapProfilerFlags, flags);
574 profiler->StartSamplingHeapProfiler(
575 static_cast<uint64_t
>(samplingIntervalValue), 128,
577 return Response::Success();
581std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode>
585 protocol::Array<protocol::HeapProfiler::SamplingHeapProfileNode>>();
586 for (
const auto* child : node->children)
587 children->emplace_back(buildSampingHeapProfileNode(isolate, child));
589 for (
const auto& allocation : node->allocations)
590 selfSize += allocation.size * allocation.count;
591 std::unique_ptr<protocol::Runtime::CallFrame> callFrame =
592 protocol::Runtime::CallFrame::create()
596 .setLineNumber(node->line_number - 1)
597 .setColumnNumber(node->column_number - 1)
599 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfileNode>
result =
600 protocol::HeapProfiler::SamplingHeapProfileNode::create()
601 .setCallFrame(std::move(callFrame))
602 .setSelfSize(selfSize)
604 .setId(node->node_id)
611 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) {
615 m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled,
622 std::unique_ptr<protocol::HeapProfiler::SamplingHeapProfile>* profile) {
626 std::unique_ptr<v8::AllocationProfile> v8Profile(
627 profiler->GetAllocationProfile());
629 return Response::ServerError(
"V8 sampling heap profiler was not started.");
631 auto samples = std::make_unique<
632 protocol::Array<protocol::HeapProfiler::SamplingHeapProfileSample>>();
633 for (
const auto& sample : v8Profile->GetSamples()) {
634 samples->emplace_back(
635 protocol::HeapProfiler::SamplingHeapProfileSample::create()
636 .setSize(sample.size * sample.count)
637 .setNodeId(sample.node_id)
638 .setOrdinal(
static_cast<double>(sample.sample_id))
641 *profile = protocol::HeapProfiler::SamplingHeapProfile::create()
642 .setHead(buildSampingHeapProfileNode(
m_isolate, root))
643 .setSamples(std::move(samples))
645 return Response::Success();
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
void StartTrackingHeapObjects(bool track_allocations=false)
@ kSamplingIncludeObjectsCollectedByMajorGC
@ kSamplingIncludeObjectsCollectedByMinorGC
SnapshotObjectId GetObjectId(Local< Value > value)
void StopSamplingHeapProfiler()
SnapshotObjectId GetHeapStats(OutputStream *stream, int64_t *timestamp_us=nullptr)
void StopTrackingHeapObjects()
HeapProfiler * GetHeapProfiler()
void PostNonNestableTask(std::unique_ptr< Task > task, const SourceLocation &location=SourceLocation::Current())
V8_INLINE bool IsEmpty() const
double InSecondsF() const
static constexpr TimeDelta FromMilliseconds(int64_t milliseconds)
static String16 fromInteger(int)
int toInteger(bool *ok=nullptr) const
GCTask(v8::Isolate *isolate, std::shared_ptr< AsyncCallbacks > asyncCallbacks)
std::weak_ptr< AsyncCallbacks > m_asyncCallbacks
HeapSnapshotTask(V8HeapProfilerAgentImpl *agent, std::shared_ptr< AsyncCallbacks > asyncCallbacks, HeapSnapshotProtocolOptions protocolOptions, std::unique_ptr< TakeHeapSnapshotCallback > callback)
HeapSnapshotProtocolOptions m_protocolOptions
std::weak_ptr< AsyncCallbacks > m_asyncCallbacks
std::unique_ptr< TakeHeapSnapshotCallback > m_callback
V8HeapProfilerAgentImpl * m_agent
void Run(cppgc::EmbedderStackState stackState)
Response enable() override
void collectGarbage(std::unique_ptr< CollectGarbageCallback > callback) override
Response takeHeapSnapshotNow(const HeapSnapshotProtocolOptions &protocolOptions, cppgc::EmbedderStackState stackState)
Response disable() override
void takePendingHeapSnapshots()
Response getHeapObjectId(const String16 &objectId, String16 *heapSnapshotObjectId) override
~V8HeapProfilerAgentImpl() override
Response stopTrackingHeapObjects(std::optional< bool > reportProgress, std::optional< bool > treatGlobalObjectsAsRoots, std::optional< bool > captureNumericValue, std::optional< bool > exposeInternals) override
std::shared_ptr< AsyncCallbacks > m_asyncCallbacks
void takeHeapSnapshot(std::optional< bool > reportProgress, std::optional< bool > treatGlobalObjectsAsRoots, std::optional< bool > captureNumericValue, std::optional< bool > exposeInternals, std::unique_ptr< TakeHeapSnapshotCallback > callback) override
Response addInspectedHeapObject(const String16 &inspectedHeapObjectId) override
V8HeapProfilerAgentImpl(V8InspectorSessionImpl *, protocol::FrontendChannel *, protocol::DictionaryValue *state)
void requestHeapStatsUpdate()
Response startSampling(std::optional< double > samplingInterval, std::optional< bool > includeObjectsCollectedByMajorGC, std::optional< bool > includeObjectsCollectedByMinorGC) override
void startTrackingHeapObjectsInternal(bool trackAllocations)
protocol::HeapProfiler::Frontend m_frontend
protocol::DictionaryValue * m_state
V8InspectorSessionImpl * m_session
void stopTrackingHeapObjectsInternal()
double m_timerDelayInSeconds
Response getSamplingProfile(std::unique_ptr< protocol::HeapProfiler::SamplingHeapProfile > *) override
Response startTrackingHeapObjects(std::optional< bool > trackAllocations) override
Response getObjectByHeapObjectId(const String16 &heapSnapshotObjectId, std::optional< String16 > objectGroup, std::unique_ptr< protocol::Runtime::RemoteObject > *result) override
Response stopSampling(std::unique_ptr< protocol::HeapProfiler::SamplingHeapProfile > *) override
static void onTimer(void *)
virtual bool isInspectableHeapObject(v8::Local< v8::Object >)
virtual void startRepeatingTimer(double, TimerCallback, void *data)
virtual double currentTimeMS()
virtual void cancelTimer(void *data)
V8InspectorClient * client()
void addInspectedObject(std::unique_ptr< V8InspectorSession::Inspectable >) override
std::unique_ptr< protocol::Runtime::RemoteObject > wrapObject(v8::Local< v8::Context >, v8::Local< v8::Value >, const String16 &groupName, bool generatePreview)
V8InspectorImpl * inspector() const
Response unwrapObject(const String16 &objectId, v8::Local< v8::Value > *, v8::Local< v8::Context > *, String16 *objectGroup)
std::vector< std::unique_ptr< InstanceTypeTree > > children
DirectHandle< JSReceiver > options
ZoneVector< RpoNumber > & result
@ kMayContainHeapPointers
void ForceGarbageCollection(Isolate *isolate, StackState embedder_stack_state)
Platform * GetCurrentPlatform()
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage * MB
String16 toProtocolString(v8::Isolate *isolate, v8::Local< v8::String > value)
static constexpr v8::base::TimeDelta kDefaultTimerDelay
uint32_t SnapshotObjectId
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_GT(v1, v2)
ObjectNameResolver * global_object_name_resolver
std::vector< std::unique_ptr< CollectGarbageCallback > > m_gcCallbacks
std::vector< V8HeapProfilerAgentImpl::HeapSnapshotTask * > m_heapSnapshotTasks
bool m_treatGlobalObjectsAsRoots
HeapSnapshotProtocolOptions(std::optional< bool > reportProgress, std::optional< bool > treatGlobalObjectsAsRoots, std::optional< bool > captureNumericValue, std::optional< bool > exposeInternals)
bool m_captureNumericValue
V8InspectorSessionImpl * m_session
protocol::HeapProfiler::Frontend * m_frontend
std::vector< char > m_strings
std::unique_ptr< ValueMirror > value