• 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 
19 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
20 #include "ecmascript/dfx/tracing/tracing.h"
21 
22 namespace panda::ecmascript {
23 const std::string JS_PATH = "entry/build/default/cache/default/default@CompileArkTS/esmodule/debug/";
24 
SamplesRecord()25 SamplesRecord::SamplesRecord()
26 {
27     profileInfo_ = std::make_unique<struct ProfileInfo>();
28     profileInfo_->tid = static_cast<uint64_t>(JSThread::GetCurrentThreadId());
29     samplesQueue_ = new SamplesQueue();
30 }
31 
~SamplesRecord()32 SamplesRecord::~SamplesRecord()
33 {
34     if (fileHandle_.is_open()) {
35         fileHandle_.close();
36     }
37     if (samplesQueue_ != nullptr) {
38         delete samplesQueue_;
39         samplesQueue_ = nullptr;
40     }
41 }
42 
NodeInit()43 void SamplesRecord::NodeInit()
44 {
45     struct NodeKey nodeKey;
46     struct CpuProfileNode methodNode;
47 
48     nodeKey.methodKey.methodIdentifier = reinterpret_cast<void *>(INT_MAX - 1);
49     nodeMap_.emplace(nodeKey, nodeMap_.size() + 1);
50     methodNode.parentId = 0;
51     methodNode.codeEntry.functionName = "(root)";
52     methodNode.id = 1;
53     profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
54 
55     nodeKey.methodKey.methodIdentifier = reinterpret_cast<void *>(INT_MAX - 2);  // 2:program node id
56     nodeMap_.emplace(nodeKey, nodeMap_.size() + 1);
57     methodNode.codeEntry.functionName = "(program)";
58     methodNode.id = 2;  // 2:program node id
59     profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
60     profileInfo_->nodes[0].children.push_back(methodNode.id);
61 
62     nodeKey.methodKey.methodIdentifier = reinterpret_cast<void *>(INT_MAX - 3);  // 3:idle node id
63     nodeMap_.emplace(nodeKey, nodeMap_.size() + 1);
64     methodNode.codeEntry.functionName = "(idle)";
65     methodNode.id = 3;  // 3:idle node id
66     profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
67     profileInfo_->nodes[0].children.push_back(methodNode.id);
68 }
69 
AddSample(FrameStackAndInfo * frame)70 void SamplesRecord::AddSample(FrameStackAndInfo *frame)
71 {
72     int frameStackLength = frame->frameStackLength;
73     if (frameStackLength == 0) {
74         AddEmptyStackSample(frame->timeStamp);
75         return;
76     }
77 
78     FrameInfoTempToMap(frame->frameInfoTemps, frame->frameInfoTempsLength);
79 
80     struct NodeKey nodeKey;
81     struct CpuProfileNode methodNode;
82     methodNode.id = 1;
83     for (; frameStackLength >= 1; frameStackLength--) {
84         nodeKey.methodKey = frame->frameStack[frameStackLength - 1];
85         methodNode.parentId = nodeKey.parentId = methodNode.id;
86         auto result = nodeMap_.find(nodeKey);
87         if (result == nodeMap_.end()) {
88             int id = static_cast<int>(nodeMap_.size() + 1);
89             nodeMap_.emplace(nodeKey, id);
90             previousId_ = methodNode.id = id;
91             methodNode.codeEntry = GetMethodInfo(nodeKey.methodKey);
92             profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
93             if (methodNode.parentId > 0 && methodNode.parentId <= profileInfo_->nodeCount) {
94                 profileInfo_->nodes[methodNode.parentId - 1].children.push_back(id);
95             }
96         } else {
97             previousId_ = methodNode.id = result->second;
98         }
99     }
100 
101     int sampleNodeId = previousId_ == 0 ? 1 : methodNode.id;
102     int timeDelta = static_cast<int>(frame->timeStamp -
103         (previousTimeStamp_ == 0 ? profileInfo_->startTime : previousTimeStamp_));
104 
105     // delete abnormal sample
106     if (timeDelta > static_cast<int>(timeDeltaThreshold_) && previousState_ != RunningState::NAPI) {
107         uint32_t size = profileInfo_->samples.size();
108         if (size > 0) {
109             profileInfo_->samples[size - 1] = PROGRAM_NODE_ID;
110         }
111         previousState_ = RunningState::OTHER;
112     }
113     StatisticStateTime(timeDelta, previousState_);
114     previousState_ = nodeKey.methodKey.state;
115     profileInfo_->nodes[sampleNodeId - 1].hitCount++;
116     profileInfo_->samples.push_back(sampleNodeId);
117     profileInfo_->timeDeltas.push_back(timeDelta);
118     previousTimeStamp_ = frame->timeStamp;
119 }
120 
AddEmptyStackSample(uint64_t sampleTimeStamp)121 void SamplesRecord::AddEmptyStackSample(uint64_t sampleTimeStamp)
122 {
123     int timeDelta = static_cast<int>(sampleTimeStamp -
124         (previousTimeStamp_ == 0 ? profileInfo_->startTime : previousTimeStamp_));
125 
126     // delete abnormal sample
127     if (timeDelta > static_cast<int>(timeDeltaThreshold_) && previousState_ != RunningState::NAPI) {
128         uint32_t size = profileInfo_->samples.size();
129         if (size > 0) {
130             profileInfo_->samples[size - 1] = PROGRAM_NODE_ID;
131         }
132         previousState_ = RunningState::OTHER;
133     }
134 
135     StatisticStateTime(timeDelta, previousState_);
136     previousState_ = RunningState::OTHER;
137     profileInfo_->nodes[1].hitCount++;
138     profileInfo_->samples.push_back(PROGRAM_NODE_ID);
139     profileInfo_->timeDeltas.push_back(timeDelta);
140     previousTimeStamp_ = sampleTimeStamp;
141 }
142 
StringifySampleData()143 void SamplesRecord::StringifySampleData()
144 {
145     sampleData_ += "{\"tid\":"
146         + std::to_string(profileInfo_->tid) + ",\"startTime\":"
147         + std::to_string(profileInfo_->startTime) + ",\"endTime\":"
148         + std::to_string(profileInfo_->stopTime) + ",";
149 
150     StringifyStateTimeStatistic();
151     StringifyNodes();
152     StringifySamples();
153 }
154 
StringifyStateTimeStatistic()155 void SamplesRecord::StringifyStateTimeStatistic()
156 {
157     sampleData_ += "\"gcTime\":"
158         + std::to_string(profileInfo_->gcTime) + ",\"cInterpreterTime\":"
159         + std::to_string(profileInfo_->cInterpreterTime) + ",\"asmInterpreterTime\":"
160         + std::to_string(profileInfo_->asmInterpreterTime) + ",\"aotTime\":"
161         + std::to_string(profileInfo_->aotTime) + ",\"asmInterpreterDeoptTime\":"
162         + std::to_string(profileInfo_->asmInterpreterDeoptTime) + ",\"builtinTime\":"
163         + std::to_string(profileInfo_->builtinTime) + ",\"napiTime\":"
164         + std::to_string(profileInfo_->napiTime) + ",\"arkuiEngineTime\":"
165         + std::to_string(profileInfo_->arkuiEngineTime) + ",\"runtimeTime\":"
166         + std::to_string(profileInfo_->runtimeTime) + ",\"jitTime\":"
167         + std::to_string(profileInfo_->jitTime) + ",\"otherTime\":"
168         + std::to_string(profileInfo_->otherTime) + ",";
169 }
170 
StringifyNodes()171 void SamplesRecord::StringifyNodes()
172 {
173     sampleData_ += "\"nodes\":[";
174     size_t nodeCount = static_cast<size_t>(profileInfo_->nodeCount);
175     bool translateCallback = false;
176     if (sourceMapTranslateCallback_ != nullptr) {
177         translateCallback = true;
178     }
179     for (size_t i = 0; i < nodeCount; i++) {
180         struct CpuProfileNode node = profileInfo_->nodes[i];
181         struct FrameInfo codeEntry = node.codeEntry;
182         if (translateCallback) {
183             TranslateUrlPositionBySourceMap(codeEntry);
184         }
185         std::string url = codeEntry.url;
186         replace(url.begin(), url.end(), '\\', '/');
187         sampleData_ += "{\"id\":"
188         + std::to_string(node.id) + ",\"callFrame\":{\"functionName\":\""
189         + codeEntry.functionName + "\",\"moduleName\":\""
190         + codeEntry.moduleName + "\",\"scriptId\":\""
191         + std::to_string(codeEntry.scriptId) + "\",\"url\":\""
192         + url + "\",\"lineNumber\":"
193         + std::to_string(codeEntry.lineNumber) + ",\"columnNumber\":"
194         + std::to_string(codeEntry.columnNumber) + "},\"hitCount\":"
195         + std::to_string(node.hitCount) + ",\"children\":[";
196         CVector<int> children = node.children;
197         size_t childrenCount = children.size();
198         for (size_t j = 0; j < childrenCount; j++) {
199             sampleData_ += std::to_string(children[j]) + ",";
200         }
201         if (childrenCount > 0) {
202             sampleData_.pop_back();
203         }
204         sampleData_ += "]},";
205     }
206     sampleData_.pop_back();
207     sampleData_ += "],";
208 }
209 
StringifySamples()210 void SamplesRecord::StringifySamples()
211 {
212     CVector<int> samples = profileInfo_->samples;
213     CVector<int> timeDeltas = profileInfo_->timeDeltas;
214 
215     size_t samplesCount = samples.size();
216     std::string samplesIdStr = "";
217     std::string timeDeltasStr = "";
218     for (size_t i = 0; i < samplesCount; i++) {
219         samplesIdStr += std::to_string(samples[i]) + ",";
220         timeDeltasStr += std::to_string(timeDeltas[i]) + ",";
221     }
222     samplesIdStr.pop_back();
223     timeDeltasStr.pop_back();
224 
225     sampleData_ += "\"samples\":[" + samplesIdStr + "],\"timeDeltas\":[" + timeDeltasStr + "]}";
226 }
227 
GetMethodNodeCount() const228 int SamplesRecord::GetMethodNodeCount() const
229 {
230     return profileInfo_->nodeCount;
231 }
232 
GetSampleData() const233 std::string SamplesRecord::GetSampleData() const
234 {
235     return sampleData_;
236 }
237 
GetMethodInfo(struct MethodKey & methodKey)238 struct FrameInfo SamplesRecord::GetMethodInfo(struct MethodKey &methodKey)
239 {
240     struct FrameInfo entry;
241     auto iter = stackInfoMap_.find(methodKey);
242     if (iter != stackInfoMap_.end()) {
243         entry = iter->second;
244     }
245     return entry;
246 }
247 
AddRunningState(char * functionName,RunningState state,kungfu::DeoptType type)248 std::string SamplesRecord::AddRunningState(char *functionName, RunningState state, kungfu::DeoptType type)
249 {
250     std::string temp = functionName;
251     switch (state) {
252         case RunningState::AINT_D:
253             temp.append("(AINT-D)");
254             break;
255         case RunningState::GC:
256             temp.append("(GC)");
257             break;
258         case RunningState::CINT:
259             if (enableVMTag_) {
260                 temp.append("(CINT)");
261             }
262             break;
263         case RunningState::AINT:
264             if (enableVMTag_) {
265                 temp.append("(AINT)");
266             }
267             break;
268         case RunningState::AOT:
269             if (enableVMTag_) {
270                 temp.append("(AOT)");
271             }
272             break;
273         case RunningState::BUILTIN:
274             temp.append("(BUILTIN)");
275             break;
276         case RunningState::NAPI:
277             temp.append("(NAPI)");
278             break;
279         case RunningState::ARKUI_ENGINE:
280             temp.append("(ARKUI_ENGINE)");
281             break;
282         case RunningState::RUNTIME:
283             if (enableVMTag_) {
284                 temp.append("(RUNTIME)");
285             }
286             break;
287         case RunningState::JIT:
288             temp.append("(JIT)");
289             break;
290         default:
291             break;
292     }
293     if (state == RunningState::AINT_D && type != kungfu::DeoptType::NONE && enableVMTag_) {
294         std::string typeCheckStr = "(DEOPT:" + Deoptimizier::DisplayItems(type) + ")";
295         temp.append(typeCheckStr);
296     }
297     return temp;
298 }
299 
StatisticStateTime(int timeDelta,RunningState state)300 void SamplesRecord::StatisticStateTime(int timeDelta, RunningState state)
301 {
302     switch (state) {
303         case RunningState::AINT_D: {
304             profileInfo_->asmInterpreterDeoptTime += static_cast<uint64_t>(timeDelta);
305             return;
306         }
307         case RunningState::GC: {
308             profileInfo_->gcTime += static_cast<uint64_t>(timeDelta);
309             return;
310         }
311         case RunningState::CINT: {
312             profileInfo_->cInterpreterTime += static_cast<uint64_t>(timeDelta);
313             return;
314         }
315         case RunningState::AINT: {
316             profileInfo_->asmInterpreterTime += static_cast<uint64_t>(timeDelta);
317             return;
318         }
319         case RunningState::AOT: {
320             profileInfo_->aotTime += static_cast<uint64_t>(timeDelta);
321             return;
322         }
323         case RunningState::BUILTIN: {
324             profileInfo_->builtinTime += static_cast<uint64_t>(timeDelta);
325             return;
326         }
327         case RunningState::NAPI: {
328             profileInfo_->napiTime += static_cast<uint64_t>(timeDelta);
329             return;
330         }
331         case RunningState::ARKUI_ENGINE: {
332             profileInfo_->arkuiEngineTime += static_cast<uint64_t>(timeDelta);
333             return;
334         }
335         case RunningState::RUNTIME: {
336             profileInfo_->runtimeTime += static_cast<uint64_t>(timeDelta);
337             return;
338         }
339         case RunningState::JIT: {
340             profileInfo_->jitTime += static_cast<uint64_t>(timeDelta);
341             return;
342         }
343         default: {
344             profileInfo_->otherTime += static_cast<uint64_t>(timeDelta);
345             return;
346         }
347     }
348 }
349 
SetThreadStartTime(uint64_t threadStartTime)350 void SamplesRecord::SetThreadStartTime(uint64_t threadStartTime)
351 {
352     profileInfo_->startTime = threadStartTime;
353 }
354 
GetThreadStartTime()355 uint64_t SamplesRecord::GetThreadStartTime()
356 {
357     return profileInfo_->startTime;
358 }
359 
SetThreadStopTime()360 void SamplesRecord::SetThreadStopTime()
361 {
362     profileInfo_->stopTime = previousTimeStamp_;
363 }
364 
SetFileName(std::string & fileName)365 void SamplesRecord::SetFileName(std::string &fileName)
366 {
367     fileName_ = fileName;
368 }
369 
GetFileName() const370 const std::string SamplesRecord::GetFileName() const
371 {
372     return fileName_;
373 }
374 
GetProfileInfo()375 std::unique_ptr<struct ProfileInfo> SamplesRecord::GetProfileInfo()
376 {
377     return std::move(profileInfo_);
378 }
379 
SetCallNapiFlag(bool flag)380 void SamplesRecord::SetCallNapiFlag(bool flag)
381 {
382     callNapi_.store(flag);
383 }
384 
GetCallNapiFlag()385 bool SamplesRecord::GetCallNapiFlag()
386 {
387     return callNapi_.load();
388 }
389 
SemInit(int index,int pshared,int value)390 int SamplesRecord::SemInit(int index, int pshared, int value)
391 {
392     return sem_init(&sem_[index], pshared, value);
393 }
394 
SemPost(int index)395 int SamplesRecord::SemPost(int index)
396 {
397     return sem_post(&sem_[index]);
398 }
399 
SemWait(int index)400 int SamplesRecord::SemWait(int index)
401 {
402     return sem_wait(&sem_[index]);
403 }
404 
SemDestroy(int index)405 int SamplesRecord::SemDestroy(int index)
406 {
407     return sem_destroy(&sem_[index]);
408 }
409 
GetStackInfo() const410 const CMap<struct MethodKey, struct FrameInfo> &SamplesRecord::GetStackInfo() const
411 {
412     return stackInfoMap_;
413 }
414 
InsertStackInfo(struct MethodKey & methodKey,struct FrameInfo & codeEntry)415 void SamplesRecord::InsertStackInfo(struct MethodKey &methodKey, struct FrameInfo &codeEntry)
416 {
417     stackInfoMap_.emplace(methodKey, codeEntry);
418 }
419 
PushFrameStack(struct MethodKey & methodKey)420 bool SamplesRecord::PushFrameStack(struct MethodKey &methodKey)
421 {
422     if (UNLIKELY(frameStackLength_ >= MAX_STACK_SIZE)) {
423         return false;
424     }
425     frameStack_[frameStackLength_++] = methodKey;
426     return true;
427 }
428 
PushNapiFrameStack(struct MethodKey & methodKey)429 bool SamplesRecord::PushNapiFrameStack(struct MethodKey &methodKey)
430 {
431     if (UNLIKELY(napiFrameStack_.size() >= MAX_STACK_SIZE)) {
432         return false;
433     }
434     napiFrameStack_.push_back(methodKey);
435     return true;
436 }
437 
ClearNapiStack()438 void SamplesRecord::ClearNapiStack()
439 {
440     napiFrameStack_.clear();
441     napiFrameInfoTemps_.clear();
442 }
443 
GetNapiFrameStackLength()444 int SamplesRecord::GetNapiFrameStackLength()
445 {
446     return napiFrameStack_.size();
447 }
448 
GetGcState() const449 bool SamplesRecord::GetGcState() const
450 {
451     return gcState_.load();
452 }
453 
SetGcState(bool gcState)454 void SamplesRecord::SetGcState(bool gcState)
455 {
456     gcState_.store(gcState);
457 }
458 
GetRuntimeState() const459 bool SamplesRecord::GetRuntimeState() const
460 {
461     return runtimeState_.load();
462 }
463 
SetRuntimeState(bool runtimeState)464 void SamplesRecord::SetRuntimeState(bool runtimeState)
465 {
466     runtimeState_.store(runtimeState);
467 }
468 
GetIsStart() const469 bool SamplesRecord::GetIsStart() const
470 {
471     return isStart_.load();
472 }
473 
SetIsStart(bool isStart)474 void SamplesRecord::SetIsStart(bool isStart)
475 {
476     isStart_.store(isStart);
477 }
478 
PushStackInfo(const FrameInfoTemp & frameInfoTemp)479 bool SamplesRecord::PushStackInfo(const FrameInfoTemp &frameInfoTemp)
480 {
481     if (UNLIKELY(frameInfoTempLength_ >= MAX_STACK_SIZE)) {
482         return false;
483     }
484     frameInfoTemps_[frameInfoTempLength_++] = frameInfoTemp;
485     return true;
486 }
487 
PushNapiStackInfo(const FrameInfoTemp & frameInfoTemp)488 bool SamplesRecord::PushNapiStackInfo(const FrameInfoTemp &frameInfoTemp)
489 {
490     if (UNLIKELY(napiFrameInfoTemps_.size() == MAX_STACK_SIZE)) {
491         return false;
492     }
493     napiFrameInfoTemps_.push_back(frameInfoTemp);
494     return true;
495 }
496 
GetModuleName(char * recordName)497 std::string SamplesRecord::GetModuleName(char *recordName)
498 {
499     std::string recordNameStr = recordName;
500     std::string::size_type atPos = recordNameStr.find("@");
501     if (atPos == std::string::npos) {
502         return "";
503     }
504 
505     std::string::size_type slashPos = recordNameStr.rfind("/", atPos);
506     if (slashPos == std::string::npos) {
507         return "";
508     }
509 
510     return recordNameStr.substr(slashPos + 1, atPos - slashPos - 1);
511 }
512 
FrameInfoTempToMap(FrameInfoTemp * frameInfoTemps,int frameInfoTempLength)513 void SamplesRecord::FrameInfoTempToMap(FrameInfoTemp *frameInfoTemps, int frameInfoTempLength)
514 {
515     if (frameInfoTempLength == 0) {
516         return;
517     }
518     struct FrameInfo frameInfo;
519     for (int i = 0; i < frameInfoTempLength; ++i) {
520         frameInfo.url = frameInfoTemps[i].url;
521         auto iter = scriptIdMap_.find(frameInfo.url);
522         if (iter == scriptIdMap_.end()) {
523             scriptIdMap_.emplace(frameInfo.url, scriptIdMap_.size() + 1);
524             frameInfo.scriptId = static_cast<int>(scriptIdMap_.size());
525         } else {
526             frameInfo.scriptId = iter->second;
527         }
528         frameInfo.functionName = AddRunningState(frameInfoTemps[i].functionName,
529                                                  frameInfoTemps[i].methodKey.state,
530                                                  frameInfoTemps[i].methodKey.deoptType);
531         if (strlen(frameInfoTemps[i].recordName) != 0) {
532             frameInfo.moduleName = GetModuleName(frameInfoTemps[i].recordName);
533         }
534         frameInfo.columnNumber = frameInfoTemps[i].columnNumber;
535         frameInfo.lineNumber = frameInfoTemps[i].lineNumber;
536         stackInfoMap_.emplace(frameInfoTemps[i].methodKey, frameInfo);
537     }
538     frameInfoTempLength_ = 0;
539 }
540 
NapiFrameInfoTempToMap()541 void SamplesRecord::NapiFrameInfoTempToMap()
542 {
543     size_t length = napiFrameInfoTemps_.size();
544     if (length == 0) {
545         return;
546     }
547     struct FrameInfo frameInfo;
548     for (size_t i = 0; i < length; ++i) {
549         frameInfo.url = napiFrameInfoTemps_[i].url;
550         auto iter = scriptIdMap_.find(frameInfo.url);
551         if (iter == scriptIdMap_.end()) {
552             scriptIdMap_.emplace(frameInfo.url, scriptIdMap_.size() + 1);
553             frameInfo.scriptId = static_cast<int>(scriptIdMap_.size());
554         } else {
555             frameInfo.scriptId = iter->second;
556         }
557         frameInfo.functionName = AddRunningState(napiFrameInfoTemps_[i].functionName,
558                                                  napiFrameInfoTemps_[i].methodKey.state,
559                                                  napiFrameInfoTemps_[i].methodKey.deoptType);
560         if (strlen(napiFrameInfoTemps_[i].recordName) != 0) {
561             frameInfo.moduleName = GetModuleName(napiFrameInfoTemps_[i].recordName);
562         }
563         frameInfo.columnNumber = napiFrameInfoTemps_[i].columnNumber;
564         frameInfo.lineNumber = napiFrameInfoTemps_[i].lineNumber;
565         stackInfoMap_.emplace(napiFrameInfoTemps_[i].methodKey, frameInfo);
566     }
567 }
568 
GetframeStackLength() const569 int SamplesRecord::GetframeStackLength() const
570 {
571     return frameStackLength_;
572 }
573 
PostFrame()574 void SamplesRecord::PostFrame()
575 {
576     samplesQueue_->PostFrame(frameInfoTemps_, frameStack_, frameInfoTempLength_, frameStackLength_);
577 }
578 
PostNapiFrame()579 void SamplesRecord::PostNapiFrame()
580 {
581     samplesQueue_->PostNapiFrame(napiFrameInfoTemps_, napiFrameStack_);
582 }
583 
ResetFrameLength()584 void SamplesRecord::ResetFrameLength()
585 {
586     frameStackLength_ = 0;
587     frameInfoTempLength_ = 0;
588 }
589 
GetCallTimeStamp()590 uint64_t SamplesRecord::GetCallTimeStamp()
591 {
592     return callTimeStamp_;
593 }
594 
SetCallTimeStamp(uint64_t timeStamp)595 void SamplesRecord::SetCallTimeStamp(uint64_t timeStamp)
596 {
597     callTimeStamp_ = timeStamp;
598 }
599 
TranslateUrlPositionBySourceMap(struct FrameInfo & codeEntry)600 void SamplesRecord::TranslateUrlPositionBySourceMap(struct FrameInfo &codeEntry)
601 {
602     if (codeEntry.url.empty()) {
603         return;
604     }
605     if (!sourceMapTranslateCallback_(codeEntry.url, codeEntry.lineNumber, codeEntry.columnNumber,
606                                      codeEntry.packageName)) {
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