diff --git a/ecmascript/dfx/hprof/heap_profiler.cpp b/ecmascript/dfx/hprof/heap_profiler.cpp index f23afbc7..764915de 100644 --- a/ecmascript/dfx/hprof/heap_profiler.cpp +++ b/ecmascript/dfx/hprof/heap_profiler.cpp @@ -55,13 +55,13 @@ bool HeapProfiler::DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progr return jsonSerializer_->Serialize(snapshot, stream); } -bool HeapProfiler::StartHeapTracking(double timeInterval, bool isVmMode, Stream *stream) +bool HeapProfiler::StartHeapTracking(double timeInterval, bool isVmMode, Stream *stream, bool traceAllocation) { - HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::REAL_TIME, isVmMode); + HeapSnapshot *snapshot = MakeHeapSnapshot(SampleType::REAL_TIME, isVmMode, false, traceAllocation); if (snapshot == nullptr) { return false; } - + heapTracker_ = std::make_unique(snapshot, timeInterval, stream); const_cast(vm_)->StartHeapTracking(heapTracker_.get()); heapTracker_->StartTracing(); @@ -150,7 +150,7 @@ bool HeapProfiler::ForceFullGC(const EcmaVM *vm) return false; } -HeapSnapshot *HeapProfiler::MakeHeapSnapshot(SampleType sampleType, bool isVmMode, bool isPrivate) +HeapSnapshot *HeapProfiler::MakeHeapSnapshot(SampleType sampleType, bool isVmMode, bool isPrivate, bool traceAllocation) { LOG_ECMA(ERROR) << "HeapProfiler::MakeHeapSnapshot"; DISALLOW_GARBAGE_COLLECTION; @@ -158,7 +158,7 @@ HeapSnapshot *HeapProfiler::MakeHeapSnapshot(SampleType sampleType, bool isVmMod switch (sampleType) { case SampleType::ONE_SHOT: { auto *snapshot = const_cast(vm_->GetNativeAreaAllocator()) - ->New(vm_, isVmMode, isPrivate); + ->New(vm_, isVmMode, isPrivate, traceAllocation); if (snapshot == nullptr) { LOG_FULL(FATAL) << "alloc snapshot failed"; UNREACHABLE(); @@ -169,7 +169,7 @@ HeapSnapshot *HeapProfiler::MakeHeapSnapshot(SampleType sampleType, bool isVmMod } case SampleType::REAL_TIME: { auto *snapshot = const_cast(vm_->GetNativeAreaAllocator()) - ->New(vm_, isVmMode, isPrivate); + ->New(vm_, isVmMode, isPrivate, traceAllocation); if (snapshot == nullptr) { LOG_FULL(FATAL) << "alloc snapshot failed"; UNREACHABLE(); diff --git a/ecmascript/dfx/hprof/heap_profiler.h b/ecmascript/dfx/hprof/heap_profiler.h index 859b807d..b13d8513 100644 --- a/ecmascript/dfx/hprof/heap_profiler.h +++ b/ecmascript/dfx/hprof/heap_profiler.h @@ -53,7 +53,8 @@ public: void AddSnapshot(HeapSnapshot *snapshot); - bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr) override; + bool StartHeapTracking(double timeInterval, bool isVmMode = true, + Stream *stream = nullptr, bool traceAllocation = false) override; bool StopHeapTracking(Stream *stream, Progress *progress = nullptr) override; private: @@ -65,7 +66,8 @@ private: /** * make a new heap snapshot and put it into a container eg, vector */ - HeapSnapshot *MakeHeapSnapshot(SampleType sampleType, bool isVmMode = true, bool isPrivate = false); + HeapSnapshot *MakeHeapSnapshot(SampleType sampleType, bool isVmMode = true, + bool isPrivate = false, bool traceAllocation = false); std::string GenDumpFileName(DumpFormat dumpFormat); CString GetTimeStamp(); void ClearSnapshot(); diff --git a/ecmascript/dfx/hprof/heap_profiler_interface.h b/ecmascript/dfx/hprof/heap_profiler_interface.h index 1e38c683..54ce4ed6 100644 --- a/ecmascript/dfx/hprof/heap_profiler_interface.h +++ b/ecmascript/dfx/hprof/heap_profiler_interface.h @@ -35,7 +35,8 @@ public: virtual bool DumpHeapSnapshot(DumpFormat dumpFormat, Stream *stream, Progress *progress = nullptr, bool isVmMode = true, bool isPrivate = false) = 0; - virtual bool StartHeapTracking(double timeInterval, bool isVmMode = true, Stream *stream = nullptr) = 0; + virtual bool StartHeapTracking(double timeInterval, bool isVmMode = true, + Stream *stream = nullptr, bool traceAllocation = false) = 0; virtual bool StopHeapTracking(Stream *stream, Progress *progress = nullptr) = 0; NO_MOVE_SEMANTIC(HeapProfilerInterface); diff --git a/ecmascript/dfx/hprof/heap_snapshot.cpp b/ecmascript/dfx/hprof/heap_snapshot.cpp index c80e59f0..ed62192b 100644 --- a/ecmascript/dfx/hprof/heap_snapshot.cpp +++ b/ecmascript/dfx/hprof/heap_snapshot.cpp @@ -33,6 +33,7 @@ #include "ecmascript/property_attributes.h" #include "ecmascript/tagged_array.h" #include "ecmascript/tagged_dictionary.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" namespace panda::ecmascript { CString *HeapSnapshot::GetString(const CString &as) @@ -72,6 +73,11 @@ HeapSnapshot::~HeapSnapshot() } nodes_.clear(); edges_.clear(); + traceInfoStack_.clear(); + stackInfo_.clear(); + scriptIdMap_.clear(); + methodToTraceNodeId_.clear(); + traceNodeIndex_.clear(); } bool HeapSnapshot::BuildUp() @@ -91,6 +97,9 @@ bool HeapSnapshot::Verify() void HeapSnapshot::PrepareSnapshot() { FillNodes(); + if (trackAllocations()) { + PrepareTraceInfo(); + } } void HeapSnapshot::UpdateNode() @@ -162,20 +171,23 @@ void HeapSnapshot::PushHeapStat(Stream* stream) stream->UpdateLastSeenObjectId(sequenceId_); } -void HeapSnapshot::AddNode(TaggedObject* address) +Node *HeapSnapshot::AddNode(TaggedObject* address) { - GenerateNode(JSTaggedValue(address)); + return GenerateNode(JSTaggedValue(address)); } void HeapSnapshot::MoveNode(uintptr_t address, TaggedObject* forward_address) { int sequenceId = -1; + int traceNodeId = 0; Node *node = entryMap_.FindAndEraseNode(address); if (node != nullptr) { sequenceId = static_cast(node->GetId()); + traceNodeId = node->GetStackTraceId(); EraseNodeUnique(node); } - GenerateNode(JSTaggedValue(forward_address), sequenceId); + node = GenerateNode(JSTaggedValue(forward_address), sequenceId); + node->SetTraceId(traceNodeId); } // NOLINTNEXTLINE(readability-function-size) @@ -599,6 +611,157 @@ Node *HeapSnapshot::GenerateNode(JSTaggedValue entry, int sequenceId) return node; } +TraceNode::TraceNode(TraceTree* tree, uint32_t nodeIndex) + : tree_(tree), + nodeIndex_(nodeIndex), + totalSize_(0), + totalCount_(0), + id_(tree->GetNextNodeId()) +{ +} + +TraceNode::~TraceNode() +{ + for (TraceNode* node : children_) { + delete node; + } + children_.clear(); +} + +TraceNode* TraceTree::AddNodeToTree(CVector traceNodeIndex) +{ + uint32_t len = traceNodeIndex.size(); + if (len == 0) { + return nullptr; + } + + TraceNode* node = GetRoot(); + for (int i = len - 1; i >= 0; i--) { + node = node->FindOrAddChild(traceNodeIndex[i]); + } + return node; +} + +TraceNode* TraceNode::FindOrAddChild(uint32_t nodeIndex) +{ + TraceNode* child = FindChild(nodeIndex); + if (child == nullptr) { + child = new TraceNode(tree_, nodeIndex); + children_.push_back(child); + } + return child; +} + +TraceNode* TraceNode::FindChild(uint32_t nodeIndex) +{ + for (TraceNode* node : children_) { + if (node->GetNodeIndex() == nodeIndex) { + return node; + } + } + return nullptr; +} + +void HeapSnapshot::AddTraceNodeId(JSMethod *method) +{ + uint32_t traceNodeId = 0; + auto result = methodToTraceNodeId_.find(method); + if (result == methodToTraceNodeId_.end()) { + traceNodeId = traceInfoStack_.size() - 1; + methodToTraceNodeId_.insert(std::make_pair(method, traceNodeId)); + } else { + traceNodeId = result->second; + } + traceNodeIndex_.emplace_back(traceNodeId); +} + +int HeapSnapshot::AddTraceNode(int sequenceId, int size) +{ + traceNodeIndex_.clear(); + FrameHandler frameHandler(vm_->GetAssociatedJSThread()); + for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) { + if (!frameHandler.IsInterpretedFrame()) { + continue; + } + auto method = frameHandler.CheckAndGetMethod(); + if (method == nullptr || method->IsNativeWithCallField()) { + continue; + } + if (stackInfo_.count(method) == 0) { + AddMethodInfo(method, frameHandler, sequenceId); + } + AddTraceNodeId(method); + } + + TraceNode* topNode = traceTree_.AddNodeToTree(traceNodeIndex_); + if (topNode == nullptr) { + return -1; + } + int totalSize = topNode->GetTotalSize(); + totalSize += size; + topNode->SetTotalSize(totalSize); + int totalCount = topNode->GetTotalCount(); + topNode->SetTotalCount(++totalCount); + return topNode->GetId(); +} + +void HeapSnapshot::AddMethodInfo(JSMethod *method, const FrameHandler &frameHandler, int sequenceId) +{ + struct FunctionInfo codeEntry; + codeEntry.functionId = sequenceId; + const std::string &functionName = method->ParseFunctionName(); + if (functionName.empty()) { + codeEntry.functionName = "anonymous"; + } else { + codeEntry.functionName = functionName; + } + GetString(codeEntry.functionName.c_str()); + + // source file + tooling::JSPtExtractor *debugExtractor = + JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile()); + const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId()); + if (sourceFile.empty()) { + codeEntry.scriptName = ""; + } else { + codeEntry.scriptName = sourceFile; + auto iter = scriptIdMap_.find(codeEntry.scriptName); + if (iter == scriptIdMap_.end()) { + scriptIdMap_.insert(std::make_pair(codeEntry.scriptName, scriptIdMap_.size() + 1)); + codeEntry.scriptId = static_cast(scriptIdMap_.size()); + } else { + codeEntry.scriptId = iter->second; + } + } + GetString(codeEntry.scriptName.c_str()); + + // line number + int32_t lineNumber = 0; + int32_t columnNumber = 0; + auto callbackLineFunc = [&](int32_t line) -> bool { + lineNumber = line + 1; + return true; + }; + auto callbackColumnFunc = [&](int32_t column) -> bool { + columnNumber = column + 1; + return true; + }; + panda_file::File::EntityId methodId = method->GetMethodId(); + uint32_t offset = frameHandler.GetBytecodeOffset(); + if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) || + !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) { + codeEntry.lineNumber = 0; + codeEntry.columnNumber = 0; + } else { + codeEntry.lineNumber = lineNumber; + codeEntry.columnNumber = columnNumber; + } + + traceInfoStack_.emplace_back(codeEntry); + stackInfo_.insert(std::make_pair(method, codeEntry)); + return; +} + Node *HeapSnapshot::GenerateStringNode(JSTaggedValue entry, int sequenceId) { Node *node = nullptr; diff --git a/ecmascript/dfx/hprof/heap_snapshot.h b/ecmascript/dfx/hprof/heap_snapshot.h index 61b0e15c..cc2bf8dd 100644 --- a/ecmascript/dfx/hprof/heap_snapshot.h +++ b/ecmascript/dfx/hprof/heap_snapshot.h @@ -30,6 +30,7 @@ #include "ecmascript/mem/c_containers.h" #include "os/mem.h" #include "ecmascript/tooling/interface/stream.h" +#include "ecmascript/interpreter/frame_handler.h" namespace panda::ecmascript { // Define the Object Graphic @@ -107,6 +108,10 @@ public: { isLive_ = isLive; } + void SetTraceId(uint64_t traceId) + { + traceId_ = traceId; + } static Node *NewNode(const EcmaVM *vm, size_t id, size_t index, CString *name, NodeType type, size_t size, TaggedObject *entry, bool isLive = true); template @@ -256,13 +261,95 @@ private: CUnorderedMap nodesMap_ {}; }; +struct FunctionInfo { + int functionId = 0; + std::string functionName = ""; + std::string scriptName = ""; + int scriptId = 0; + int columnNumber = -1; + int lineNumber = -1; +}; + +class TraceTree; +class TraceNode { +public: + TraceNode(TraceTree* tree, uint32_t nodeIndex); + ~TraceNode(); + + TraceNode(const TraceNode&) = delete; + TraceNode& operator=(const TraceNode&) = delete; + TraceNode* FindChild(uint32_t nodeIndex); + TraceNode* FindOrAddChild(uint32_t nodeIndex); + uint32_t GetNodeIndex() const + { + return nodeIndex_; + } + uint32_t GetTotalSize() const + { + return totalSize_; + } + uint32_t GetTotalCount() const + { + return totalCount_; + } + uint32_t GetId() const + { + return id_; + } + const std::vector& GetChildren() const + { + return children_; + } + TraceNode &SetTotalSize(uint32_t totalSize) + { + totalSize_ = totalSize; + return *this; + } + TraceNode &SetTotalCount(uint32_t totalCount) + { + totalCount_ = totalCount; + return *this; + } + +private: + TraceTree* tree_; + uint32_t nodeIndex_; + uint32_t totalSize_; + uint32_t totalCount_; + uint32_t id_; + std::vector children_; +}; + +class TraceTree { +public: + TraceTree() : nextNodeId_(1), root_(this, 0) + { + } + ~TraceTree() = default; + TraceTree(const TraceTree&) = delete; + TraceTree& operator=(const TraceTree&) = delete; + TraceNode* AddNodeToTree(CVector traceNodeIndex); + TraceNode* GetRoot() + { + return &root_; + } + uint32_t GetNextNodeId() + { + return nextNodeId_++; + } + +private: + uint32_t nextNodeId_; + TraceNode root_; +}; + class HeapSnapshot { public: static constexpr int SEQ_STEP = 2; NO_MOVE_SEMANTIC(HeapSnapshot); NO_COPY_SEMANTIC(HeapSnapshot); - explicit HeapSnapshot(const EcmaVM *vm, const bool isVmMode, const bool isPrivate) - : stringTable_(vm), vm_(vm), isVmMode_(isVmMode), isPrivate_(isPrivate) + explicit HeapSnapshot(const EcmaVM *vm, const bool isVmMode, const bool isPrivate, const bool trackAllocations) + : stringTable_(vm), vm_(vm), isVmMode_(isVmMode), isPrivate_(isPrivate), trackAllocations_(trackAllocations) { } ~HeapSnapshot(); @@ -271,11 +358,14 @@ public: void PrepareSnapshot(); void UpdateNode(); - void AddNode(TaggedObject* address); + Node *AddNode(TaggedObject* address); void MoveNode(uintptr_t address, TaggedObject* forward_address); void RecordSampleTime(); bool FinishSnapshot(); void PushHeapStat(Stream* stream); + int AddTraceNode(int sequenceId, int size); + void AddMethodInfo(JSMethod *method, const FrameHandler &frameHandler, int sequenceId); + void AddTraceNodeId(JSMethod *method); const CVector &GetTimeStamps() const { @@ -329,6 +419,29 @@ public: return isPrivate_; } + bool trackAllocations() const + { + return trackAllocations_; + } + + const CVector &GetTrackAllocationsStack() const + { + return traceInfoStack_; + } + + TraceTree* GetTraceTree() + { + return &traceTree_; + } + + void PrepareTraceInfo() + { + struct FunctionInfo info; + info.functionName = "(root)"; + GetString(info.functionName.c_str()); + traceInfoStack_.push_back(info); + } + private: void FillNodes(); Node *GenerateNode(JSTaggedValue entry, int sequenceId = -1); @@ -359,6 +472,13 @@ private: bool isVmMode_ {true}; bool isPrivate_ {false}; Node* privateStringNode_ {nullptr}; + bool trackAllocations_ {false}; + CVector traceInfoStack_ {}; + CMap stackInfo_; + CMap scriptIdMap_; + TraceTree traceTree_; + CMap methodToTraceNodeId_; + CVector traceNodeIndex_; }; class EntryVisitor { diff --git a/ecmascript/dfx/hprof/heap_snapshot_json_serializer.cpp b/ecmascript/dfx/hprof/heap_snapshot_json_serializer.cpp index 40986ec1..7bd01343 100644 --- a/ecmascript/dfx/hprof/heap_snapshot_json_serializer.cpp +++ b/ecmascript/dfx/hprof/heap_snapshot_json_serializer.cpp @@ -76,8 +76,7 @@ void HeapSnapshotJSONSerializer::SerializeSnapshotHeader() stringBuffer_ << "\"location_fields\":[\"object_index\",\"script_id\",\"line\",\"column\"]},\n"; // 10. stringBuffer_ << "\"node_count\":" << snapshot_->GetNodeCount() << ",\n"; // 11. stringBuffer_ << "\"edge_count\":" << snapshot_->GetEdgeCount() << ",\n"; // 12. - stringBuffer_ << "\"trace_function_count\":" - << "0\n"; // 13. + stringBuffer_ << "\"trace_function_count\":" << snapshot_->GetTrackAllocationsStack().size() << "\n"; // 13. stringBuffer_ << "},\n"; // 14. } @@ -133,12 +132,60 @@ void HeapSnapshotJSONSerializer::SerializeEdges() void HeapSnapshotJSONSerializer::SerializeTraceFunctionInfo() { - stringBuffer_ << "\"trace_function_infos\":[],\n"; // Empty + const CVector trackAllocationsStack = snapshot_->GetTrackAllocationsStack(); + const StringHashMap *stringTable = snapshot_->GetEcmaStringTable(); + + stringBuffer_ << "\"trace_function_infos\":["; // Empty + size_t i = 0; + + for (const auto &info : trackAllocationsStack) { + if (i > 0) { // add comma except the first line + stringBuffer_ << ","; + } + stringBuffer_ << info.functionId << ","; + CString functionName(info.functionName.c_str()); + stringBuffer_ << stringTable->GetStringId(&functionName) << ","; + CString scriptName(info.scriptName.c_str()); + stringBuffer_ << stringTable->GetStringId(&scriptName) << ","; + stringBuffer_ << info.scriptId << ","; + stringBuffer_ << info.columnNumber << ","; + stringBuffer_ << info.lineNumber << "\n"; + i++; + } + stringBuffer_ << "],\n"; } void HeapSnapshotJSONSerializer::SerializeTraceTree() { - stringBuffer_ << "\"trace_tree\":[],\n"; // Empty + stringBuffer_ << "\"trace_tree\":["; + TraceTree* tree = snapshot_->GetTraceTree(); + if (tree != nullptr) { + SerializeTraceNode(tree->GetRoot()); + } + stringBuffer_ << "],\n"; +} + +void HeapSnapshotJSONSerializer::SerializeTraceNode(TraceNode* node) +{ + if (node == nullptr) { + return; + } + + stringBuffer_ << node->GetId() << ","; + stringBuffer_ << node->GetNodeIndex() << ","; + stringBuffer_ << node->GetTotalCount() << ","; + stringBuffer_ << node->GetTotalSize() << ","; + stringBuffer_ << "["; + + int i = 0; + for (TraceNode* child : node->GetChildren()) { + if (i > 0) { + stringBuffer_ << ","; + } + SerializeTraceNode(child); + i++; + } + stringBuffer_ << "]"; } void HeapSnapshotJSONSerializer::SerializeSamples() diff --git a/ecmascript/dfx/hprof/heap_snapshot_json_serializer.h b/ecmascript/dfx/hprof/heap_snapshot_json_serializer.h index 2606070e..fc1b92d7 100644 --- a/ecmascript/dfx/hprof/heap_snapshot_json_serializer.h +++ b/ecmascript/dfx/hprof/heap_snapshot_json_serializer.h @@ -28,6 +28,7 @@ using fstream = std::fstream; using stringstream = std::stringstream; class HeapSnapshot; +class TraceNode; class HeapSnapshotJSONSerializer { public: @@ -43,6 +44,7 @@ private: void SerializeEdges(); void SerializeTraceFunctionInfo(); void SerializeTraceTree(); + void SerializeTraceNode(TraceNode* node); void SerializeSamples(); void SerializeLocations(); void SerializeStringTable(); diff --git a/ecmascript/dfx/hprof/heap_tracker.cpp b/ecmascript/dfx/hprof/heap_tracker.cpp index 0d3e4d98..fb16b4b8 100644 --- a/ecmascript/dfx/hprof/heap_tracker.cpp +++ b/ecmascript/dfx/hprof/heap_tracker.cpp @@ -33,8 +33,17 @@ void HeapTrackerSample::Run() void HeapTracker::AllocationEvent(TaggedObject* address) { + Node *node; if (snapshot_ != nullptr) { - snapshot_->AddNode(address); + node = snapshot_->AddNode(address); + if (node != nullptr && snapshot_->trackAllocations()) { + int size = node->GetSelfSize(); + int sequenceId = node->GetId(); + int traceId = snapshot_->AddTraceNode(sequenceId, size); + if (traceId != -1) { + node->SetTraceId(static_cast(traceId)); + } + } } } diff --git a/ecmascript/napi/dfx_jsnapi.cpp b/ecmascript/napi/dfx_jsnapi.cpp index e178b131..94ac8755 100644 --- a/ecmascript/napi/dfx_jsnapi.cpp +++ b/ecmascript/napi/dfx_jsnapi.cpp @@ -90,10 +90,11 @@ bool DFXJSNApi::BuildJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr) return true; } -bool DFXJSNApi::StartHeapTracking(const EcmaVM *vm, double timeInterval, bool isVmMode, Stream *stream) +bool DFXJSNApi::StartHeapTracking(const EcmaVM *vm, double timeInterval, bool isVmMode, + Stream *stream, bool traceAllocation) { ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(vm); - return heapProfile->StartHeapTracking(timeInterval, isVmMode, stream); + return heapProfile->StartHeapTracking(timeInterval, isVmMode, stream, traceAllocation); } bool DFXJSNApi::StopHeapTracking(const EcmaVM *vm, const std::string &filePath) diff --git a/ecmascript/napi/include/dfx_jsnapi.h b/ecmascript/napi/include/dfx_jsnapi.h index e9882584..d23ee1c8 100644 --- a/ecmascript/napi/include/dfx_jsnapi.h +++ b/ecmascript/napi/include/dfx_jsnapi.h @@ -52,7 +52,7 @@ public: static bool BuildNativeAndJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr); static bool BuildJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr); static bool StartHeapTracking(const EcmaVM *vm, double timeInterval, bool isVmMode = true, - Stream *stream = nullptr); + Stream *stream = nullptr, bool traceAllocation = false); static bool StopHeapTracking(const EcmaVM *vm, const std::string &filePath); static bool StopHeapTracking(const EcmaVM *vm, Stream *stream, Progress *progress = nullptr); static void PrintStatisticResult(const EcmaVM *vm); diff --git a/ecmascript/tooling/agent/heapprofiler_impl.cpp b/ecmascript/tooling/agent/heapprofiler_impl.cpp index 28a07f80..c88cad3a 100644 --- a/ecmascript/tooling/agent/heapprofiler_impl.cpp +++ b/ecmascript/tooling/agent/heapprofiler_impl.cpp @@ -298,10 +298,10 @@ DispatchResponse HeapProfilerImpl::StartSampling([[maybe_unused]]const StartSamp return DispatchResponse::Fail("StartSampling not support now"); } -DispatchResponse HeapProfilerImpl::StartTrackingHeapObjects( - [[maybe_unused]]const StartTrackingHeapObjectsParams ¶ms) +DispatchResponse HeapProfilerImpl::StartTrackingHeapObjects(const StartTrackingHeapObjectsParams ¶ms) { - bool result = panda::DFXJSNApi::StartHeapTracking(vm_, INTERVAL, true, &stream_); + bool traceAllocation = params.GetTrackAllocations(); + bool result = panda::DFXJSNApi::StartHeapTracking(vm_, INTERVAL, true, &stream_, traceAllocation); if (result) { return DispatchResponse::Ok(); } else {