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/samples_record.h"
17 
18 #include <climits>
19 #include <sys/syscall.h>
20 #include <unistd.h>
21 
22 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
23 #include "ecmascript/dfx/tracing/tracing.h"
24 
25 namespace panda::ecmascript {
26 const std::string JS_PATH = "entry/build/default/cache/default/default@CompileArkTS/esmodule/debug/";
27 
SamplesRecord()28 SamplesRecord::SamplesRecord()
29 {
30     profileInfo_ = std::make_unique<struct ProfileInfo>();
31     profileInfo_->tid = static_cast<uint64_t>(JSThread::GetCurrentThreadId());
32     samplesQueue_ = new SamplesQueue();
33 }
34 
~SamplesRecord()35 SamplesRecord::~SamplesRecord()
36 {
37     if (fileHandle_.is_open()) {
38         fileHandle_.close();
39     }
40     if (samplesQueue_ != nullptr) {
41         delete samplesQueue_;
42         samplesQueue_ = nullptr;
43     }
44 }
45 
NodeInit()46 void SamplesRecord::NodeInit()
47 {
48     struct NodeKey nodeKey;
49     struct CpuProfileNode methodNode;
50 
51     nodeKey.methodKey.methodIdentifier = reinterpret_cast<void *>(INT_MAX - 1);
52     nodeMap_.emplace(nodeKey, nodeMap_.size() + 1);
53     methodNode.parentId = 0;
54     methodNode.codeEntry.functionName = "(root)";
55     methodNode.id = 1;
56     profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
57 
58     nodeKey.methodKey.methodIdentifier = reinterpret_cast<void *>(INT_MAX - 2);  // 2:program node id
59     nodeMap_.emplace(nodeKey, nodeMap_.size() + 1);
60     methodNode.codeEntry.functionName = "(program)";
61     methodNode.id = 2;  // 2:program node id
62     profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
63     profileInfo_->nodes[0].children.push_back(methodNode.id);
64 
65     nodeKey.methodKey.methodIdentifier = reinterpret_cast<void *>(INT_MAX - 3);  // 3:idle node id
66     nodeMap_.emplace(nodeKey, nodeMap_.size() + 1);
67     methodNode.codeEntry.functionName = "(idle)";
68     methodNode.id = 3;  // 3:idle node id
69     profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
70     profileInfo_->nodes[0].children.push_back(methodNode.id);
71 }
72 
AddSample(FrameStackAndInfo *frame)73 void SamplesRecord::AddSample(FrameStackAndInfo *frame)
74 {
75     int frameStackLength = frame->frameStackLength;
76     if (frameStackLength == 0) {
77         AddEmptyStackSample(frame->timeStamp);
78         return;
79     }
80 
81     FrameInfoTempToMap(frame->frameInfoTemps, frame->frameInfoTempsLength);
82 
83     struct NodeKey nodeKey;
84     struct CpuProfileNode methodNode;
85     methodNode.id = 1;
86     for (; frameStackLength >= 1; frameStackLength--) {
87         nodeKey.methodKey = frame->frameStack[frameStackLength - 1];
88         methodNode.parentId = nodeKey.parentId = methodNode.id;
89         auto result = nodeMap_.find(nodeKey);
90         if (result == nodeMap_.end()) {
91             int id = static_cast<int>(nodeMap_.size() + 1);
92             nodeMap_.emplace(nodeKey, id);
93             previousId_ = methodNode.id = id;
94             methodNode.codeEntry = GetMethodInfo(nodeKey.methodKey);
95             profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
96             if (methodNode.parentId > 0 && methodNode.parentId <= profileInfo_->nodeCount) {
97                 profileInfo_->nodes[methodNode.parentId - 1].children.push_back(id);
98             }
99         } else {
100             previousId_ = methodNode.id = result->second;
101         }
102     }
103 
104     int sampleNodeId = previousId_ == 0 ? 1 : methodNode.id;
105     int timeDelta = static_cast<int>(frame->timeStamp -
106         (previousTimeStamp_ == 0 ? profileInfo_->startTime : previousTimeStamp_));
107 
108     // delete abnormal sample
109     if (timeDelta > static_cast<int>(timeDeltaThreshold_) && previousState_ != RunningState::NAPI) {
110         uint32_t size = profileInfo_->samples.size();
111         if (size > 0) {
112             profileInfo_->samples[size - 1] = PROGRAM_NODE_ID;
113         }
114         previousState_ = RunningState::OTHER;
115     }
116     StatisticStateTime(timeDelta, previousState_);
117     previousState_ = nodeKey.methodKey.state;
118     profileInfo_->nodes[sampleNodeId - 1].hitCount++;
119     profileInfo_->samples.push_back(sampleNodeId);
120     profileInfo_->timeDeltas.push_back(timeDelta);
121     previousTimeStamp_ = frame->timeStamp;
122 }
123 
AddEmptyStackSample(uint64_t sampleTimeStamp)124 void SamplesRecord::AddEmptyStackSample(uint64_t sampleTimeStamp)
125 {
126     int timeDelta = static_cast<int>(sampleTimeStamp -
127         (previousTimeStamp_ == 0 ? profileInfo_->startTime : previousTimeStamp_));
128 
129     // delete abnormal sample
130     if (timeDelta > static_cast<int>(timeDeltaThreshold_) && previousState_ != RunningState::NAPI) {
131         uint32_t size = profileInfo_->samples.size();
132         if (size > 0) {
133             profileInfo_->samples[size - 1] = PROGRAM_NODE_ID;
134         }
135         previousState_ = RunningState::OTHER;
136     }
137 
138     StatisticStateTime(timeDelta, previousState_);
139     previousState_ = RunningState::OTHER;
140     profileInfo_->nodes[1].hitCount++;
141     profileInfo_->samples.push_back(PROGRAM_NODE_ID);
142     profileInfo_->timeDeltas.push_back(timeDelta);
143     previousTimeStamp_ = sampleTimeStamp;
144 }
145 
StringifySampleData()146 void SamplesRecord::StringifySampleData()
147 {
148     sampleData_ += "{\"tid\":"
149         + std::to_string(profileInfo_->tid) + ",\"startTime\":"
150         + std::to_string(profileInfo_->startTime) + ",\"endTime\":"
151         + std::to_string(profileInfo_->stopTime) + ",";
152 
153     StringifyStateTimeStatistic();
154     StringifyNodes();
155     StringifySamples();
156 }
157 
StringifyStateTimeStatistic()158 void SamplesRecord::StringifyStateTimeStatistic()
159 {
160     sampleData_ += "\"gcTime\":"
161         + std::to_string(profileInfo_->gcTime) + ",\"cInterpreterTime\":"
162         + std::to_string(profileInfo_->cInterpreterTime) + ",\"asmInterpreterTime\":"
163         + std::to_string(profileInfo_->asmInterpreterTime) + ",\"aotTime\":"
164         + std::to_string(profileInfo_->aotTime) + ",\"asmInterpreterDeoptTime\":"
165         + std::to_string(profileInfo_->asmInterpreterDeoptTime) + ",\"builtinTime\":"
166         + std::to_string(profileInfo_->builtinTime) + ",\"napiTime\":"
167         + std::to_string(profileInfo_->napiTime) + ",\"arkuiEngineTime\":"
168         + std::to_string(profileInfo_->arkuiEngineTime) + ",\"runtimeTime\":"
169         + std::to_string(profileInfo_->runtimeTime) + ",\"jitTime\":"
170         + std::to_string(profileInfo_->jitTime) + ",\"otherTime\":"
171         + std::to_string(profileInfo_->otherTime) + ",";
172 }
173 
StringifyNodes()174 void SamplesRecord::StringifyNodes()
175 {
176     sampleData_ += "\"nodes\":[";
177     size_t nodeCount = static_cast<size_t>(profileInfo_->nodeCount);
178     bool translateCallback = false;
179     if (sourceMapTranslateCallback_ != nullptr) {
180         translateCallback = true;
181     }
182     for (size_t i = 0; i < nodeCount; i++) {
183         struct CpuProfileNode node = profileInfo_->nodes[i];
184         struct FrameInfo codeEntry = node.codeEntry;
185         if (translateCallback) {
186             TranslateUrlPositionBySourceMap(codeEntry);
187         }
188         std::string url = codeEntry.url;
189         replace(url.begin(), url.end(), '\\', '/');
190         sampleData_ += "{\"id\":"
191         + std::to_string(node.id) + ",\"callFrame\":{\"functionName\":\""
192         + codeEntry.functionName + "\",\"moduleName\":\""
193         + codeEntry.moduleName + "\",\"scriptId\":\""
194         + std::to_string(codeEntry.scriptId) + "\",\"url\":\""
195         + url + "\",\"lineNumber\":"
196         + std::to_string(codeEntry.lineNumber) + ",\"columnNumber\":"
197         + std::to_string(codeEntry.columnNumber) + "},\"hitCount\":"
198         + std::to_string(node.hitCount) + ",\"children\":[";
199         CVector<int> children = node.children;
200         size_t childrenCount = children.size();
201         for (size_t j = 0; j < childrenCount; j++) {
202             sampleData_ += std::to_string(children[j]) + ",";
203         }
204         if (childrenCount > 0) {
205             sampleData_.pop_back();
206         }
207         sampleData_ += "]},";
208     }
209     sampleData_.pop_back();
210     sampleData_ += "],";
211 }
212 
StringifySamples()213 void SamplesRecord::StringifySamples()
214 {
215     CVector<int> samples = profileInfo_->samples;
216     CVector<int> timeDeltas = profileInfo_->timeDeltas;
217 
218     size_t samplesCount = samples.size();
219     std::string samplesIdStr = "";
220     std::string timeDeltasStr = "";
221     for (size_t i = 0; i < samplesCount; i++) {
222         samplesIdStr += std::to_string(samples[i]) + ",";
223         timeDeltasStr += std::to_string(timeDeltas[i]) + ",";
224     }
225     samplesIdStr.pop_back();
226     timeDeltasStr.pop_back();
227 
228     sampleData_ += "\"samples\":[" + samplesIdStr + "],\"timeDeltas\":[" + timeDeltasStr + "]}";
229 }
230 
GetMethodNodeCount() const231 int SamplesRecord::GetMethodNodeCount() const
232 {
233     return profileInfo_->nodeCount;
234 }
235 
GetSampleData() const236 std::string SamplesRecord::GetSampleData() const
237 {
238     return sampleData_;
239 }
240 
GetMethodInfo(struct MethodKey &methodKey)241 struct FrameInfo SamplesRecord::GetMethodInfo(struct MethodKey &methodKey)
242 {
243     struct FrameInfo entry;
244     auto iter = stackInfoMap_.find(methodKey);
245     if (iter != stackInfoMap_.end()) {
246         entry = iter->second;
247     }
248     return entry;
249 }
250 
AddRunningState(char *functionName, RunningState state, kungfu::DeoptType type)251 std::string SamplesRecord::AddRunningState(char *functionName, RunningState state, kungfu::DeoptType type)
252 {
253     std::string temp = functionName;
254     switch (state) {
255         case RunningState::AINT_D:
256             temp.append("(AINT-D)");
257             break;
258         case RunningState::GC:
259             temp.append("(GC)");
260             break;
261         case RunningState::CINT:
262             if (enableVMTag_) {
263                 temp.append("(CINT)");
264             }
265             break;
266         case RunningState::AINT:
267             if (enableVMTag_) {
268                 temp.append("(AINT)");
269             }
270             break;
271         case RunningState::AOT:
272             if (enableVMTag_) {
273                 temp.append("(AOT)");
274             }
275             break;
276         case RunningState::BUILTIN:
277             temp.append("(BUILTIN)");
278             break;
279         case RunningState::NAPI:
280             temp.append("(NAPI)");
281             break;
282         case RunningState::ARKUI_ENGINE:
283             temp.append("(ARKUI_ENGINE)");
284             break;
285         case RunningState::RUNTIME:
286             if (enableVMTag_) {
287                 temp.append("(RUNTIME)");
288             }
289             break;
290         case RunningState::JIT:
291             temp.append("(JIT)");
292             break;
293         default:
294             break;
295     }
296     if (state == RunningState::AINT_D && type != kungfu::DeoptType::NONE && enableVMTag_) {
297         std::string typeCheckStr = "(DEOPT:" + Deoptimizier::DisplayItems(type) + ")";
298         temp.append(typeCheckStr);
299     }
300     return temp;
301 }
302 
StatisticStateTime(int timeDelta, RunningState state)303 void SamplesRecord::StatisticStateTime(int timeDelta, RunningState state)
304 {
305     switch (state) {
306         case RunningState::AINT_D: {
307             profileInfo_->asmInterpreterDeoptTime += static_cast<uint64_t>(timeDelta);
308             return;
309         }
310         case RunningState::GC: {
311             profileInfo_->gcTime += static_cast<uint64_t>(timeDelta);
312             return;
313         }
314         case RunningState::CINT: {
315             profileInfo_->cInterpreterTime += static_cast<uint64_t>(timeDelta);
316             return;
317         }
318         case RunningState::AINT: {
319             profileInfo_->asmInterpreterTime += static_cast<uint64_t>(timeDelta);
320             return;
321         }
322         case RunningState::AOT: {
323             profileInfo_->aotTime += static_cast<uint64_t>(timeDelta);
324             return;
325         }
326         case RunningState::BUILTIN: {
327             profileInfo_->builtinTime += static_cast<uint64_t>(timeDelta);
328             return;
329         }
330         case RunningState::NAPI: {
331             profileInfo_->napiTime += static_cast<uint64_t>(timeDelta);
332             return;
333         }
334         case RunningState::ARKUI_ENGINE: {
335             profileInfo_->arkuiEngineTime += static_cast<uint64_t>(timeDelta);
336             return;
337         }
338         case RunningState::RUNTIME: {
339             profileInfo_->runtimeTime += static_cast<uint64_t>(timeDelta);
340             return;
341         }
342         case RunningState::JIT: {
343             profileInfo_->jitTime += static_cast<uint64_t>(timeDelta);
344             return;
345         }
346         default: {
347             profileInfo_->otherTime += static_cast<uint64_t>(timeDelta);
348             return;
349         }
350     }
351 }
352 
SetThreadStartTime(uint64_t threadStartTime)353 void SamplesRecord::SetThreadStartTime(uint64_t threadStartTime)
354 {
355     profileInfo_->startTime = threadStartTime;
356 }
357 
GetThreadStartTime()358 uint64_t SamplesRecord::GetThreadStartTime()
359 {
360     return profileInfo_->startTime;
361 }
362 
SetThreadStopTime()363 void SamplesRecord::SetThreadStopTime()
364 {
365     profileInfo_->stopTime = previousTimeStamp_;
366 }
367 
SetFileName(std::string &fileName)368 void SamplesRecord::SetFileName(std::string &fileName)
369 {
370     fileName_ = fileName;
371 }
372 
GetFileName() const373 const std::string SamplesRecord::GetFileName() const
374 {
375     return fileName_;
376 }
377 
GetProfileInfo()378 std::unique_ptr<struct ProfileInfo> SamplesRecord::GetProfileInfo()
379 {
380     return std::move(profileInfo_);
381 }
382 
SetCallNapiFlag(bool flag)383 void SamplesRecord::SetCallNapiFlag(bool flag)
384 {
385     callNapi_.store(flag);
386 }
387 
GetCallNapiFlag()388 bool SamplesRecord::GetCallNapiFlag()
389 {
390     return callNapi_.load();
391 }
392 
SemInit(int index, int pshared, int value)393 int SamplesRecord::SemInit(int index, int pshared, int value)
394 {
395     return sem_init(&sem_[index], pshared, value);
396 }
397 
SemPost(int index)398 int SamplesRecord::SemPost(int index)
399 {
400     return sem_post(&sem_[index]);
401 }
402 
SemWait(int index)403 int SamplesRecord::SemWait(int index)
404 {
405     return sem_wait(&sem_[index]);
406 }
407 
SemDestroy(int index)408 int SamplesRecord::SemDestroy(int index)
409 {
410     return sem_destroy(&sem_[index]);
411 }
412 
GetStackInfo() const413 const CMap<struct MethodKey, struct FrameInfo> &SamplesRecord::GetStackInfo() const
414 {
415     return stackInfoMap_;
416 }
417 
InsertStackInfo(struct MethodKey &methodKey, struct FrameInfo &codeEntry)418 void SamplesRecord::InsertStackInfo(struct MethodKey &methodKey, struct FrameInfo &codeEntry)
419 {
420     stackInfoMap_.emplace(methodKey, codeEntry);
421 }
422 
PushFrameStack(struct MethodKey &methodKey)423 bool SamplesRecord::PushFrameStack(struct MethodKey &methodKey)
424 {
425     if (UNLIKELY(frameStackLength_ >= MAX_STACK_SIZE)) {
426         return false;
427     }
428     frameStack_[frameStackLength_++] = methodKey;
429     return true;
430 }
431 
PushNapiFrameStack(struct MethodKey &methodKey)432 bool SamplesRecord::PushNapiFrameStack(struct MethodKey &methodKey)
433 {
434     if (UNLIKELY(napiFrameStack_.size() >= MAX_STACK_SIZE)) {
435         return false;
436     }
437     napiFrameStack_.push_back(methodKey);
438     return true;
439 }
440 
ClearNapiStack()441 void SamplesRecord::ClearNapiStack()
442 {
443     napiFrameStack_.clear();
444     napiFrameInfoTemps_.clear();
445 }
446 
GetNapiFrameStackLength()447 int SamplesRecord::GetNapiFrameStackLength()
448 {
449     return napiFrameStack_.size();
450 }
451 
GetGcState() const452 bool SamplesRecord::GetGcState() const
453 {
454     return gcState_.load();
455 }
456 
SetGcState(bool gcState)457 void SamplesRecord::SetGcState(bool gcState)
458 {
459     gcState_.store(gcState);
460 }
461 
GetRuntimeState() const462 bool SamplesRecord::GetRuntimeState() const
463 {
464     return runtimeState_.load();
465 }
466 
SetRuntimeState(bool runtimeState)467 void SamplesRecord::SetRuntimeState(bool runtimeState)
468 {
469     runtimeState_.store(runtimeState);
470 }
471 
GetIsStart() const472 bool SamplesRecord::GetIsStart() const
473 {
474     return isStart_.load();
475 }
476 
SetIsStart(bool isStart)477 void SamplesRecord::SetIsStart(bool isStart)
478 {
479     isStart_.store(isStart);
480 }
481 
PushStackInfo(const FrameInfoTemp &frameInfoTemp)482 bool SamplesRecord::PushStackInfo(const FrameInfoTemp &frameInfoTemp)
483 {
484     if (UNLIKELY(frameInfoTempLength_ >= MAX_STACK_SIZE)) {
485         return false;
486     }
487     frameInfoTemps_[frameInfoTempLength_++] = frameInfoTemp;
488     return true;
489 }
490 
PushNapiStackInfo(const FrameInfoTemp &frameInfoTemp)491 bool SamplesRecord::PushNapiStackInfo(const FrameInfoTemp &frameInfoTemp)
492 {
493     if (UNLIKELY(napiFrameInfoTemps_.size() == MAX_STACK_SIZE)) {
494         return false;
495     }
496     napiFrameInfoTemps_.push_back(frameInfoTemp);
497     return true;
498 }
499 
GetModuleName(char *recordName)500 std::string SamplesRecord::GetModuleName(char *recordName)
501 {
502     std::string recordNameStr = recordName;
503     std::string::size_type atPos = recordNameStr.find("@");
504     if (atPos == std::string::npos) {
505         return "";
506     }
507 
508     std::string::size_type slashPos = recordNameStr.rfind("/", atPos);
509     if (slashPos == std::string::npos) {
510         return "";
511     }
512 
513     return recordNameStr.substr(slashPos + 1, atPos - slashPos - 1);
514 }
515 
FrameInfoTempToMap(FrameInfoTemp *frameInfoTemps, int frameInfoTempLength)516 void SamplesRecord::FrameInfoTempToMap(FrameInfoTemp *frameInfoTemps, int frameInfoTempLength)
517 {
518     if (frameInfoTempLength == 0) {
519         return;
520     }
521     struct FrameInfo frameInfo;
522     for (int i = 0; i < frameInfoTempLength; ++i) {
523         frameInfo.url = frameInfoTemps[i].url;
524         auto iter = scriptIdMap_.find(frameInfo.url);
525         if (iter == scriptIdMap_.end()) {
526             scriptIdMap_.emplace(frameInfo.url, scriptIdMap_.size() + 1);
527             frameInfo.scriptId = static_cast<int>(scriptIdMap_.size());
528         } else {
529             frameInfo.scriptId = iter->second;
530         }
531         frameInfo.functionName = AddRunningState(frameInfoTemps[i].functionName,
532                                                  frameInfoTemps[i].methodKey.state,
533                                                  frameInfoTemps[i].methodKey.deoptType);
534         if (strlen(frameInfoTemps[i].recordName) != 0) {
535             frameInfo.moduleName = GetModuleName(frameInfoTemps[i].recordName);
536         }
537         frameInfo.columnNumber = frameInfoTemps[i].columnNumber;
538         frameInfo.lineNumber = frameInfoTemps[i].lineNumber;
539         stackInfoMap_.emplace(frameInfoTemps[i].methodKey, frameInfo);
540     }
541     frameInfoTempLength_ = 0;
542 }
543 
NapiFrameInfoTempToMap()544 void SamplesRecord::NapiFrameInfoTempToMap()
545 {
546     size_t length = napiFrameInfoTemps_.size();
547     if (length == 0) {
548         return;
549     }
550     struct FrameInfo frameInfo;
551     for (size_t i = 0; i < length; ++i) {
552         frameInfo.url = napiFrameInfoTemps_[i].url;
553         auto iter = scriptIdMap_.find(frameInfo.url);
554         if (iter == scriptIdMap_.end()) {
555             scriptIdMap_.emplace(frameInfo.url, scriptIdMap_.size() + 1);
556             frameInfo.scriptId = static_cast<int>(scriptIdMap_.size());
557         } else {
558             frameInfo.scriptId = iter->second;
559         }
560         frameInfo.functionName = AddRunningState(napiFrameInfoTemps_[i].functionName,
561                                                  napiFrameInfoTemps_[i].methodKey.state,
562                                                  napiFrameInfoTemps_[i].methodKey.deoptType);
563         if (strlen(napiFrameInfoTemps_[i].recordName) != 0) {
564             frameInfo.moduleName = GetModuleName(napiFrameInfoTemps_[i].recordName);
565         }
566         frameInfo.columnNumber = napiFrameInfoTemps_[i].columnNumber;
567         frameInfo.lineNumber = napiFrameInfoTemps_[i].lineNumber;
568         stackInfoMap_.emplace(napiFrameInfoTemps_[i].methodKey, frameInfo);
569     }
570 }
571 
GetframeStackLength() const572 int SamplesRecord::GetframeStackLength() const
573 {
574     return frameStackLength_;
575 }
576 
PostFrame()577 void SamplesRecord::PostFrame()
578 {
579     samplesQueue_->PostFrame(frameInfoTemps_, frameStack_, frameInfoTempLength_, frameStackLength_);
580 }
581 
PostNapiFrame()582 void SamplesRecord::PostNapiFrame()
583 {
584     samplesQueue_->PostNapiFrame(napiFrameInfoTemps_, napiFrameStack_);
585 }
586 
ResetFrameLength()587 void SamplesRecord::ResetFrameLength()
588 {
589     frameStackLength_ = 0;
590     frameInfoTempLength_ = 0;
591 }
592 
GetCallTimeStamp()593 uint64_t SamplesRecord::GetCallTimeStamp()
594 {
595     return callTimeStamp_;
596 }
597 
SetCallTimeStamp(uint64_t timeStamp)598 void SamplesRecord::SetCallTimeStamp(uint64_t timeStamp)
599 {
600     callTimeStamp_ = timeStamp;
601 }
602 
TranslateUrlPositionBySourceMap(struct FrameInfo &codeEntry)603 void SamplesRecord::TranslateUrlPositionBySourceMap(struct FrameInfo &codeEntry)
604 {
605     if (codeEntry.url.empty()) {
606         return;
607     }
608     if (!sourceMapTranslateCallback_(codeEntry.url, codeEntry.lineNumber, codeEntry.columnNumber)) {
609         size_t find = codeEntry.url.rfind("_.js");
610         if (find == std::string::npos) {
611             size_t start = codeEntry.url.find("entry/");
612             size_t end = codeEntry.url.rfind(".ets");
613             if (start != std::string::npos && end != std::string::npos) {
614                 std::string key = codeEntry.url.substr(start + SUB_LEN, end - start - SUB_LEN);
615                 codeEntry.url = JS_PATH + key + ".js";
616             }
617         }
618     }
619 }
620 
AddStartTraceEvent()621 void SamplesRecord::AddStartTraceEvent()
622 {
623     uint64_t tid = profileInfo_->tid;
624     auto vm = CpuProfiler::GetVmbyTid(tid);
625     if (vm == nullptr) {
626         LOG_ECMA(ERROR) << "CpuProfiler get vm from tid failed";
627         return;
628     }
629 
630     Tracing *tracing = vm->GetTracing();
631     if (tracing == nullptr || !tracing->IsTracing()) {
632         return;
633     }
634 
635     tracing->TraceEventRecordCpuProfilerStart(profileInfo_.get());
636 }
637 
AddTraceEvent(bool isFinish)638 void SamplesRecord::AddTraceEvent(bool isFinish)
639 {
640     const uint32_t samplesCountPerEvent = 100;
641     if (!isFinish && (profileInfo_->samples.size() - traceEventSamplePos_ < samplesCountPerEvent)) {
642         return;
643     }
644 
645     uint64_t tid = profileInfo_->tid;
646     auto vm = CpuProfiler::GetVmbyTid(tid);
647     if (vm == nullptr) {
648         LOG_ECMA(ERROR) << "CpuProfiler get vm from tid failed";
649         return;
650     }
651 
652     Tracing *tracing = vm->GetTracing();
653     if (tracing == nullptr || !tracing->IsTracing()) {
654         return;
655     }
656 
657     tracing->TraceEventRecordCpuProfiler(profileInfo_.get(), traceEventNodePos_, traceEventSamplePos_);
658 
659     if (isFinish) {
660         tracing->TraceEventRecordCpuProfilerEnd(profileInfo_.get());
661     }
662 }
663 
664 // SamplesQueue
PostFrame(FrameInfoTemp *frameInfoTemps, MethodKey *frameStack, int frameInfoTempsLength, int frameStackLength)665 void SamplesQueue::PostFrame(FrameInfoTemp *frameInfoTemps, MethodKey *frameStack,
666                              int frameInfoTempsLength, int frameStackLength)
667 {
668     LockHolder holder(mtx_);
669     if (!IsFull()) {
670         // frameInfoTemps
671         for (int i = 0; i < frameInfoTempsLength; i++) {
672             CheckAndCopy(frames_[rear_].frameInfoTemps[i].functionName,
673                 sizeof(frames_[rear_].frameInfoTemps[i].functionName), frameInfoTemps[i].functionName);
674             CheckAndCopy(frames_[rear_].frameInfoTemps[i].recordName,
675                 sizeof(frames_[rear_].frameInfoTemps[i].recordName), frameInfoTemps[i].recordName);
676             frames_[rear_].frameInfoTemps[i].columnNumber = frameInfoTemps[i].columnNumber;
677             frames_[rear_].frameInfoTemps[i].lineNumber = frameInfoTemps[i].lineNumber;
678             frames_[rear_].frameInfoTemps[i].scriptId = frameInfoTemps[i].scriptId;
679             CheckAndCopy(frames_[rear_].frameInfoTemps[i].url,
680                 sizeof(frames_[rear_].frameInfoTemps[i].url), frameInfoTemps[i].url);
681             frames_[rear_].frameInfoTemps[i].methodKey.methodIdentifier = frameInfoTemps[i].methodKey.methodIdentifier;
682             frames_[rear_].frameInfoTemps[i].methodKey.state = frameInfoTemps[i].methodKey.state;
683             frames_[rear_].frameInfoTemps[i].methodKey.lineNumber = frameInfoTemps[i].methodKey.lineNumber;
684         }
685         // frameStack
686         for (int i = 0; i < frameStackLength; i++) {
687             frames_[rear_].frameStack[i].methodIdentifier = frameStack[i].methodIdentifier;
688             frames_[rear_].frameStack[i].state = frameStack[i].state;
689             frames_[rear_].frameStack[i].lineNumber = frameStack[i].lineNumber;
690         }
691         // frameStackLength
692         frames_[rear_].frameStackLength = frameStackLength;
693         // frameInfoTempsLength
694         frames_[rear_].frameInfoTempsLength = frameInfoTempsLength;
695         // timeStamp
696         frames_[rear_].timeStamp = SamplingProcessor::GetMicrosecondsTimeStamp();
697 
698         rear_ = (rear_ + 1) % QUEUE_CAPACITY;
699     }
700 }
701 
PostNapiFrame(CVector<FrameInfoTemp> &napiFrameInfoTemps, CVector<MethodKey> &napiFrameStack)702 void SamplesQueue::PostNapiFrame(CVector<FrameInfoTemp> &napiFrameInfoTemps,
703                                  CVector<MethodKey> &napiFrameStack)
704 {
705     LockHolder holder(mtx_);
706     if (!IsFull()) {
707         size_t frameInfoTempsLength = napiFrameInfoTemps.size();
708         size_t frameStackLength = napiFrameStack.size();
709         // napiFrameInfoTemps
710         for (size_t i = 0; i < frameInfoTempsLength; i++) {
711             CheckAndCopy(frames_[rear_].frameInfoTemps[i].functionName,
712                 sizeof(frames_[rear_].frameInfoTemps[i].functionName), napiFrameInfoTemps[i].functionName);
713             CheckAndCopy(frames_[rear_].frameInfoTemps[i].recordName,
714                 sizeof(frames_[rear_].frameInfoTemps[i].recordName), napiFrameInfoTemps[i].recordName);
715             frames_[rear_].frameInfoTemps[i].columnNumber = napiFrameInfoTemps[i].columnNumber;
716             frames_[rear_].frameInfoTemps[i].lineNumber = napiFrameInfoTemps[i].lineNumber;
717             frames_[rear_].frameInfoTemps[i].scriptId = napiFrameInfoTemps[i].scriptId;
718             CheckAndCopy(frames_[rear_].frameInfoTemps[i].url,
719                 sizeof(frames_[rear_].frameInfoTemps[i].url), napiFrameInfoTemps[i].url);
720             frames_[rear_].frameInfoTemps[i].methodKey.methodIdentifier =
721                 napiFrameInfoTemps[i].methodKey.methodIdentifier;
722             frames_[rear_].frameInfoTemps[i].methodKey.state = napiFrameInfoTemps[i].methodKey.state;
723             frames_[rear_].frameInfoTemps[i].methodKey.lineNumber = napiFrameInfoTemps[i].methodKey.lineNumber;
724         }
725         // napiFrameStack
726         for (size_t i = 0; i < frameStackLength; i++) {
727             frames_[rear_].frameStack[i].methodIdentifier = napiFrameStack[i].methodIdentifier;
728             frames_[rear_].frameStack[i].state = napiFrameStack[i].state;
729             frames_[rear_].frameStack[i].lineNumber = napiFrameStack[i].lineNumber;
730         }
731         // frameStackLength
732         frames_[rear_].frameStackLength = frameStackLength;
733         // frameInfoTempsLength
734         frames_[rear_].frameInfoTempsLength = frameInfoTempsLength;
735         // timeStamp
736         frames_[rear_].timeStamp = SamplingProcessor::GetMicrosecondsTimeStamp();
737 
738         rear_ = (rear_ + 1) % QUEUE_CAPACITY;
739     }
740 }
741 
PopFrame()742 FrameStackAndInfo *SamplesQueue::PopFrame()
743 {
744     LockHolder holder(mtx_);
745     if (!IsEmpty()) {
746         FrameStackAndInfo *frame = &frames_[front_];
747         front_ = (front_ + 1) % QUEUE_CAPACITY;
748         return frame;
749     }
750     return nullptr;
751 }
752 
IsEmpty()753 bool SamplesQueue::IsEmpty()
754 {
755     return front_ == rear_;
756 }
757 
IsFull()758 bool SamplesQueue::IsFull()
759 {
760     return (rear_ + 1) % QUEUE_CAPACITY == front_;
761 }
762 
GetSize()763 int SamplesQueue::GetSize()
764 {
765     return (rear_ + QUEUE_CAPACITY - front_) % QUEUE_CAPACITY;
766 }
767 
GetFrontIndex()768 int SamplesQueue::GetFrontIndex()
769 {
770     return front_;
771 }
772 
GetRearIndex()773 int SamplesQueue::GetRearIndex()
774 {
775     return rear_;
776 }
777 
CheckAndCopy(char *dest, size_t length, const char *src) const778 bool SamplesQueue::CheckAndCopy(char *dest, size_t length, const char *src) const
779 {
780     int srcLength = strlen(src);
781     if (length <= static_cast<size_t>(srcLength) || strcpy_s(dest, srcLength + 1, src) != EOK) {
782         LOG_ECMA(ERROR) << "SamplesQueue PostFrame strcpy_s failed, maybe srcLength more than destLength";
783         return false;
784     }
785     dest[srcLength] = '\0';
786     return true;
787 }
788 } // namespace panda::ecmascript
789