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