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 ¤tProcessInfo)
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