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