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