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