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