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