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