mirror of
https://github.com/openharmony/ark_js_runtime.git
synced 2026-07-20 23:00:29 -04:00
!1740 heapprofiler support traceAllocation
Merge pull request !1740 from Riachel/master
This commit is contained in:
@@ -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<HeapTracker>(snapshot, timeInterval, stream);
|
||||
const_cast<EcmaVM *>(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<NativeAreaAllocator *>(vm_->GetNativeAreaAllocator())
|
||||
->New<HeapSnapshot>(vm_, isVmMode, isPrivate);
|
||||
->New<HeapSnapshot>(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<NativeAreaAllocator *>(vm_->GetNativeAreaAllocator())
|
||||
->New<HeapSnapshot>(vm_, isVmMode, isPrivate);
|
||||
->New<HeapSnapshot>(vm_, isVmMode, isPrivate, traceAllocation);
|
||||
if (snapshot == nullptr) {
|
||||
LOG_FULL(FATAL) << "alloc snapshot failed";
|
||||
UNREACHABLE();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<int>(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<uint32_t> 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<int>(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;
|
||||
|
||||
@@ -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<typename T>
|
||||
@@ -256,13 +261,95 @@ private:
|
||||
CUnorderedMap<Address, Node *> 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<TraceNode*>& 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<TraceNode*> children_;
|
||||
};
|
||||
|
||||
class TraceTree {
|
||||
public:
|
||||
TraceTree() : nextNodeId_(1), root_(this, 0)
|
||||
{
|
||||
}
|
||||
~TraceTree() = default;
|
||||
TraceTree(const TraceTree&) = delete;
|
||||
TraceTree& operator=(const TraceTree&) = delete;
|
||||
TraceNode* AddNodeToTree(CVector<uint32_t> 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<TimeStamp> &GetTimeStamps() const
|
||||
{
|
||||
@@ -329,6 +419,29 @@ public:
|
||||
return isPrivate_;
|
||||
}
|
||||
|
||||
bool trackAllocations() const
|
||||
{
|
||||
return trackAllocations_;
|
||||
}
|
||||
|
||||
const CVector<FunctionInfo> &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<FunctionInfo> traceInfoStack_ {};
|
||||
CMap<JSMethod *, struct FunctionInfo> stackInfo_;
|
||||
CMap<std::string, int> scriptIdMap_;
|
||||
TraceTree traceTree_;
|
||||
CMap<JSMethod *, uint32_t> methodToTraceNodeId_;
|
||||
CVector<uint32_t> traceNodeIndex_;
|
||||
};
|
||||
|
||||
class EntryVisitor {
|
||||
|
||||
@@ -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<FunctionInfo> 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()
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<uint64_t>(traceId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user