Files
ark_js_runtime/ecmascript/cpu_profiler/profile_generator.cpp
zhangyukun a97747fe18 Description:sync from code from wgr_master to ohos
Signed-off-by: zhangyukun <zhangyukun8@huawei.com>
Change-Id: Ic66a9e649de8c0ce530483296fe323b8f50621fb
2021-12-21 09:36:03 +08:00

203 lines
7.4 KiB
C++

/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/cpu_profiler/profile_generator.h"
#include <climits>
#include "ecmascript/cpu_profiler/cpu_profiler.h"
#include "ecmascript/interpreter/interpreter.h"
namespace panda::ecmascript {
int ProfileGenerator::staticGcState_ = false;
ProfileGenerator::ProfileGenerator()
{
stackTopLines_.push_back(0);
}
ProfileGenerator::~ProfileGenerator() {}
void ProfileGenerator::AddSample(CVector<JSMethod *> sample, time_t sampleTimeStamp)
{
static int PreviousId = 0;
struct MethodKey methodkey;
struct MethodNode methodNode;
if (staticGcState_) {
methodkey.method = reinterpret_cast<JSMethod*>(INT_MAX);
methodNode.parentId = methodkey.parentId = PreviousId;
auto result = methodMap_.find(methodkey);
if (result == methodMap_.end()) {
methodNode.id = methodMap_.size() + 1;
methodMap_.insert(std::make_pair(methodkey, methodNode.id));
methodNode.codeEntry = GetGcInfo();
stackTopLines_.push_back(0);
methodNodes_.push_back(methodNode);
} else {
methodNode.id = result->second;
}
staticGcState_ = false;
} else {
for (auto method = sample.rbegin(); method != sample.rend(); method++) {
methodkey.method = *method;
if (method == sample.rbegin()) {
methodNode.parentId = methodkey.parentId = 0;
} else {
methodNode.parentId = methodkey.parentId = methodNode.id;
}
auto result = methodMap_.find(methodkey);
if (result == methodMap_.end()) {
int id = methodMap_.size() + 1;
methodMap_.insert(std::make_pair(methodkey, id));
PreviousId = methodNode.id = id;
methodNode.codeEntry = GetMethodInfo(methodkey.method);
stackTopLines_.push_back(methodNode.codeEntry.lineNumber);
methodNodes_.push_back(methodNode);
} else {
PreviousId = methodNode.id = result->second;
}
}
}
static time_t threadStartTime = 0;
struct SampleInfo sampleInfo;
sampleInfo.id = methodNode.id;
sampleInfo.line = stackTopLines_[methodNode.id];
if (threadStartTime == 0) {
sampleInfo.timeStamp = sampleTimeStamp - threadStartTime_;
} else {
sampleInfo.timeStamp = sampleTimeStamp - threadStartTime;
}
samples_.push_back(sampleInfo);
threadStartTime = sampleTimeStamp;
}
void ProfileGenerator::WriteAddNodes()
{
sampleData_ += "{\"args\":{\"data\":{\"cpuProfile\":{\"nodes\":[";
for (auto it : methodNodes_) {
sampleData_ += "{\"callFrame\":{\"codeType\":\"" + it.codeEntry.codeType + "\",";
if (it.parentId == 0) {
sampleData_ += "\"functionName\":\"(root)\",\"scriptId\":0},\"id\":1},";
continue;
}
if (it.codeEntry.codeType == "other" || it.codeEntry.codeType == "jsvm") {
sampleData_ += "\"functionName\":\"" + it.codeEntry.functionName + "\",\"scriptId\":" +
std::to_string(it.codeEntry.scriptId) + "},\"id\":" + std::to_string(it.id);
} else {
sampleData_ += "\"columnNumber\":" + std::to_string(it.codeEntry.columnNumber) +
",\"functionName\":\"" + it.codeEntry.functionName + "\",\"lineNumber\":\"" +
std::to_string(it.codeEntry.lineNumber) + "\",\"scriptId\":" +
std::to_string(it.codeEntry.scriptId) + ",\"url\":\"" + it.codeEntry.url +
"\"},\"id\":" + std::to_string(it.id);
}
sampleData_ += ",\"parent\":" + std::to_string(it.parentId) + "},";
}
sampleData_.pop_back();
sampleData_ += "],\"samples\":[";
}
void ProfileGenerator::WriteAddSamples()
{
if (samples_.empty()) {
return;
}
std::string sampleId = "";
std::string sampleLine = "";
std::string timeStamp = "";
for (auto it : samples_) {
sampleId += std::to_string(it.id) + ",";
sampleLine += std::to_string(it.line) + ",";
timeStamp += std::to_string(it.timeStamp) + ",";
}
sampleId.pop_back();
sampleLine.pop_back();
timeStamp.pop_back();
sampleData_ += sampleId + "]},\"lines\":[" + sampleLine + "],\"timeDeltas\":[" + timeStamp + "]}},";
}
void ProfileGenerator::WriteMethodsAndSampleInfo(bool timeEnd)
{
if (methodNodes_.size() >= 10) { // 10:Number of nodes currently stored
WriteAddNodes();
WriteAddSamples();
methodNodes_.clear();
samples_.clear();
} else if (samples_.size() == 100 || timeEnd) { // 100:Number of samples currently stored
if (!methodNodes_.empty()) {
WriteAddNodes();
WriteAddSamples();
methodNodes_.clear();
samples_.clear();
} else if (!samples_.empty()) {
sampleData_ += "{\"args\":{\"data\":{\"cpuProfile\":{\"samples\":[";
WriteAddSamples();
samples_.clear();
} else {
return;
}
}
sampleData_ += "\"cat\":\"disabled-by-default-v8.cpu_profiler\",\"id\":"
"\"0x2\",\"name\":\"ProfileChunk\",\"ph\":\"P\",\"pid\":";
pid_t pid = getpid();
pthread_t tid = syscall(SYS_gettid);
time_t ts = ProfileProcessor::GetMicrosecondsTimeStamp();
ts = ts % TIME_CHANGE;
struct timespec time = {0, 0};
clock_gettime(CLOCK_MONOTONIC, &time);
time_t tts = time.tv_nsec / 1000; // 1000:Nanoseconds to milliseconds.
sampleData_ += std::to_string(pid) + ",\"tid\":" +
std::to_string(tid) + ",\"ts\":" +
std::to_string(ts) + ",\"tts\":" +
std::to_string(tts) + "},\n";
}
CVector<struct MethodNode> ProfileGenerator::GetMethodNodes() const
{
return methodNodes_;
}
CDeque<struct SampleInfo> ProfileGenerator::GetSamples() const
{
return samples_;
}
std::string ProfileGenerator::GetSampleData() const
{
return sampleData_;
}
struct StackInfo ProfileGenerator::GetMethodInfo(JSMethod *method)
{
struct StackInfo entry;
auto iter = CpuProfiler::staticStackInfo_.find(method);
if (iter != CpuProfiler::staticStackInfo_.end()) {
entry = iter->second;
}
return entry;
}
struct StackInfo ProfileGenerator::GetGcInfo()
{
struct StackInfo gcEntry;
gcEntry.codeType = "jsvm";
gcEntry.functionName = "garbage collector";
return gcEntry;
}
void ProfileGenerator::SetThreadStartTime(time_t threadStartTime)
{
threadStartTime_ = threadStartTime;
}
void ProfileGenerator::SetStartsampleData(std::string sampleData)
{
sampleData_ += sampleData;
}
} // namespace panda::ecmascript