• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
17 
18 
19 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21 
22 #if defined(ENABLE_FFRT_INTERFACES)
23 #include "c/executor_task.h"
24 #endif
25 
26 #if !defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
27     #error "ECMASCRIPT_SUPPORT_CPUPROFILER not defined"
28 #endif
29 
30 namespace panda::ecmascript {
31 Mutex CpuProfiler::synchronizationMutex_;
32 CMap<pthread_t, struct TaskInfo> CpuProfiler::profilerMap_ = CMap<pthread_t, struct TaskInfo>();
CpuProfiler(const EcmaVM * vm,const int interval)33 CpuProfiler::CpuProfiler(const EcmaVM *vm, const int interval) : vm_(vm), interval_(interval)
34 {
35     enableVMTag_ = const_cast<EcmaVM *>(vm)->GetJSOptions().EnableCpuProfilerVMTag();
36     generator_ = new SamplesRecord();
37     generator_->SetEnableVMTag(enableVMTag_);
38     generator_->SetSourceMapTranslateCallback(vm->GetSourceMapTranslateCallback());
39     generator_->NodeInit();
40     if (generator_->SemInit(0, 0, 0) != 0) {
41         LOG_ECMA(ERROR) << "sem_[0] init failed";
42     }
43     if (generator_->SemInit(1, 0, 0) != 0) {
44         LOG_ECMA(ERROR) << "sem_[1] init failed";
45     }
46     if (generator_->SemInit(2, 0, 0) != 0) { // 2: signal 2
47         LOG_ECMA(ERROR) << "sem_[2] init failed";
48     }
49 }
50 
RegisterGetStackSignal()51 bool CpuProfiler::RegisterGetStackSignal()
52 {
53     struct sigaction sa;
54     sa.sa_sigaction = &GetStackSignalHandler;
55     if (sigemptyset(&sa.sa_mask) != 0) {
56         LOG_ECMA(ERROR) << "CpuProfiler::RegisterGetStackSignal, sigemptyset failed, errno = " << errno;
57         return false;
58     }
59     sa.sa_flags = SA_RESTART | SA_SIGINFO;
60     if (sigaction(SIGPROF, &sa, nullptr) != 0) {
61         LOG_ECMA(ERROR) << "CpuProfiler::RegisterGetStackSignal, sigaction failed, errno = " << errno;
62         return false;
63     }
64     return true;
65 }
66 
StartCpuProfilerForInfo()67 bool CpuProfiler::StartCpuProfilerForInfo()
68 {
69     LOG_ECMA(INFO) << "CpuProfiler::StartCpuProfilerForInfo, sampling interval = " << interval_;
70     if (isProfiling_) {
71         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, can not start when CpuProfiler is Profiling";
72         return false;
73     }
74     if (!RegisterGetStackSignal()) {
75         return false;
76     }
77     // when the ffrt is enabled for the thread, the tid_ will be task id
78     tid_ = static_cast<pthread_t>(JSThread::GetCurrentThreadId());
79     void *taskHandle = nullptr;
80     // when the ffrt is enabled for the thread,
81     // we record the task handle, which can be used to obtain the running thread id in the task
82 #if defined(ENABLE_FFRT_INTERFACES)
83     taskHandle = ffrt_get_cur_task();
84     TaskInfo taskInfo { vm_, taskHandle };
85 #else
86     TaskInfo taskInfo { vm_, nullptr };
87 #endif // defined(ENABLE_FFRT_INTERFACES)
88     {
89         LockHolder lock(synchronizationMutex_);
90         profilerMap_[tid_] = taskInfo;
91     }
92 
93     JSPandaFileManager *pandaFileManager = JSPandaFileManager::GetInstance();
94     pandaFileManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
95         pandaFileManager->CpuProfilerGetJSPtExtractor(file.get());
96         return true;
97     });
98 
99     generator_->SetTimeDeltaThreshold(interval_ * THRESHOLD_GROWTH_FACTORY + THRESHOLD_FIXED_INCREMENT);
100     generator_->SetIsStart(true);
101     uint64_t startTime = SamplingProcessor::GetMicrosecondsTimeStamp();
102     generator_->SetThreadStartTime(startTime);
103     params_ = new RunParams(generator_, static_cast<uint32_t>(interval_), pthread_self(), taskHandle);
104     if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) {
105         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForInfo, pthread_create failed, errno = " << errno;
106         return false;
107     }
108     isProfiling_ = true;
109     vm_->GetJSThread()->SetIsProfiling(true);
110     outToFile_ = false;
111     return true;
112 }
113 
StartCpuProfilerForFile(const std::string & fileName)114 bool CpuProfiler::StartCpuProfilerForFile(const std::string &fileName)
115 {
116     LOG_ECMA(INFO) << "CpuProfiler::StartCpuProfilerForFile, sampling interval = " << interval_;
117     if (isProfiling_) {
118         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, can not start when CpuProfiler is Profiling";
119         return false;
120     }
121     std::string absoluteFilePath("");
122     if (!CheckFileName(fileName, absoluteFilePath)) {
123         return false;
124     }
125     fileName_ = absoluteFilePath;
126     generator_->SetFileName(fileName_);
127     generator_->fileHandle_.open(fileName_.c_str());
128     if (generator_->fileHandle_.fail()) {
129         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, fileHandle_ open failed";
130         return false;
131     }
132     if (!RegisterGetStackSignal()) {
133         return false;
134     }
135     // when the ffrt is enabled for the thread, the tid_ will be task id
136     tid_ = static_cast<pthread_t>(JSThread::GetCurrentThreadId());
137     void *taskHandle = nullptr;
138     // when the ffrt is enabled for the thread,
139     // we record the task handle, which can be used to obtain the running thread id in the task
140 #if defined(ENABLE_FFRT_INTERFACES)
141     taskHandle = ffrt_get_cur_task();
142     TaskInfo taskInfo { vm_, taskHandle };
143 #else
144     TaskInfo taskInfo { vm_, nullptr };
145 #endif // defined(ENABLE_FFRT_INTERFACES)
146     {
147         LockHolder lock(synchronizationMutex_);
148         profilerMap_[tid_] = taskInfo;
149     }
150 
151     JSPandaFileManager *pandaFileManager = JSPandaFileManager::GetInstance();
152     pandaFileManager->EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
153         pandaFileManager->CpuProfilerGetJSPtExtractor(file.get());
154         return true;
155     });
156 
157     generator_->SetTimeDeltaThreshold(interval_ * THRESHOLD_GROWTH_FACTORY + THRESHOLD_FIXED_INCREMENT);
158     generator_->SetIsStart(true);
159     uint64_t startTime = SamplingProcessor::GetMicrosecondsTimeStamp();
160     generator_->SetThreadStartTime(startTime);
161     params_ = new RunParams(generator_, static_cast<uint32_t>(interval_), pthread_self(), taskHandle);
162     if (pthread_create(&tid_, nullptr, SamplingProcessor::Run, params_) != 0) {
163         LOG_ECMA(ERROR) << "CpuProfiler::StartCpuProfilerForFile, pthread_create failed, errno = " << errno;
164         return false;
165     }
166     isProfiling_ = true;
167     vm_->GetJSThread()->SetIsProfiling(true);
168     outToFile_ = true;
169     return true;
170 }
171 
StopCpuProfilerForInfo(std::unique_ptr<struct ProfileInfo> & profileInfo)172 bool CpuProfiler::StopCpuProfilerForInfo(std::unique_ptr<struct ProfileInfo> &profileInfo)
173 {
174     LOG_ECMA(INFO) << "CpuProfiler::StopCpuProfilerForInfo enter";
175     if (!isProfiling_) {
176         LOG_ECMA(WARN) << "CpuProfiler::StopCpuProfilerForInfo, not isProfiling_";
177         return true;
178     }
179     if (outToFile_) {
180         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, is outToFile_";
181         return false;
182     }
183     generator_->SetIsStart(false);
184     if (generator_->SemPost(0) != 0) {
185         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, sem_[0] post failed, errno = " << errno;
186         return false;
187     }
188     if (generator_->SemWait(1) != 0) {
189         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForInfo, sem_[1] wait failed, errno = " << errno;
190         return false;
191     }
192     isProfiling_ = false;
193     vm_->GetJSThread()->SetIsProfiling(false);
194     profileInfo = generator_->GetProfileInfo();
195     return true;
196 }
197 
SetCpuSamplingInterval(int interval)198 void CpuProfiler::SetCpuSamplingInterval(int interval)
199 {
200     interval_ = static_cast<uint32_t>(interval);
201 }
202 
StopCpuProfilerForFile()203 bool CpuProfiler::StopCpuProfilerForFile()
204 {
205     LOG_ECMA(INFO) << "CpuProfiler::StopCpuProfilerForFile enter";
206     if (!isProfiling_) {
207         LOG_ECMA(WARN) << "CpuProfiler::StopCpuProfilerForFile, not isProfiling_";
208         return true;
209     }
210     if (!outToFile_) {
211         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, not outToFile_";
212         return false;
213     }
214     generator_->SetIsStart(false);
215     if (generator_->SemPost(0) != 0) {
216         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, sem_[0] post failed, errno = " << errno;
217         return false;
218     }
219     if (generator_->SemWait(1) != 0) {
220         LOG_ECMA(ERROR) << "CpuProfiler::StopCpuProfilerForFile, sem_[1] wait failed, errno = " << errno;
221         return false;
222     }
223     isProfiling_ = false;
224     vm_->GetJSThread()->SetIsProfiling(false);
225     generator_->StringifySampleData();
226     std::string fileData = generator_->GetSampleData();
227     generator_->fileHandle_ << fileData;
228     return true;
229 }
230 
~CpuProfiler()231 CpuProfiler::~CpuProfiler()
232 {
233     if (generator_->SemDestroy(0) != 0) {
234         LOG_ECMA(ERROR) << "sem_[0] destroy failed";
235     }
236     if (generator_->SemDestroy(1) != 0) {
237         LOG_ECMA(ERROR) << "sem_[1] destroy failed";
238     }
239     if (generator_->SemDestroy(2) != 0) { // 2: signal 2
240         LOG_ECMA(ERROR) << "sem_[2] destroy failed";
241     }
242     if (generator_ != nullptr) {
243         delete generator_;
244         generator_ = nullptr;
245     }
246     if (params_ != nullptr) {
247         delete params_;
248         params_ = nullptr;
249     }
250 }
251 
GetStack(FrameIterator & it)252 void CpuProfiler::GetStack(FrameIterator &it)
253 {
254     const CMap<struct MethodKey, struct FrameInfo> &stackInfo = generator_->GetStackInfo();
255     bool topFrame = true;
256     generator_->ResetFrameLength();
257     for (; !it.Done(); it.Advance<>()) {
258         auto method = it.CheckAndGetMethod();
259         if (method == nullptr || !JSTaggedValue(method).IsMethod()) {
260             continue;
261         }
262         bool isNative = method->IsNativeWithCallField();
263         struct MethodKey methodKey;
264         methodKey.deoptType = method->GetDeoptType();
265         if (topFrame) {
266             methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, true, enableVMTag_);
267             topFrame = false;
268         } else {
269             methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, false, enableVMTag_);
270         }
271         if (isNative) {
272             JsStackGetter::GetCallLineNumber(it, methodKey.lineNumber);
273         }
274         void *methodIdentifier = JsStackGetter::GetMethodIdentifier(method, it);
275         if (methodIdentifier == nullptr) {
276             continue;
277         }
278         methodKey.methodIdentifier = methodIdentifier;
279         if (stackInfo.count(methodKey) == 0) {
280             struct FrameInfoTemp codeEntry;
281             if (UNLIKELY(!JsStackGetter::ParseMethodInfo(methodKey, it, vm_, codeEntry, true))) {
282                 continue;
283             }
284             if (UNLIKELY(!generator_->PushStackInfo(codeEntry))) {
285                 return;
286             }
287         }
288         if (UNLIKELY(!generator_->PushFrameStack(methodKey))) {
289             return;
290         }
291     }
292     generator_->PostFrame();
293 }
294 
GetStackBeforeCallNapi(JSThread * thread)295 bool CpuProfiler::GetStackBeforeCallNapi(JSThread *thread)
296 {
297     uint64_t tempTimeStamp = SamplingProcessor::GetMicrosecondsTimeStamp();
298     if (tempTimeStamp - beforeCallNapiTimeStamp_ < interval_) {
299         return false;
300     }
301 
302     if (GetStackCallNapi(thread, true)) {
303         beforeCallNapiTimeStamp_ = tempTimeStamp;
304         return true;
305     }
306     return false;
307 }
308 
GetStackAfterCallNapi(JSThread * thread)309 void CpuProfiler::GetStackAfterCallNapi(JSThread *thread)
310 {
311     GetStackCallNapi(thread, false);
312 }
313 
GetStackCallNapi(JSThread * thread,bool beforeCallNapi)314 bool CpuProfiler::GetStackCallNapi(JSThread *thread, bool beforeCallNapi)
315 {
316     [[maybe_unused]] CallNapiScope scope(this);
317     const CMap<struct MethodKey, struct FrameInfo> &stackInfo = generator_->GetStackInfo();
318     generator_->ClearNapiStack();
319     bool topFrame = true;
320     auto currentFrame = const_cast<JSTaggedType *>(thread->GetCurrentFrame());
321     FrameIterator it(currentFrame, thread);
322     if (!beforeCallNapi) {
323         it.Advance<GCVisitedFlag::IGNORED>();
324     }
325     for (; !it.Done(); it.Advance<GCVisitedFlag::IGNORED>()) {
326         auto method = it.CheckAndGetMethod();
327         if (method == nullptr || !JSTaggedValue(method).IsMethod()) {
328             continue;
329         }
330 
331         bool isNative = method->IsNativeWithCallField();
332         struct MethodKey methodKey;
333         methodKey.deoptType = method->GetDeoptType();
334         if (topFrame) {
335             if (beforeCallNapi) {
336                 methodKey.state = RunningState::NAPI;
337             } else {
338                 methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, true, enableVMTag_);
339             }
340             topFrame = false;
341         } else {
342             methodKey.state = JsStackGetter::GetRunningState(it, vm_, isNative, false, enableVMTag_);
343         }
344         if (isNative) {
345             JsStackGetter::GetCallLineNumber(it, methodKey.lineNumber);
346         }
347         void *methodIdentifier = JsStackGetter::GetMethodIdentifier(method, it);
348         if (methodIdentifier == nullptr) {
349             continue;
350         }
351         methodKey.methodIdentifier = methodIdentifier;
352         if (stackInfo.count(methodKey) == 0) {
353             struct FrameInfoTemp codeEntry;
354             if (UNLIKELY(!JsStackGetter::ParseMethodInfo(methodKey, it, vm_, codeEntry, true))) {
355                 continue;
356             }
357             if (UNLIKELY(!generator_->PushNapiStackInfo(codeEntry))) {
358                 return false;
359             }
360         }
361         if (UNLIKELY(!generator_->PushNapiFrameStack(methodKey))) {
362             return false;
363         }
364     }
365     generator_->PostNapiFrame();
366     return true;
367 }
368 
GetStackSignalHandler(int signal,siginfo_t * siginfo,void * context)369 void CpuProfiler::GetStackSignalHandler(int signal, [[maybe_unused]] siginfo_t *siginfo, void *context)
370 {
371     if (signal != SIGPROF) {
372         return;
373     }
374     CpuProfiler *profiler = nullptr;
375     JSThread *thread = nullptr;
376     {
377         LockHolder lock(synchronizationMutex_);
378         // If no task running in this thread, we get the id of the last task that ran in this thread
379         pthread_t tid = static_cast<pthread_t>(GetThreadIdOrCachedTaskId());
380         const EcmaVM *vm = profilerMap_[tid].vm_;
381         if (vm == nullptr) {
382             LOG_ECMA(ERROR) << "CpuProfiler GetStackSignalHandler vm is nullptr";
383             return;
384         }
385         profiler = vm->GetProfiler();
386         thread = vm->GetAssociatedJSThread();
387         if (profiler == nullptr) {
388             LOG_ECMA(ERROR) << "CpuProfiler GetStackSignalHandler profiler is nullptr";
389             return;
390         }
391     }
392     [[maybe_unused]] SignalStateScope scope(thread->GetEcmaVM()->GetJsDebuggerManager());
393 
394     if (profiler->GetBuildNapiStack() || thread->GetGcState()) {
395         if (profiler->generator_->SemPost(0) != 0) {
396             LOG_ECMA(ERROR) << "sem_[0] post failed";
397         }
398         return;
399     }
400 
401     uint64_t pc = 0;
402     if (thread->IsAsmInterpreter()) {
403         // If the attempt fails, the callback will be terminated directly to avoid the reentrancy deadlock,
404         // and a sampling will be abandoned. Failures are rare, so the impact on the overall sampling results
405         // is very limited.
406         if (!thread->GetEcmaVM()->GetAOTFileManager()->TryReadLock()) {
407             if (profiler->generator_->SemPost(0) != 0) {
408                 LOG_ECMA(ERROR) << "sem_[0] post failed";
409             }
410             return;
411         }
412         pc = GetPcFromContext(context);
413     }
414     if (thread->IsAsmInterpreter() && profiler->IsAddrAtStubOrAot(pc) &&
415         !profiler->IsEntryFrameHeaderOrTail(thread, pc)) {
416         [[maybe_unused]] ucontext_t *ucontext = reinterpret_cast<ucontext_t*>(context);
417         [[maybe_unused]] mcontext_t &mcontext = ucontext->uc_mcontext;
418         [[maybe_unused]] void *fp = nullptr;
419         [[maybe_unused]] void *sp = nullptr;
420 #if defined(PANDA_TARGET_AMD64)
421         fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]);
422         sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]);
423 #elif defined(PANDA_TARGET_ARM64)
424         fp = reinterpret_cast<void*>(mcontext.regs[29]); // FP is an alias for x29.
425         sp = reinterpret_cast<void*>(mcontext.sp);
426 #else
427         LOG_FULL(FATAL) << "AsmInterpreter does not currently support other platforms, please run on x64 and arm64";
428         return;
429 #endif
430         if (reinterpret_cast<uint64_t*>(sp) > reinterpret_cast<uint64_t*>(fp)) {
431             LOG_ECMA(ERROR) << "sp > fp, stack frame exception";
432             if (profiler->generator_->SemPost(0) != 0) {
433                 LOG_ECMA(ERROR) << "sem_[0] post failed";
434             }
435             return;
436         }
437         if (JsStackGetter::CheckFrameType(thread, reinterpret_cast<JSTaggedType *>(fp))) {
438             FrameIterator it(reinterpret_cast<JSTaggedType *>(fp), thread);
439             profiler->GetStack(it);
440         }
441     } else if (thread->IsAsmInterpreter()) {
442         if (thread->GetLastLeaveFrame() != nullptr) {
443             JSTaggedType *leaveFrame = const_cast<JSTaggedType *>(thread->GetLastLeaveFrame());
444             if (JsStackGetter::CheckFrameType(thread, leaveFrame)) {
445                 FrameIterator it(leaveFrame, thread);
446                 profiler->GetStack(it);
447             }
448         }
449     } else {
450         if (thread->GetCurrentFrame() != nullptr) {
451             if (JsStackGetter::CheckFrameType(thread, const_cast<JSTaggedType *>(thread->GetCurrentFrame()))) {
452                 FrameHandler frameHandler(thread);
453                 FrameIterator it(frameHandler.GetSp(), thread);
454                 profiler->GetStack(it);
455             }
456         }
457     }
458     if (profiler->generator_->SemPost(0) != 0) {
459         LOG_ECMA(ERROR) << "sem_[0] post failed";
460         return;
461     }
462 }
463 
InHeaderOrTail(uint64_t pc,uint64_t entryBegin,uint64_t entryDuration,uint64_t headerSize,uint64_t tailSize) const464 bool CpuProfiler::InHeaderOrTail(uint64_t pc, uint64_t entryBegin, uint64_t entryDuration, uint64_t headerSize,
465                                  uint64_t tailSize) const
466 {
467     uintptr_t entryEnd = entryBegin + entryDuration;
468     if (pc >= entryBegin && pc <= (entryBegin + headerSize)) {
469         return true;
470     }
471     if (pc <= entryEnd && pc >= (entryEnd - tailSize)) {
472         return true;
473     }
474     return false;
475 }
476 
IsEntryFrameHeaderOrTail(JSThread * thread,uint64_t pc) const477 bool CpuProfiler::IsEntryFrameHeaderOrTail(JSThread *thread, uint64_t pc) const
478 {
479     uint64_t headerSize = 0;
480     uint64_t tailSize = 0;
481     uint64_t entryDuration = 0;
482     Assembler::GetFrameCompletionPos(headerSize, tailSize, entryDuration);
483     uintptr_t entryBegin = thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_AsmInterpreterEntry);
484     bool inAsmInterpreterEntry = InHeaderOrTail(pc, entryBegin, entryDuration, headerSize, tailSize);
485     entryBegin = thread->GetRTInterface(kungfu::RuntimeStubCSigns::ID_GeneratorReEnterAsmInterp);
486     bool inGeneratorReEnterAsmInterp = InHeaderOrTail(pc, entryBegin, entryDuration, headerSize, tailSize);
487     return (inAsmInterpreterEntry || inGeneratorReEnterAsmInterp);
488 }
489 
GetPcFromContext(void * context)490 uint64_t CpuProfiler::GetPcFromContext(void *context)
491 {
492     [[maybe_unused]] ucontext_t *ucontext = reinterpret_cast<ucontext_t*>(context);
493     [[maybe_unused]] mcontext_t &mcontext = ucontext->uc_mcontext;
494     uint64_t pc = 0;
495 #if defined(PANDA_TARGET_AMD64)
496     pc = static_cast<uint64_t>(mcontext.gregs[REG_RIP]);
497 #elif defined(PANDA_TARGET_ARM64)
498     pc = static_cast<uint64_t>(mcontext.pc);
499 #else
500     LOG_FULL(FATAL) << "AsmInterpreter does not currently support other platforms, please run on x64 and arm64";
501     pc = 0;
502 #endif
503     return pc;
504 }
505 
IsAddrAtStubOrAot(uint64_t pc) const506 bool CpuProfiler::IsAddrAtStubOrAot(uint64_t pc) const
507 {
508     AOTFileManager *loader = vm_->GetAOTFileManager();
509     return loader->InsideStub(pc) || loader->InsideAOT(pc);
510 }
511 
CheckFileName(const std::string & fileName,std::string & absoluteFilePath) const512 bool CpuProfiler::CheckFileName(const std::string &fileName, std::string &absoluteFilePath) const
513 {
514     if (fileName.empty()) {
515         LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, fileName is empty";
516         return false;
517     }
518 
519     if (fileName.size() > PATH_MAX) {
520         LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, fileName exceed PATH_MAX";
521         return false;
522     }
523 
524     CVector<char> resolvedPath(PATH_MAX);
525     auto result = realpath(fileName.c_str(), resolvedPath.data());
526     if (result == nullptr) {
527         LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, realpath fail, errno = " << errno;
528         return false;
529     }
530     std::ofstream file(resolvedPath.data());
531     if (!file.good()) {
532         LOG_ECMA(ERROR) << "CpuProfiler::CheckFileName, file is not good, errno = " << errno;
533         return false;
534     }
535     file.close();
536     absoluteFilePath = resolvedPath.data();
537     return true;
538 }
539 
SetBuildNapiStack(bool flag)540 void CpuProfiler::SetBuildNapiStack(bool flag)
541 {
542     isBuildNapiStack_.store(flag);
543 }
544 
GetBuildNapiStack()545 bool CpuProfiler::GetBuildNapiStack()
546 {
547     return isBuildNapiStack_.load();
548 }
549 
GetOutToFile()550 bool CpuProfiler::GetOutToFile()
551 {
552     return outToFile_;
553 }
554 
GetVmbyTid(pthread_t tid)555 EcmaVM* CpuProfiler::GetVmbyTid(pthread_t tid)
556 {
557     LockHolder lock(synchronizationMutex_);
558     return const_cast<EcmaVM *>(profilerMap_[tid].vm_);
559 }
560 } // namespace panda::ecmascript
561