!7274 [Bug]: startcpuprofiler增加防重入机制

Merge pull request !7274 from wanghuan2022/master
This commit is contained in:
openharmony_ci 2024-05-13 03:32:12 +00:00 committed by Gitee
commit 86dfd767ac
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 120 additions and 109 deletions

View File

@ -47,26 +47,23 @@ CpuProfiler::CpuProfiler(const EcmaVM *vm, const int interval) : vm_(vm), interv
}
}
void CpuProfiler::StartCpuProfilerForInfo()
bool CpuProfiler::StartCpuProfilerForInfo()
{
LOG_ECMA(INFO) << "StartCpuProfilerForInfo, Sampling interval is: " << interval_;
LOG_ECMA(INFO) << "CpuProfiler::StartCpuProfilerForInfo, sampling interval = " << interval_;
if (isProfiling_) {
LOG_ECMA(ERROR) << "Can not StartCpuProfilerForInfo when CpuProfiler is Profiling";
return;
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, can not start when CpuProfiler is Profiling";
return false;
}
isProfiling_ = true;
struct sigaction sa;
sa.sa_sigaction = &GetStackSignalHandler;
if (sigemptyset(&sa.sa_mask) != 0) {
LOG_ECMA(ERROR) << "Parameter set signal set initialization and emptying failed";
isProfiling_ = false;
return;
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, sigemptyset failed, errno = " << errno;
return false;
}
sa.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGPROF, &sa, nullptr) != 0) {
LOG_ECMA(ERROR) << "sigaction failed to set signal";
isProfiling_ = false;
return;
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, sigaction failed, errno = " << errno;
return false;
}
tid_ = static_cast<pthread_t>(syscall(SYS_gettid));
{
@ -74,7 +71,6 @@ void CpuProfiler::StartCpuProfilerForInfo()
profilerMap_[tid_] = vm_;
}
vm_->GetJSThread()->SetIsProfiling(true);
JSPandaFileManager *pandaFileManager = JSPandaFileManager::GetInstance();
pandaFileManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
pandaFileManager->CpuProfilerGetJSPtExtractor(file.get());
@ -85,59 +81,50 @@ void CpuProfiler::StartCpuProfilerForInfo()
generator_->SetIsStart(true);
params_ = new RunParams(generator_, static_cast<uint32_t>(interval_), pthread_self());
if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) {
LOG_ECMA(ERROR) << "pthread_create fail!";
return;
}
}
void CpuProfiler::StartCpuProfilerForFile(const std::string &fileName)
{
LOG_ECMA(INFO) << "StartCpuProfilerForFile, Sampling interval is: " << interval_;
if (isProfiling_) {
LOG_ECMA(ERROR) << "Can not StartCpuProfilerForFile when CpuProfiler is Profiling";
return;
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, pthread_create failed, errno = " << errno;
return false;
}
isProfiling_ = true;
vm_->GetJSThread()->SetIsProfiling(true);
outToFile_ = false;
return true;
}
bool CpuProfiler::StartCpuProfilerForFile(const std::string &fileName)
{
LOG_ECMA(INFO) << "CpuProfiler::StartCpuProfilerForFile, sampling interval = " << interval_;
if (isProfiling_) {
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, can not start when CpuProfiler is Profiling";
return false;
}
std::string absoluteFilePath("");
if (!CheckFileName(fileName, absoluteFilePath)) {
LOG_ECMA(ERROR) << "The filename contains illegal characters";
isProfiling_ = false;
return;
return false;
}
fileName_ = absoluteFilePath;
if (fileName_.empty()) {
LOG_ECMA(ERROR) << "CpuProfiler filename is empty!";
isProfiling_ = false;
return;
}
generator_->SetFileName(fileName_);
generator_->fileHandle_.open(fileName_.c_str());
if (generator_->fileHandle_.fail()) {
LOG_ECMA(ERROR) << "File open failed";
isProfiling_ = false;
return;
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, fileHandle_ open failed";
return false;
}
struct sigaction sa;
sa.sa_sigaction = &GetStackSignalHandler;
if (sigemptyset(&sa.sa_mask) != 0) {
LOG_ECMA(ERROR) << "Parameter set signal set initialization and emptying failed";
isProfiling_ = false;
return;
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, sigemptyset failed, errno = " << errno;
return false;
}
sa.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigaction(SIGPROF, &sa, nullptr) != 0) {
LOG_ECMA(ERROR) << "sigaction failed to set signal";
isProfiling_ = false;
return;
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, sigaction failed, errno = " << errno;
return false;
}
tid_ = static_cast<pthread_t>(syscall(SYS_gettid));
{
LockHolder lock(synchronizationMutex_);
profilerMap_[tid_] = vm_;
}
outToFile_ = true;
vm_->GetJSThread()->SetIsProfiling(true);
JSPandaFileManager *pandaFileManager = JSPandaFileManager::GetInstance();
pandaFileManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
pandaFileManager->CpuProfilerGetJSPtExtractor(file.get());
@ -148,37 +135,39 @@ void CpuProfiler::StartCpuProfilerForFile(const std::string &fileName)
generator_->SetIsStart(true);
params_ = new RunParams(generator_, static_cast<uint32_t>(interval_), pthread_self());
if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) {
LOG_ECMA(ERROR) << "pthread_create fail!";
return;
LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, pthread_create failed, errno = " << errno;
return false;
}
isProfiling_ = true;
vm_->GetJSThread()->SetIsProfiling(true);
outToFile_ = true;
return true;
}
std::unique_ptr<struct ProfileInfo> CpuProfiler::StopCpuProfilerForInfo()
bool CpuProfiler::StopCpuProfilerForInfo(std::unique_ptr<struct ProfileInfo> &profileInfo)
{
LOG_ECMA(INFO) << "StopCpuProfilerForInfo enter";
std::unique_ptr<struct ProfileInfo> profileInfo;
LOG_ECMA(INFO) << "CpuProfiler::StopCpuProfilerForInfo enter";
if (!isProfiling_) {
LOG_ECMA(ERROR) << "Do not execute stop cpuprofiler twice in a row or didn't execute the start\
or the sampling thread is not started";
return profileInfo;
LOG_ECMA(WARN) << "CpuProfiler::StopCpuProfilerForInfo, not isProfiling_";
return true;
}
if (outToFile_) {
LOG_ECMA(ERROR) << "Can not Stop a CpuProfiler sampling which is for file output by this stop method";
return profileInfo;
LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, is outToFile_";
return false;
}
generator_->SetIsStart(false);
if (generator_->SemPost(0) != 0) {
LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, sem_[0] post failed, errno = " << errno;
return false;
}
if (generator_->SemWait(1) != 0) {
LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, sem_[1] wait failed, errno = " << errno;
return false;
}
isProfiling_ = false;
vm_->GetJSThread()->SetIsProfiling(false);
generator_->SetIsStart(false);
if (generator_->SemPost(0) != 0) {
LOG_ECMA(ERROR) << "sem_[0] post failed, errno = " << errno;
return profileInfo;
}
if (generator_->SemWait(1) != 0) {
LOG_ECMA(ERROR) << "sem_[1] wait failed, errno = " << errno;
return profileInfo;
}
profileInfo = generator_->GetProfileInfo();
return profileInfo;
return true;
}
void CpuProfiler::SetCpuSamplingInterval(int interval)
@ -186,35 +175,32 @@ void CpuProfiler::SetCpuSamplingInterval(int interval)
interval_ = static_cast<uint32_t>(interval);
}
void CpuProfiler::StopCpuProfilerForFile()
bool CpuProfiler::StopCpuProfilerForFile()
{
LOG_ECMA(INFO) << "StopCpuProfilerForFile enter";
LOG_ECMA(INFO) << "CpuProfiler::StopCpuProfilerForFile enter";
if (!isProfiling_) {
LOG_ECMA(ERROR) << "Do not execute stop cpuprofiler twice in a row or didn't execute the start\
or the sampling thread is not started";
return;
LOG_ECMA(WARN) << "CpuProfiler::StopCpuProfilerForFile, not isProfiling_";
return true;
}
if (!outToFile_) {
LOG_ECMA(ERROR) << "Can not Stop a CpuProfiler sampling which is for return profile info by\
this stop method";
return;
LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, not outToFile_";
return false;
}
isProfiling_ = false;
vm_->GetJSThread()->SetIsProfiling(false);
generator_->SetIsStart(false);
if (generator_->SemPost(0) != 0) {
LOG_ECMA(ERROR) << "sem_[0] post failed";
return;
LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, sem_[0] post failed, errno = " << errno;
return false;
}
if (generator_->SemWait(1) != 0) {
LOG_ECMA(ERROR) << "sem_[1] wait failed";
return;
LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, sem_[1] wait failed, errno = " << errno;
return false;
}
isProfiling_ = false;
vm_->GetJSThread()->SetIsProfiling(false);
generator_->StringifySampleData();
std::string fileData = generator_->GetSampleData();
generator_->fileHandle_ << fileData;
return true;
}
CpuProfiler::~CpuProfiler()
@ -232,6 +218,10 @@ CpuProfiler::~CpuProfiler()
delete generator_;
generator_ = nullptr;
}
if (params_ != nullptr) {
delete params_;
params_ = nullptr;
}
}
void CpuProfiler::SetProfileStart(uint64_t nowTimeStamp)
@ -526,21 +516,24 @@ bool CpuProfiler::IsAddrAtStubOrAot(uint64_t pc) const
bool CpuProfiler::CheckFileName(const std::string &fileName, std::string &absoluteFilePath) const
{
if (fileName.empty()) {
return true;
LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, fileName is empty";
return false;
}
if (fileName.size() > PATH_MAX) {
LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, fileName exceed PATH_MAX";
return false;
}
CVector<char> resolvedPath(PATH_MAX);
auto result = realpath(fileName.c_str(), resolvedPath.data());
if (result == nullptr) {
LOG_ECMA(INFO) << "The file path does not exist";
LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, realpath fail, errno = " << errno;
return false;
}
std::ofstream file(resolvedPath.data());
if (!file.good()) {
LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, file is not good, errno = " << errno;
return false;
}
file.close();

View File

@ -86,10 +86,10 @@ public:
bool GetStackCallNapi(JSThread *thread, bool beforeCallNapi);
static void GetStackSignalHandler(int signal, siginfo_t *siginfo, void *context);
void StartCpuProfilerForInfo();
std::unique_ptr<struct ProfileInfo> StopCpuProfilerForInfo();
void StartCpuProfilerForFile(const std::string &fileName);
void StopCpuProfilerForFile();
bool StartCpuProfilerForInfo();
bool StopCpuProfilerForInfo(std::unique_ptr<struct ProfileInfo> &profileInfo);
bool StartCpuProfilerForFile(const std::string &fileName);
bool StopCpuProfilerForFile();
void SetCpuSamplingInterval(int interval);
void RecordCallNapiInfo(const std::string &methodAddr);
void SetBuildNapiStack(bool flag);

View File

@ -424,13 +424,17 @@ EcmaVM::~EcmaVM()
#endif
initialized_ = false;
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
if (thread_->isProfiling_) {
if (profiler_ != nullptr) {
if (profiler_->GetOutToFile()) {
DFXJSNApi::StopCpuProfilerForFile(this);
} else {
DFXJSNApi::StopCpuProfilerForInfo(this);
}
}
if (profiler_ != nullptr) {
delete profiler_;
profiler_ = nullptr;
}
#endif
#if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
DeleteHeapProfile();

View File

@ -577,40 +577,50 @@ bool DFXJSNApi::CpuProfilerSamplingAnyTime([[maybe_unused]] const EcmaVM *vm)
#endif
}
void DFXJSNApi::StartCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm,
bool DFXJSNApi::StartCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm,
[[maybe_unused]] const std::string &fileName,
[[maybe_unused]] int interval)
{
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
if (interval < 0) {
LOG_ECMA(ERROR) << "Sampling interval is illegal";
return;
LOG_ECMA(INFO) << "DFXJSNApi::StartCpuProfilerForFile, vm = " << vm;
if (interval <= 0) {
LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, interval <= 0";
return false;
}
if (vm == nullptr) {
return;
LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, vm == nullptr";
return false;
}
CpuProfiler *profiler = vm->GetProfiler();
if (profiler == nullptr) {
profiler = new CpuProfiler(vm, interval);
const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
}
profiler->StartCpuProfilerForFile(fileName);
return profiler->StartCpuProfilerForFile(fileName);
#else
LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForFile, not support cpu profiler";
return false;
#endif
}
void DFXJSNApi::StopCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm)
{
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
LOG_ECMA(INFO) << "DFXJSNApi::StopCpuProfilerForFile, vm = " << vm;
if (vm == nullptr) {
LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile, vm == nullptr";
return;
}
CpuProfiler *profiler = vm->GetProfiler();
if (profiler == nullptr) {
LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile, profiler == nullptr";
return;
}
bool result = profiler->StopCpuProfilerForFile();
if (!result) {
LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForFile failed";
return;
}
profiler->StopCpuProfilerForFile();
delete profiler;
profiler = nullptr;
const_cast<EcmaVM *>(vm)->SetProfiler(nullptr);
@ -619,24 +629,27 @@ void DFXJSNApi::StopCpuProfilerForFile([[maybe_unused]] const EcmaVM *vm)
#endif
}
void DFXJSNApi::StartCpuProfilerForInfo([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int interval)
bool DFXJSNApi::StartCpuProfilerForInfo([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int interval)
{
#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
if (interval < 0) {
LOG_ECMA(ERROR) << "Sampling interval is illegal";
return;
LOG_ECMA(INFO) << "DFXJSNApi::StartCpuProfilerForInfo, vm = " << vm;
if (interval <= 0) {
LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, interval <= 0";
return false;
}
if (vm == nullptr) {
return;
LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, vm == nullptr";
return false;
}
CpuProfiler *profiler = vm->GetProfiler();
if (profiler == nullptr) {
profiler = new CpuProfiler(vm, interval);
const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
}
profiler->StartCpuProfilerForInfo();
return profiler->StartCpuProfilerForInfo();
#else
LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
LOG_ECMA(ERROR) << "DFXJSNApi::StartCpuProfilerForInfo, not support cpu profiler";
return false;
#endif
}
@ -653,14 +666,16 @@ std::unique_ptr<ProfileInfo> DFXJSNApi::StopCpuProfilerForInfo([[maybe_unused]]
LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo, profiler == nullptr";
return nullptr;
}
auto profile = profiler->StopCpuProfilerForInfo();
if (profile == nullptr) {
LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo, CpuProfiler::StopCpuProfilerForInfo failed";
std::unique_ptr<ProfileInfo> profileInfo;
bool result = profiler->StopCpuProfilerForInfo(profileInfo);
if (!result) {
LOG_ECMA(ERROR) << "DFXJSNApi::StopCpuProfilerForInfo failed";
return nullptr;
}
delete profiler;
profiler = nullptr;
const_cast<EcmaVM *>(vm)->SetProfiler(nullptr);
return profile;
return profileInfo;
#else
LOG_ECMA(ERROR) << "Not support arkcompiler cpu profiler";
return nullptr;
@ -821,10 +836,9 @@ bool DFXJSNApi::StartProfiler(EcmaVM *vm, const ProfilerOption &option, int tid,
if (option.profilerType == ProfilerType::CPU_PROFILER) {
debugOption.isDebugMode = false;
if (JSNApi::NotifyDebugMode(tid, vm, debugOption, instanceId, debuggerPostTask, isDebugApp)) {
StartCpuProfilerForInfo(vm, option.interval);
return true;
return StartCpuProfilerForInfo(vm, option.interval);
} else {
LOG_ECMA(ERROR) << "DFXJSNApi:Failed to StartDebugger";
LOG_ECMA(ERROR) << "DFXJSNApi::StartProfiler, NotifyDebugMode failed";
return false;
}
} else {

View File

@ -115,10 +115,10 @@ public:
// cpuprofiler
static bool StopCpuProfilerForColdStart(const EcmaVM *vm);
static bool CpuProfilerSamplingAnyTime(const EcmaVM *vm);
static void StartCpuProfilerForFile(const EcmaVM *vm, const std::string &fileName,
static bool StartCpuProfilerForFile(const EcmaVM *vm, const std::string &fileName,
int interval = 500); // 500:Default Sampling interval 500 microseconds
static void StopCpuProfilerForFile(const EcmaVM *vm);
static void StartCpuProfilerForInfo(const EcmaVM *vm,
static bool StartCpuProfilerForInfo(const EcmaVM *vm,
int interval = 500); // 500:Default Sampling interval 500 microseconds
static std::unique_ptr<ProfileInfo> StopCpuProfilerForInfo(const EcmaVM *vm);
static void EnableSeriliazationTimeoutCheck(const EcmaVM *ecmaVM, int32_t threshhold);