14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include <atomic> 194514f5e3Sopenharmony_ci#include <chrono> 204514f5e3Sopenharmony_ci#include <climits> 214514f5e3Sopenharmony_ci#include <fstream> 224514f5e3Sopenharmony_ci 234514f5e3Sopenharmony_ci#include "ecmascript/compiler/aot_file/aot_file_manager.h" 244514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/js_pandafile_manager.h" 254514f5e3Sopenharmony_ci#include "ecmascript/platform/ffrt.h" 264514f5e3Sopenharmony_ci 274514f5e3Sopenharmony_ci#if defined(ENABLE_FFRT_INTERFACES) 284514f5e3Sopenharmony_ci#include "c/executor_task.h" 294514f5e3Sopenharmony_ci#endif 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_ci#if !defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 324514f5e3Sopenharmony_ci #error "ECMASCRIPT_SUPPORT_CPUPROFILER not defined" 334514f5e3Sopenharmony_ci#endif 344514f5e3Sopenharmony_ci 354514f5e3Sopenharmony_cinamespace panda::ecmascript { 364514f5e3Sopenharmony_ciMutex CpuProfiler::synchronizationMutex_; 374514f5e3Sopenharmony_ciCMap<pthread_t, struct TaskInfo> CpuProfiler::profilerMap_ = CMap<pthread_t, struct TaskInfo>(); 384514f5e3Sopenharmony_ciCpuProfiler::CpuProfiler(const EcmaVM *vm, const int interval) : vm_(vm), interval_(interval) 394514f5e3Sopenharmony_ci{ 404514f5e3Sopenharmony_ci enableVMTag_ = const_cast<EcmaVM *>(vm)->GetJSOptions().EnableCpuProfilerVMTag(); 414514f5e3Sopenharmony_ci generator_ = new SamplesRecord(); 424514f5e3Sopenharmony_ci generator_->SetEnableVMTag(enableVMTag_); 434514f5e3Sopenharmony_ci generator_->SetSourceMapTranslateCallback(vm->GetSourceMapTranslateCallback()); 444514f5e3Sopenharmony_ci generator_->NodeInit(); 454514f5e3Sopenharmony_ci if (generator_->SemInit(0, 0, 0) != 0) { 464514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[0] init failed"; 474514f5e3Sopenharmony_ci } 484514f5e3Sopenharmony_ci if (generator_->SemInit(1, 0, 0) != 0) { 494514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[1] init failed"; 504514f5e3Sopenharmony_ci } 514514f5e3Sopenharmony_ci if (generator_->SemInit(2, 0, 0) != 0) { // 2: signal 2 524514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[2] init failed"; 534514f5e3Sopenharmony_ci } 544514f5e3Sopenharmony_ci} 554514f5e3Sopenharmony_ci 564514f5e3Sopenharmony_cibool CpuProfiler::RegisterGetStackSignal() 574514f5e3Sopenharmony_ci{ 584514f5e3Sopenharmony_ci struct sigaction sa; 594514f5e3Sopenharmony_ci sa.sa_sigaction = &GetStackSignalHandler; 604514f5e3Sopenharmony_ci if (sigemptyset(&sa.sa_mask) != 0) { 614514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::RegisterGetStackSignal, sigemptyset failed, errno = " << errno; 624514f5e3Sopenharmony_ci return false; 634514f5e3Sopenharmony_ci } 644514f5e3Sopenharmony_ci sa.sa_flags = SA_RESTART | SA_SIGINFO; 654514f5e3Sopenharmony_ci if (sigaction(SIGPROF, &sa, nullptr) != 0) { 664514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::RegisterGetStackSignal, sigaction failed, errno = " << errno; 674514f5e3Sopenharmony_ci return false; 684514f5e3Sopenharmony_ci } 694514f5e3Sopenharmony_ci return true; 704514f5e3Sopenharmony_ci} 714514f5e3Sopenharmony_ci 724514f5e3Sopenharmony_cibool CpuProfiler::StartCpuProfilerForInfo() 734514f5e3Sopenharmony_ci{ 744514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "CpuProfiler::StartCpuProfilerForInfo, sampling interval = " << interval_; 754514f5e3Sopenharmony_ci if (isProfiling_) { 764514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, can not start when CpuProfiler is Profiling"; 774514f5e3Sopenharmony_ci return false; 784514f5e3Sopenharmony_ci } 794514f5e3Sopenharmony_ci if (!RegisterGetStackSignal()) { 804514f5e3Sopenharmony_ci return false; 814514f5e3Sopenharmony_ci } 824514f5e3Sopenharmony_ci // when the ffrt is enabled for the thread, the tid_ will be task id 834514f5e3Sopenharmony_ci tid_ = static_cast<pthread_t>(JSThread::GetCurrentThreadId()); 844514f5e3Sopenharmony_ci void *taskHandle = nullptr; 854514f5e3Sopenharmony_ci // when the ffrt is enabled for the thread, 864514f5e3Sopenharmony_ci // we record the task handle, which can be used to obtain the running thread id in the task 874514f5e3Sopenharmony_ci#if defined(ENABLE_FFRT_INTERFACES) 884514f5e3Sopenharmony_ci taskHandle = ffrt_get_cur_task(); 894514f5e3Sopenharmony_ci TaskInfo taskInfo { vm_, taskHandle }; 904514f5e3Sopenharmony_ci#else 914514f5e3Sopenharmony_ci TaskInfo taskInfo { vm_, nullptr }; 924514f5e3Sopenharmony_ci#endif // defined(ENABLE_FFRT_INTERFACES) 934514f5e3Sopenharmony_ci { 944514f5e3Sopenharmony_ci LockHolder lock(synchronizationMutex_); 954514f5e3Sopenharmony_ci profilerMap_[tid_] = taskInfo; 964514f5e3Sopenharmony_ci } 974514f5e3Sopenharmony_ci 984514f5e3Sopenharmony_ci JSPandaFileManager *pandaFileManager = JSPandaFileManager::GetInstance(); 994514f5e3Sopenharmony_ci pandaFileManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool { 1004514f5e3Sopenharmony_ci pandaFileManager->CpuProfilerGetJSPtExtractor(file.get()); 1014514f5e3Sopenharmony_ci return true; 1024514f5e3Sopenharmony_ci }); 1034514f5e3Sopenharmony_ci 1044514f5e3Sopenharmony_ci generator_->SetTimeDeltaThreshold(interval_ * THRESHOLD_GROWTH_FACTORY + THRESHOLD_FIXED_INCREMENT); 1054514f5e3Sopenharmony_ci generator_->SetIsStart(true); 1064514f5e3Sopenharmony_ci uint64_t startTime = SamplingProcessor::GetMicrosecondsTimeStamp(); 1074514f5e3Sopenharmony_ci generator_->SetThreadStartTime(startTime); 1084514f5e3Sopenharmony_ci params_ = new RunParams(generator_, static_cast<uint32_t>(interval_), pthread_self(), taskHandle); 1094514f5e3Sopenharmony_ci if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) { 1104514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, pthread_create failed, errno = " << errno; 1114514f5e3Sopenharmony_ci return false; 1124514f5e3Sopenharmony_ci } 1134514f5e3Sopenharmony_ci isProfiling_ = true; 1144514f5e3Sopenharmony_ci vm_->GetJSThread()->SetIsProfiling(true); 1154514f5e3Sopenharmony_ci outToFile_ = false; 1164514f5e3Sopenharmony_ci return true; 1174514f5e3Sopenharmony_ci} 1184514f5e3Sopenharmony_ci 1194514f5e3Sopenharmony_cibool CpuProfiler::StartCpuProfilerForFile(const std::string &fileName) 1204514f5e3Sopenharmony_ci{ 1214514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "CpuProfiler::StartCpuProfilerForFile, sampling interval = " << interval_; 1224514f5e3Sopenharmony_ci if (isProfiling_) { 1234514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, can not start when CpuProfiler is Profiling"; 1244514f5e3Sopenharmony_ci return false; 1254514f5e3Sopenharmony_ci } 1264514f5e3Sopenharmony_ci std::string absoluteFilePath(""); 1274514f5e3Sopenharmony_ci if (!CheckFileName(fileName, absoluteFilePath)) { 1284514f5e3Sopenharmony_ci return false; 1294514f5e3Sopenharmony_ci } 1304514f5e3Sopenharmony_ci fileName_ = absoluteFilePath; 1314514f5e3Sopenharmony_ci generator_->SetFileName(fileName_); 1324514f5e3Sopenharmony_ci generator_->fileHandle_.open(fileName_.c_str()); 1334514f5e3Sopenharmony_ci if (generator_->fileHandle_.fail()) { 1344514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, fileHandle_ open failed"; 1354514f5e3Sopenharmony_ci return false; 1364514f5e3Sopenharmony_ci } 1374514f5e3Sopenharmony_ci if (!RegisterGetStackSignal()) { 1384514f5e3Sopenharmony_ci return false; 1394514f5e3Sopenharmony_ci } 1404514f5e3Sopenharmony_ci // when the ffrt is enabled for the thread, the tid_ will be task id 1414514f5e3Sopenharmony_ci tid_ = static_cast<pthread_t>(JSThread::GetCurrentThreadId()); 1424514f5e3Sopenharmony_ci void *taskHandle = nullptr; 1434514f5e3Sopenharmony_ci // when the ffrt is enabled for the thread, 1444514f5e3Sopenharmony_ci // we record the task handle, which can be used to obtain the running thread id in the task 1454514f5e3Sopenharmony_ci#if defined(ENABLE_FFRT_INTERFACES) 1464514f5e3Sopenharmony_ci taskHandle = ffrt_get_cur_task(); 1474514f5e3Sopenharmony_ci TaskInfo taskInfo { vm_, taskHandle }; 1484514f5e3Sopenharmony_ci#else 1494514f5e3Sopenharmony_ci TaskInfo taskInfo { vm_, nullptr }; 1504514f5e3Sopenharmony_ci#endif // defined(ENABLE_FFRT_INTERFACES) 1514514f5e3Sopenharmony_ci { 1524514f5e3Sopenharmony_ci LockHolder lock(synchronizationMutex_); 1534514f5e3Sopenharmony_ci profilerMap_[tid_] = taskInfo; 1544514f5e3Sopenharmony_ci } 1554514f5e3Sopenharmony_ci 1564514f5e3Sopenharmony_ci JSPandaFileManager *pandaFileManager = JSPandaFileManager::GetInstance(); 1574514f5e3Sopenharmony_ci pandaFileManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool { 1584514f5e3Sopenharmony_ci pandaFileManager->CpuProfilerGetJSPtExtractor(file.get()); 1594514f5e3Sopenharmony_ci return true; 1604514f5e3Sopenharmony_ci }); 1614514f5e3Sopenharmony_ci 1624514f5e3Sopenharmony_ci generator_->SetTimeDeltaThreshold(interval_ * THRESHOLD_GROWTH_FACTORY + THRESHOLD_FIXED_INCREMENT); 1634514f5e3Sopenharmony_ci generator_->SetIsStart(true); 1644514f5e3Sopenharmony_ci uint64_t startTime = SamplingProcessor::GetMicrosecondsTimeStamp(); 1654514f5e3Sopenharmony_ci generator_->SetThreadStartTime(startTime); 1664514f5e3Sopenharmony_ci params_ = new RunParams(generator_, static_cast<uint32_t>(interval_), pthread_self(), taskHandle); 1674514f5e3Sopenharmony_ci if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) { 1684514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, pthread_create failed, errno = " << errno; 1694514f5e3Sopenharmony_ci return false; 1704514f5e3Sopenharmony_ci } 1714514f5e3Sopenharmony_ci isProfiling_ = true; 1724514f5e3Sopenharmony_ci vm_->GetJSThread()->SetIsProfiling(true); 1734514f5e3Sopenharmony_ci outToFile_ = true; 1744514f5e3Sopenharmony_ci return true; 1754514f5e3Sopenharmony_ci} 1764514f5e3Sopenharmony_ci 1774514f5e3Sopenharmony_cibool CpuProfiler::StopCpuProfilerForInfo(std::unique_ptr<struct ProfileInfo> &profileInfo) 1784514f5e3Sopenharmony_ci{ 1794514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "CpuProfiler::StopCpuProfilerForInfo enter"; 1804514f5e3Sopenharmony_ci if (!isProfiling_) { 1814514f5e3Sopenharmony_ci LOG_ECMA(WARN) << "CpuProfiler::StopCpuProfilerForInfo, not isProfiling_"; 1824514f5e3Sopenharmony_ci return true; 1834514f5e3Sopenharmony_ci } 1844514f5e3Sopenharmony_ci if (outToFile_) { 1854514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, is outToFile_"; 1864514f5e3Sopenharmony_ci return false; 1874514f5e3Sopenharmony_ci } 1884514f5e3Sopenharmony_ci generator_->SetIsStart(false); 1894514f5e3Sopenharmony_ci if (generator_->SemPost(0) != 0) { 1904514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, sem_[0] post failed, errno = " << errno; 1914514f5e3Sopenharmony_ci return false; 1924514f5e3Sopenharmony_ci } 1934514f5e3Sopenharmony_ci if (generator_->SemWait(1) != 0) { 1944514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, sem_[1] wait failed, errno = " << errno; 1954514f5e3Sopenharmony_ci return false; 1964514f5e3Sopenharmony_ci } 1974514f5e3Sopenharmony_ci isProfiling_ = false; 1984514f5e3Sopenharmony_ci vm_->GetJSThread()->SetIsProfiling(false); 1994514f5e3Sopenharmony_ci profileInfo = generator_->GetProfileInfo(); 2004514f5e3Sopenharmony_ci return true; 2014514f5e3Sopenharmony_ci} 2024514f5e3Sopenharmony_ci 2034514f5e3Sopenharmony_civoid CpuProfiler::SetCpuSamplingInterval(int interval) 2044514f5e3Sopenharmony_ci{ 2054514f5e3Sopenharmony_ci interval_ = static_cast<uint32_t>(interval); 2064514f5e3Sopenharmony_ci} 2074514f5e3Sopenharmony_ci 2084514f5e3Sopenharmony_cibool CpuProfiler::StopCpuProfilerForFile() 2094514f5e3Sopenharmony_ci{ 2104514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "CpuProfiler::StopCpuProfilerForFile enter"; 2114514f5e3Sopenharmony_ci if (!isProfiling_) { 2124514f5e3Sopenharmony_ci LOG_ECMA(WARN) << "CpuProfiler::StopCpuProfilerForFile, not isProfiling_"; 2134514f5e3Sopenharmony_ci return true; 2144514f5e3Sopenharmony_ci } 2154514f5e3Sopenharmony_ci if (!outToFile_) { 2164514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, not outToFile_"; 2174514f5e3Sopenharmony_ci return false; 2184514f5e3Sopenharmony_ci } 2194514f5e3Sopenharmony_ci generator_->SetIsStart(false); 2204514f5e3Sopenharmony_ci if (generator_->SemPost(0) != 0) { 2214514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, sem_[0] post failed, errno = " << errno; 2224514f5e3Sopenharmony_ci return false; 2234514f5e3Sopenharmony_ci } 2244514f5e3Sopenharmony_ci if (generator_->SemWait(1) != 0) { 2254514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, sem_[1] wait failed, errno = " << errno; 2264514f5e3Sopenharmony_ci return false; 2274514f5e3Sopenharmony_ci } 2284514f5e3Sopenharmony_ci isProfiling_ = false; 2294514f5e3Sopenharmony_ci vm_->GetJSThread()->SetIsProfiling(false); 2304514f5e3Sopenharmony_ci generator_->StringifySampleData(); 2314514f5e3Sopenharmony_ci std::string fileData = generator_->GetSampleData(); 2324514f5e3Sopenharmony_ci generator_->fileHandle_ << fileData; 2334514f5e3Sopenharmony_ci return true; 2344514f5e3Sopenharmony_ci} 2354514f5e3Sopenharmony_ci 2364514f5e3Sopenharmony_ciCpuProfiler::~CpuProfiler() 2374514f5e3Sopenharmony_ci{ 2384514f5e3Sopenharmony_ci if (generator_->SemDestroy(0) != 0) { 2394514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[0] destroy failed"; 2404514f5e3Sopenharmony_ci } 2414514f5e3Sopenharmony_ci if (generator_->SemDestroy(1) != 0) { 2424514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[1] destroy failed"; 2434514f5e3Sopenharmony_ci } 2444514f5e3Sopenharmony_ci if (generator_->SemDestroy(2) != 0) { // 2: signal 2 2454514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[2] destroy failed"; 2464514f5e3Sopenharmony_ci } 2474514f5e3Sopenharmony_ci if (generator_ != nullptr) { 2484514f5e3Sopenharmony_ci delete generator_; 2494514f5e3Sopenharmony_ci generator_ = nullptr; 2504514f5e3Sopenharmony_ci } 2514514f5e3Sopenharmony_ci if (params_ != nullptr) { 2524514f5e3Sopenharmony_ci delete params_; 2534514f5e3Sopenharmony_ci params_ = nullptr; 2544514f5e3Sopenharmony_ci } 2554514f5e3Sopenharmony_ci} 2564514f5e3Sopenharmony_ci 2574514f5e3Sopenharmony_civoid CpuProfiler::GetStack(FrameIterator &it) 2584514f5e3Sopenharmony_ci{ 2594514f5e3Sopenharmony_ci const CMap<struct MethodKey, struct FrameInfo> &stackInfo = generator_->GetStackInfo(); 2604514f5e3Sopenharmony_ci bool topFrame = true; 2614514f5e3Sopenharmony_ci generator_->ResetFrameLength(); 2624514f5e3Sopenharmony_ci for (; !it.Done(); it.Advance<>()) { 2634514f5e3Sopenharmony_ci auto method = it.CheckAndGetMethod(); 2644514f5e3Sopenharmony_ci if (method == nullptr || !JSTaggedValue(method).IsMethod()) { 2654514f5e3Sopenharmony_ci continue; 2664514f5e3Sopenharmony_ci } 2674514f5e3Sopenharmony_ci bool isNative = method->IsNativeWithCallField(); 2684514f5e3Sopenharmony_ci struct MethodKey methodKey; 2694514f5e3Sopenharmony_ci methodKey.deoptType = method->GetDeoptType(); 2704514f5e3Sopenharmony_ci if (topFrame) { 2714514f5e3Sopenharmony_ci methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, true, enableVMTag_); 2724514f5e3Sopenharmony_ci topFrame = false; 2734514f5e3Sopenharmony_ci } else { 2744514f5e3Sopenharmony_ci methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, false, enableVMTag_); 2754514f5e3Sopenharmony_ci } 2764514f5e3Sopenharmony_ci if (isNative) { 2774514f5e3Sopenharmony_ci JsStackGetter::GetCallLineNumber(it, methodKey.lineNumber); 2784514f5e3Sopenharmony_ci } 2794514f5e3Sopenharmony_ci void *methodIdentifier = JsStackGetter::GetMethodIdentifier(method, it); 2804514f5e3Sopenharmony_ci if (methodIdentifier == nullptr) { 2814514f5e3Sopenharmony_ci continue; 2824514f5e3Sopenharmony_ci } 2834514f5e3Sopenharmony_ci methodKey.methodIdentifier = methodIdentifier; 2844514f5e3Sopenharmony_ci if (stackInfo.count(methodKey) == 0) { 2854514f5e3Sopenharmony_ci struct FrameInfoTemp codeEntry; 2864514f5e3Sopenharmony_ci if (UNLIKELY(!JsStackGetter::ParseMethodInfo(methodKey, it, vm_, codeEntry, true))) { 2874514f5e3Sopenharmony_ci continue; 2884514f5e3Sopenharmony_ci } 2894514f5e3Sopenharmony_ci if (UNLIKELY(!generator_->PushStackInfo(codeEntry))) { 2904514f5e3Sopenharmony_ci return; 2914514f5e3Sopenharmony_ci } 2924514f5e3Sopenharmony_ci } 2934514f5e3Sopenharmony_ci if (UNLIKELY(!generator_->PushFrameStack(methodKey))) { 2944514f5e3Sopenharmony_ci return; 2954514f5e3Sopenharmony_ci } 2964514f5e3Sopenharmony_ci } 2974514f5e3Sopenharmony_ci generator_->PostFrame(); 2984514f5e3Sopenharmony_ci} 2994514f5e3Sopenharmony_ci 3004514f5e3Sopenharmony_cibool CpuProfiler::GetStackBeforeCallNapi(JSThread *thread) 3014514f5e3Sopenharmony_ci{ 3024514f5e3Sopenharmony_ci uint64_t tempTimeStamp = SamplingProcessor::GetMicrosecondsTimeStamp(); 3034514f5e3Sopenharmony_ci if (tempTimeStamp - beforeCallNapiTimeStamp_ < interval_) { 3044514f5e3Sopenharmony_ci return false; 3054514f5e3Sopenharmony_ci } 3064514f5e3Sopenharmony_ci 3074514f5e3Sopenharmony_ci if (GetStackCallNapi(thread, true)) { 3084514f5e3Sopenharmony_ci beforeCallNapiTimeStamp_ = tempTimeStamp; 3094514f5e3Sopenharmony_ci return true; 3104514f5e3Sopenharmony_ci } 3114514f5e3Sopenharmony_ci return false; 3124514f5e3Sopenharmony_ci} 3134514f5e3Sopenharmony_ci 3144514f5e3Sopenharmony_civoid CpuProfiler::GetStackAfterCallNapi(JSThread *thread) 3154514f5e3Sopenharmony_ci{ 3164514f5e3Sopenharmony_ci GetStackCallNapi(thread, false); 3174514f5e3Sopenharmony_ci} 3184514f5e3Sopenharmony_ci 3194514f5e3Sopenharmony_cibool CpuProfiler::GetStackCallNapi(JSThread *thread, bool beforeCallNapi) 3204514f5e3Sopenharmony_ci{ 3214514f5e3Sopenharmony_ci [[maybe_unused]] CallNapiScope scope(this); 3224514f5e3Sopenharmony_ci const CMap<struct MethodKey, struct FrameInfo> &stackInfo = generator_->GetStackInfo(); 3234514f5e3Sopenharmony_ci generator_->ClearNapiStack(); 3244514f5e3Sopenharmony_ci bool topFrame = true; 3254514f5e3Sopenharmony_ci auto currentFrame = const_cast<JSTaggedType *>(thread->GetCurrentFrame()); 3264514f5e3Sopenharmony_ci FrameIterator it(currentFrame, thread); 3274514f5e3Sopenharmony_ci if (!beforeCallNapi) { 3284514f5e3Sopenharmony_ci it.Advance<GCVisitedFlag::IGNORED>(); 3294514f5e3Sopenharmony_ci } 3304514f5e3Sopenharmony_ci for (; !it.Done(); it.Advance<GCVisitedFlag::IGNORED>()) { 3314514f5e3Sopenharmony_ci auto method = it.CheckAndGetMethod(); 3324514f5e3Sopenharmony_ci if (method == nullptr || !JSTaggedValue(method).IsMethod()) { 3334514f5e3Sopenharmony_ci continue; 3344514f5e3Sopenharmony_ci } 3354514f5e3Sopenharmony_ci 3364514f5e3Sopenharmony_ci bool isNative = method->IsNativeWithCallField(); 3374514f5e3Sopenharmony_ci struct MethodKey methodKey; 3384514f5e3Sopenharmony_ci methodKey.deoptType = method->GetDeoptType(); 3394514f5e3Sopenharmony_ci if (topFrame) { 3404514f5e3Sopenharmony_ci if (beforeCallNapi) { 3414514f5e3Sopenharmony_ci methodKey.state = RunningState::NAPI; 3424514f5e3Sopenharmony_ci } else { 3434514f5e3Sopenharmony_ci methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, true, enableVMTag_); 3444514f5e3Sopenharmony_ci } 3454514f5e3Sopenharmony_ci topFrame = false; 3464514f5e3Sopenharmony_ci } else { 3474514f5e3Sopenharmony_ci methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, false, enableVMTag_); 3484514f5e3Sopenharmony_ci } 3494514f5e3Sopenharmony_ci if (isNative) { 3504514f5e3Sopenharmony_ci JsStackGetter::GetCallLineNumber(it, methodKey.lineNumber); 3514514f5e3Sopenharmony_ci } 3524514f5e3Sopenharmony_ci void *methodIdentifier = JsStackGetter::GetMethodIdentifier(method, it); 3534514f5e3Sopenharmony_ci if (methodIdentifier == nullptr) { 3544514f5e3Sopenharmony_ci continue; 3554514f5e3Sopenharmony_ci } 3564514f5e3Sopenharmony_ci methodKey.methodIdentifier = methodIdentifier; 3574514f5e3Sopenharmony_ci if (stackInfo.count(methodKey) == 0) { 3584514f5e3Sopenharmony_ci struct FrameInfoTemp codeEntry; 3594514f5e3Sopenharmony_ci if (UNLIKELY(!JsStackGetter::ParseMethodInfo(methodKey, it, vm_, codeEntry, true))) { 3604514f5e3Sopenharmony_ci continue; 3614514f5e3Sopenharmony_ci } 3624514f5e3Sopenharmony_ci if (UNLIKELY(!generator_->PushNapiStackInfo(codeEntry))) { 3634514f5e3Sopenharmony_ci return false; 3644514f5e3Sopenharmony_ci } 3654514f5e3Sopenharmony_ci } 3664514f5e3Sopenharmony_ci if (UNLIKELY(!generator_->PushNapiFrameStack(methodKey))) { 3674514f5e3Sopenharmony_ci return false; 3684514f5e3Sopenharmony_ci } 3694514f5e3Sopenharmony_ci } 3704514f5e3Sopenharmony_ci generator_->PostNapiFrame(); 3714514f5e3Sopenharmony_ci return true; 3724514f5e3Sopenharmony_ci} 3734514f5e3Sopenharmony_ci 3744514f5e3Sopenharmony_civoid CpuProfiler::GetStackSignalHandler(int signal, [[maybe_unused]] siginfo_t *siginfo, void *context) 3754514f5e3Sopenharmony_ci{ 3764514f5e3Sopenharmony_ci if (signal != SIGPROF) { 3774514f5e3Sopenharmony_ci return; 3784514f5e3Sopenharmony_ci } 3794514f5e3Sopenharmony_ci CpuProfiler *profiler = nullptr; 3804514f5e3Sopenharmony_ci JSThread *thread = nullptr; 3814514f5e3Sopenharmony_ci { 3824514f5e3Sopenharmony_ci LockHolder lock(synchronizationMutex_); 3834514f5e3Sopenharmony_ci // If no task running in this thread, we get the id of the last task that ran in this thread 3844514f5e3Sopenharmony_ci pthread_t tid = static_cast<pthread_t>(GetThreadIdOrCachedTaskId()); 3854514f5e3Sopenharmony_ci const EcmaVM *vm = profilerMap_[tid].vm_; 3864514f5e3Sopenharmony_ci if (vm == nullptr) { 3874514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler GetStackSignalHandler vm is nullptr"; 3884514f5e3Sopenharmony_ci return; 3894514f5e3Sopenharmony_ci } 3904514f5e3Sopenharmony_ci profiler = vm->GetProfiler(); 3914514f5e3Sopenharmony_ci thread = vm->GetAssociatedJSThread(); 3924514f5e3Sopenharmony_ci if (profiler == nullptr) { 3934514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler GetStackSignalHandler profiler is nullptr"; 3944514f5e3Sopenharmony_ci return; 3954514f5e3Sopenharmony_ci } 3964514f5e3Sopenharmony_ci } 3974514f5e3Sopenharmony_ci [[maybe_unused]] SignalStateScope scope(thread->GetEcmaVM()->GetJsDebuggerManager()); 3984514f5e3Sopenharmony_ci 3994514f5e3Sopenharmony_ci if (profiler->GetBuildNapiStack() || thread->GetGcState()) { 4004514f5e3Sopenharmony_ci if (profiler->generator_->SemPost(0) != 0) { 4014514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[0] post failed"; 4024514f5e3Sopenharmony_ci } 4034514f5e3Sopenharmony_ci return; 4044514f5e3Sopenharmony_ci } 4054514f5e3Sopenharmony_ci 4064514f5e3Sopenharmony_ci uint64_t pc = 0; 4074514f5e3Sopenharmony_ci if (thread->IsAsmInterpreter()) { 4084514f5e3Sopenharmony_ci // If the attempt fails, the callback will be terminated directly to avoid the reentrancy deadlock, 4094514f5e3Sopenharmony_ci // and a sampling will be abandoned. Failures are rare, so the impact on the overall sampling results 4104514f5e3Sopenharmony_ci // is very limited. 4114514f5e3Sopenharmony_ci if (!thread->GetEcmaVM()->GetAOTFileManager()->TryReadLock()) { 4124514f5e3Sopenharmony_ci if (profiler->generator_->SemPost(0) != 0) { 4134514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[0] post failed"; 4144514f5e3Sopenharmony_ci } 4154514f5e3Sopenharmony_ci return; 4164514f5e3Sopenharmony_ci } 4174514f5e3Sopenharmony_ci pc = GetPcFromContext(context); 4184514f5e3Sopenharmony_ci } 4194514f5e3Sopenharmony_ci if (thread->IsAsmInterpreter() && profiler->IsAddrAtStubOrAot(pc) && 4204514f5e3Sopenharmony_ci !profiler->IsEntryFrameHeaderOrTail(thread, pc)) { 4214514f5e3Sopenharmony_ci [[maybe_unused]] ucontext_t *ucontext = reinterpret_cast<ucontext_t*>(context); 4224514f5e3Sopenharmony_ci [[maybe_unused]] mcontext_t &mcontext = ucontext->uc_mcontext; 4234514f5e3Sopenharmony_ci [[maybe_unused]] void *fp = nullptr; 4244514f5e3Sopenharmony_ci [[maybe_unused]] void *sp = nullptr; 4254514f5e3Sopenharmony_ci#if defined(PANDA_TARGET_AMD64) 4264514f5e3Sopenharmony_ci fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]); 4274514f5e3Sopenharmony_ci sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]); 4284514f5e3Sopenharmony_ci#elif defined(PANDA_TARGET_ARM64) 4294514f5e3Sopenharmony_ci fp = reinterpret_cast<void*>(mcontext.regs[29]); // FP is an alias for x29. 4304514f5e3Sopenharmony_ci sp = reinterpret_cast<void*>(mcontext.sp); 4314514f5e3Sopenharmony_ci#else 4324514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "AsmInterpreter does not currently support other platforms, please run on x64 and arm64"; 4334514f5e3Sopenharmony_ci return; 4344514f5e3Sopenharmony_ci#endif 4354514f5e3Sopenharmony_ci if (reinterpret_cast<uint64_t*>(sp) > reinterpret_cast<uint64_t*>(fp)) { 4364514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sp > fp, stack frame exception"; 4374514f5e3Sopenharmony_ci if (profiler->generator_->SemPost(0) != 0) { 4384514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[0] post failed"; 4394514f5e3Sopenharmony_ci } 4404514f5e3Sopenharmony_ci return; 4414514f5e3Sopenharmony_ci } 4424514f5e3Sopenharmony_ci if (JsStackGetter::CheckFrameType(thread, reinterpret_cast<JSTaggedType *>(fp))) { 4434514f5e3Sopenharmony_ci FrameIterator it(reinterpret_cast<JSTaggedType *>(fp), thread); 4444514f5e3Sopenharmony_ci profiler->GetStack(it); 4454514f5e3Sopenharmony_ci } 4464514f5e3Sopenharmony_ci } else if (thread->IsAsmInterpreter()) { 4474514f5e3Sopenharmony_ci if (thread->GetLastLeaveFrame() != nullptr) { 4484514f5e3Sopenharmony_ci JSTaggedType *leaveFrame = const_cast<JSTaggedType *>(thread->GetLastLeaveFrame()); 4494514f5e3Sopenharmony_ci if (JsStackGetter::CheckFrameType(thread, leaveFrame)) { 4504514f5e3Sopenharmony_ci FrameIterator it(leaveFrame, thread); 4514514f5e3Sopenharmony_ci profiler->GetStack(it); 4524514f5e3Sopenharmony_ci } 4534514f5e3Sopenharmony_ci } 4544514f5e3Sopenharmony_ci } else { 4554514f5e3Sopenharmony_ci if (thread->GetCurrentFrame() != nullptr) { 4564514f5e3Sopenharmony_ci if (JsStackGetter::CheckFrameType(thread, const_cast<JSTaggedType *>(thread->GetCurrentFrame()))) { 4574514f5e3Sopenharmony_ci FrameHandler frameHandler(thread); 4584514f5e3Sopenharmony_ci FrameIterator it(frameHandler.GetSp(), thread); 4594514f5e3Sopenharmony_ci profiler->GetStack(it); 4604514f5e3Sopenharmony_ci } 4614514f5e3Sopenharmony_ci } 4624514f5e3Sopenharmony_ci } 4634514f5e3Sopenharmony_ci if (profiler->generator_->SemPost(0) != 0) { 4644514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "sem_[0] post failed"; 4654514f5e3Sopenharmony_ci return; 4664514f5e3Sopenharmony_ci } 4674514f5e3Sopenharmony_ci} 4684514f5e3Sopenharmony_ci 4694514f5e3Sopenharmony_cibool CpuProfiler::InHeaderOrTail(uint64_t pc, uint64_t entryBegin, uint64_t entryDuration, uint64_t headerSize, 4704514f5e3Sopenharmony_ci uint64_t tailSize) const 4714514f5e3Sopenharmony_ci{ 4724514f5e3Sopenharmony_ci uintptr_t entryEnd = entryBegin + entryDuration; 4734514f5e3Sopenharmony_ci if (pc >= entryBegin && pc <= (entryBegin + headerSize)) { 4744514f5e3Sopenharmony_ci return true; 4754514f5e3Sopenharmony_ci } 4764514f5e3Sopenharmony_ci if (pc <= entryEnd && pc >= (entryEnd - tailSize)) { 4774514f5e3Sopenharmony_ci return true; 4784514f5e3Sopenharmony_ci } 4794514f5e3Sopenharmony_ci return false; 4804514f5e3Sopenharmony_ci} 4814514f5e3Sopenharmony_ci 4824514f5e3Sopenharmony_cibool CpuProfiler::IsEntryFrameHeaderOrTail(JSThread *thread, uint64_t pc) const 4834514f5e3Sopenharmony_ci{ 4844514f5e3Sopenharmony_ci uint64_t headerSize = 0; 4854514f5e3Sopenharmony_ci uint64_t tailSize = 0; 4864514f5e3Sopenharmony_ci uint64_t entryDuration = 0; 4874514f5e3Sopenharmony_ci Assembler::GetFrameCompletionPos(headerSize, tailSize, entryDuration); 4884514f5e3Sopenharmony_ci uintptr_t entryBegin = thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_AsmInterpreterEntry); 4894514f5e3Sopenharmony_ci bool inAsmInterpreterEntry = InHeaderOrTail(pc, entryBegin, entryDuration, headerSize, tailSize); 4904514f5e3Sopenharmony_ci entryBegin = thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_GeneratorReEnterAsmInterp); 4914514f5e3Sopenharmony_ci bool inGeneratorReEnterAsmInterp = InHeaderOrTail(pc, entryBegin, entryDuration, headerSize, tailSize); 4924514f5e3Sopenharmony_ci return (inAsmInterpreterEntry || inGeneratorReEnterAsmInterp); 4934514f5e3Sopenharmony_ci} 4944514f5e3Sopenharmony_ci 4954514f5e3Sopenharmony_ciuint64_t CpuProfiler::GetPcFromContext(void *context) 4964514f5e3Sopenharmony_ci{ 4974514f5e3Sopenharmony_ci [[maybe_unused]] ucontext_t *ucontext = reinterpret_cast<ucontext_t*>(context); 4984514f5e3Sopenharmony_ci [[maybe_unused]] mcontext_t &mcontext = ucontext->uc_mcontext; 4994514f5e3Sopenharmony_ci uint64_t pc = 0; 5004514f5e3Sopenharmony_ci#if defined(PANDA_TARGET_AMD64) 5014514f5e3Sopenharmony_ci pc = static_cast<uint64_t>(mcontext.gregs[REG_RIP]); 5024514f5e3Sopenharmony_ci#elif defined(PANDA_TARGET_ARM64) 5034514f5e3Sopenharmony_ci pc = static_cast<uint64_t>(mcontext.pc); 5044514f5e3Sopenharmony_ci#else 5054514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "AsmInterpreter does not currently support other platforms, please run on x64 and arm64"; 5064514f5e3Sopenharmony_ci pc = 0; 5074514f5e3Sopenharmony_ci#endif 5084514f5e3Sopenharmony_ci return pc; 5094514f5e3Sopenharmony_ci} 5104514f5e3Sopenharmony_ci 5114514f5e3Sopenharmony_cibool CpuProfiler::IsAddrAtStubOrAot(uint64_t pc) const 5124514f5e3Sopenharmony_ci{ 5134514f5e3Sopenharmony_ci AOTFileManager *loader = vm_->GetAOTFileManager(); 5144514f5e3Sopenharmony_ci return loader->InsideStub(pc) || loader->InsideAOT(pc); 5154514f5e3Sopenharmony_ci} 5164514f5e3Sopenharmony_ci 5174514f5e3Sopenharmony_cibool CpuProfiler::CheckFileName(const std::string &fileName, std::string &absoluteFilePath) const 5184514f5e3Sopenharmony_ci{ 5194514f5e3Sopenharmony_ci if (fileName.empty()) { 5204514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, fileName is empty"; 5214514f5e3Sopenharmony_ci return false; 5224514f5e3Sopenharmony_ci } 5234514f5e3Sopenharmony_ci 5244514f5e3Sopenharmony_ci if (fileName.size() > PATH_MAX) { 5254514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, fileName exceed PATH_MAX"; 5264514f5e3Sopenharmony_ci return false; 5274514f5e3Sopenharmony_ci } 5284514f5e3Sopenharmony_ci 5294514f5e3Sopenharmony_ci CVector<char> resolvedPath(PATH_MAX); 5304514f5e3Sopenharmony_ci auto result = realpath(fileName.c_str(), resolvedPath.data()); 5314514f5e3Sopenharmony_ci if (result == nullptr) { 5324514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, realpath fail, errno = " << errno; 5334514f5e3Sopenharmony_ci return false; 5344514f5e3Sopenharmony_ci } 5354514f5e3Sopenharmony_ci std::ofstream file(resolvedPath.data()); 5364514f5e3Sopenharmony_ci if (!file.good()) { 5374514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, file is not good, errno = " << errno; 5384514f5e3Sopenharmony_ci return false; 5394514f5e3Sopenharmony_ci } 5404514f5e3Sopenharmony_ci file.close(); 5414514f5e3Sopenharmony_ci absoluteFilePath = resolvedPath.data(); 5424514f5e3Sopenharmony_ci return true; 5434514f5e3Sopenharmony_ci} 5444514f5e3Sopenharmony_ci 5454514f5e3Sopenharmony_civoid CpuProfiler::SetBuildNapiStack(bool flag) 5464514f5e3Sopenharmony_ci{ 5474514f5e3Sopenharmony_ci isBuildNapiStack_.store(flag); 5484514f5e3Sopenharmony_ci} 5494514f5e3Sopenharmony_ci 5504514f5e3Sopenharmony_cibool CpuProfiler::GetBuildNapiStack() 5514514f5e3Sopenharmony_ci{ 5524514f5e3Sopenharmony_ci return isBuildNapiStack_.load(); 5534514f5e3Sopenharmony_ci} 5544514f5e3Sopenharmony_ci 5554514f5e3Sopenharmony_cibool CpuProfiler::GetOutToFile() 5564514f5e3Sopenharmony_ci{ 5574514f5e3Sopenharmony_ci return outToFile_; 5584514f5e3Sopenharmony_ci} 5594514f5e3Sopenharmony_ci 5604514f5e3Sopenharmony_ciEcmaVM* CpuProfiler::GetVmbyTid(pthread_t tid) 5614514f5e3Sopenharmony_ci{ 5624514f5e3Sopenharmony_ci LockHolder lock(synchronizationMutex_); 5634514f5e3Sopenharmony_ci return const_cast<EcmaVM *>(profilerMap_[tid].vm_); 5644514f5e3Sopenharmony_ci} 5654514f5e3Sopenharmony_ci} // namespace panda::ecmascript 566