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