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