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