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