• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/dfx/cpu_profiler/samples_record.h"
17 
18 #include <climits>
19 #include <sys/syscall.h>
20 #include <unistd.h>
21 
22 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
23 #include "ecmascript/dfx/cpu_profiler/sampling_processor.h"
24 #include "ecmascript/ecma_vm.h"
25 #include "ecmascript/interpreter/interpreter.h"
26 #include "ecmascript/method.h"
27 
28 namespace panda::ecmascript {
SamplesRecord()29 SamplesRecord::SamplesRecord()
30 {
31     stackTopLines_.push_back(0);
32     struct NodeKey nodeKey;
33     struct CpuProfileNode methodNode;
34     struct MethodKey methodKey;
35     methodKey.methodIdentifier = reinterpret_cast<void *>(INT_MAX - 1);
36     nodeKey.methodKey = methodKey;
37     nodeMap_.emplace(nodeKey, nodeMap_.size() + 1);
38     methodNode.parentId = 0;
39     methodNode.codeEntry.codeType = "JS";
40     methodNode.codeEntry.functionName = "(root)";
41     methodNode.id = 1;
42     profileInfo_ = std::make_unique<struct ProfileInfo>();
43     profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
44     int tid = syscall(SYS_gettid);
45     if (tid != -1) {
46         profileInfo_->tid = static_cast<uint64_t>(tid);
47     }
48     samplesQueue_ = new SamplesQueue();
49 }
50 
~SamplesRecord()51 SamplesRecord::~SamplesRecord()
52 {
53     if (fileHandle_.is_open()) {
54         fileHandle_.close();
55     }
56     if (samplesQueue_ != nullptr) {
57         delete samplesQueue_;
58     }
59 }
60 
AddSample(FrameStackAndInfo * frame)61 void SamplesRecord::AddSample(FrameStackAndInfo *frame)
62 {
63     FrameInfoTempToMap(frame->frameInfoTemps, frame->frameInfoTempsLength);
64     struct NodeKey nodeKey;
65     struct CpuProfileNode methodNode;
66     int frameStackLength = frame->frameStackLength;
67     if (frameStackLength != 0) {
68         frameStackLength--;
69     }
70     methodNode.id = 1;
71     for (; frameStackLength >= 1; frameStackLength--) {
72         nodeKey.methodKey = frame->frameStack[frameStackLength - 1];
73         methodNode.parentId = nodeKey.parentId = methodNode.id;
74         auto result = nodeMap_.find(nodeKey);
75         if (result == nodeMap_.end()) {
76             int id = static_cast<int>(nodeMap_.size() + 1);
77             nodeMap_.emplace(nodeKey, id);
78             previousId_ = methodNode.id = id;
79             methodNode.codeEntry = GetMethodInfo(nodeKey.methodKey);
80             stackTopLines_.push_back(methodNode.codeEntry.lineNumber);
81             profileInfo_->nodes[profileInfo_->nodeCount++] = methodNode;
82             profileInfo_->nodes[methodNode.parentId - 1].children.push_back(id);
83         } else {
84             previousId_ = methodNode.id = result->second;
85         }
86     }
87 
88     int sampleNodeId = previousId_ == 0 ? 1 : methodNode.id;
89     int timeDelta = static_cast<int>(frame->timeStamp -
90         (previousTimeStamp_ == 0 ? profileInfo_->startTime : previousTimeStamp_));
91     StatisticStateTime(timeDelta, previousState_);
92     previousState_ = nodeKey.methodKey.state;
93     profileInfo_->nodes[sampleNodeId - 1].hitCount++;
94     profileInfo_->samples.push_back(sampleNodeId);
95     profileInfo_->timeDeltas.push_back(timeDelta);
96     previousTimeStamp_ = frame->timeStamp;
97 }
98 
AddRootSample()99 void SamplesRecord::AddRootSample()
100 {
101     int sampleNodeId = 1;
102     uint64_t sampleTimeStamp = SamplingProcessor::GetMicrosecondsTimeStamp();
103     int timeDelta = static_cast<int>(sampleTimeStamp -
104         (previousTimeStamp_ == 0 ? profileInfo_->startTime : previousTimeStamp_));
105     StatisticStateTime(timeDelta, previousState_);
106     previousState_ = RunningState::OTHER;
107     profileInfo_->nodes[0].hitCount++;
108     profileInfo_->samples.push_back(sampleNodeId);
109     profileInfo_->timeDeltas.push_back(timeDelta);
110     previousTimeStamp_ = sampleTimeStamp;
111 }
112 
StringifySampleData()113 void SamplesRecord::StringifySampleData()
114 {
115     sampleData_ += "{\"tid\":"
116         + std::to_string(profileInfo_->tid) + ",\"startTime\":"
117         + std::to_string(profileInfo_->startTime) + ",\"endTime\":"
118         + std::to_string(profileInfo_->stopTime) + ",";
119 
120     StringifyStateTimeStatistic();
121     StringifyNodes();
122     StringifySamples();
123 }
124 
StringifyStateTimeStatistic()125 void SamplesRecord::StringifyStateTimeStatistic()
126 {
127     sampleData_ += "\"gcTime\":"
128         + std::to_string(profileInfo_->gcTime) + ",\"cInterpreterTime\":"
129         + std::to_string(profileInfo_->cInterpreterTime) + ",\"asmInterpreterTime\":"
130         + std::to_string(profileInfo_->asmInterpreterTime) + ",\"aotTime\":"
131         + std::to_string(profileInfo_->aotTime) + ",\"builtinTime\":"
132         + std::to_string(profileInfo_->builtinTime) + ",\"napiTime\":"
133         + std::to_string(profileInfo_->napiTime) + ",\"arkuiEngineTime\":"
134         + std::to_string(profileInfo_->arkuiEngineTime) + ",\"runtimeTime\":"
135         + std::to_string(profileInfo_->runtimeTime) + ",\"otherTime\":"
136         + std::to_string(profileInfo_->otherTime) + ",";
137 }
138 
StringifyNodes()139 void SamplesRecord::StringifyNodes()
140 {
141     sampleData_ += "\"nodes\":[";
142     size_t nodeCount = static_cast<size_t>(profileInfo_->nodeCount);
143     for (size_t i = 0; i < nodeCount; i++) {
144         struct CpuProfileNode node = profileInfo_->nodes[i];
145         struct FrameInfo codeEntry = node.codeEntry;
146         std::string url = codeEntry.url;
147         replace(url.begin(), url.end(), '\\', '/');
148         sampleData_ += "{\"id\":"
149         + std::to_string(node.id) + ",\"callFrame\":{\"functionName\":\""
150         + codeEntry.functionName + "\",\"scriptId\":\""
151         + std::to_string(codeEntry.scriptId) + "\",\"url\":\""
152         + url + "\",\"lineNumber\":"
153         + std::to_string(codeEntry.lineNumber) + ",\"columnNumber\":"
154         + std::to_string(codeEntry.columnNumber) + "},\"hitCount\":"
155         + std::to_string(node.hitCount) + ",\"children\":[";
156         CVector<int> children = node.children;
157         size_t childrenCount = children.size();
158         for (size_t j = 0; j < childrenCount; j++) {
159             sampleData_ += std::to_string(children[j]) + ",";
160         }
161         if (childrenCount > 0) {
162             sampleData_.pop_back();
163         }
164         sampleData_ += "]},";
165     }
166     sampleData_.pop_back();
167     sampleData_ += "],";
168 }
169 
StringifySamples()170 void SamplesRecord::StringifySamples()
171 {
172     CVector<int> samples = profileInfo_->samples;
173     CVector<int> timeDeltas = profileInfo_->timeDeltas;
174 
175     size_t samplesCount = samples.size();
176     std::string samplesIdStr = "";
177     std::string timeDeltasStr = "";
178     for (size_t i = 0; i < samplesCount; i++) {
179         samplesIdStr += std::to_string(samples[i]) + ",";
180         timeDeltasStr += std::to_string(timeDeltas[i]) + ",";
181     }
182     samplesIdStr.pop_back();
183     timeDeltasStr.pop_back();
184 
185     sampleData_ += "\"samples\":[" + samplesIdStr + "],\"timeDeltas\":[" + timeDeltasStr + "]}";
186 }
187 
188 /*
189  * Description: Finetune samples timedelta when stop cpuprofiler
190  * Use two-pointer algorithm to iterate samples and actively recorded napiCallTimeVec_ and napiCallAddrVec_
191  *     Accumulate timeDelta and startTime to get the current timestamp
192  *     When current timestamp larger than napiCall start time, then
193  *         Loop backward PRE_IDX_RANGE times from previous index, find same address napi
194  *         If find the same address napi, then call FindSampleAndFinetune to finetune timedelta
195  * Parameters: null
196  * Return: null
197  */
FinetuneSampleData()198 void SamplesRecord::FinetuneSampleData()
199 {
200     CVector<int> &samples = profileInfo_->samples;
201 
202     size_t samplesCount = samples.size();           // samples count
203     size_t napiCallCount = napiCallTimeVec_.size(); // napiCall count
204     size_t sampleIdx = 0;                           // samples index
205     size_t napiCallIdx = 0;                         // napiCall index
206     uint64_t sampleTime = profileInfo_->startTime;  // current timestamp
207 
208     while (sampleIdx < samplesCount && napiCallIdx < napiCallCount) {
209         // accumulate timeDelta to get current timestamp until larger than napiCall start time
210         sampleTime += static_cast<uint64_t>(profileInfo_->timeDeltas[sampleIdx]);
211         if (sampleTime < napiCallTimeVec_[napiCallIdx]) {
212             sampleIdx++;
213             continue;
214         }
215         bool findFlag = false;
216         size_t findIdx = sampleIdx;
217         size_t preIdx = sampleIdx;
218         uint64_t preSampleTime = sampleTime -
219             static_cast<uint64_t>(profileInfo_->timeDeltas[sampleIdx]); // preIdx's timestamp
220         std::string napiFunctionAddr = napiCallAddrVec_[napiCallIdx];
221         if (sampleIdx - 1 >= 0) {
222             preIdx = sampleIdx - 1;
223             preSampleTime -= static_cast<uint64_t>(profileInfo_->timeDeltas[sampleIdx - 1]);
224         }
225         // loop backward PRE_IDX_RANGE times from previous index, find same address napi
226         for (size_t k = preIdx; k - preIdx < PRE_IDX_RANGE && k < samplesCount; k++) {
227             std::string samplesFunctionName = profileInfo_->nodes[samples[k] - 1].codeEntry.functionName;
228             preSampleTime += static_cast<uint64_t>(profileInfo_->timeDeltas[k]);
229             if (samplesFunctionName.find(napiFunctionAddr) != std::string::npos) {
230                 findFlag = true;
231                 findIdx = k;
232                 break;
233             }
234         }
235         // found the same address napi
236         if (findFlag) {
237             FindSampleAndFinetune(findIdx, napiCallIdx, sampleIdx, preSampleTime, sampleTime);
238         } else {
239             sampleTime -= static_cast<uint64_t>(profileInfo_->timeDeltas[sampleIdx]);
240         }
241         napiCallIdx += NAPI_CALL_SETP;
242     }
243 }
244 
245 /*
246  * Description: Finetune samples timedelta when find the same address napi
247  *      1. get a continuous sample: loop the samples until find the first sample that is different from findIdx
248  *      2. startIdx and endIdx: beginning and end of the continuous sample
249  *      3. call FinetuneTimeDeltas to finetune startIdx and endIdx's timedelta
250  * Parameters:
251  *      1. findIdx: sample index of same address with napi
252  *      2. napiCallIdx: napi call index
253  *      3. sampleIdx: sample index
254  *      4. startSampleTime: start sample timestamp
255  *      5. sampleTime: current timestamp
256  * Return: null
257  */
FindSampleAndFinetune(size_t findIdx,size_t napiCallIdx,size_t & sampleIdx,uint64_t startSampleTime,uint64_t & sampleTime)258 void SamplesRecord::FindSampleAndFinetune(size_t findIdx, size_t napiCallIdx, size_t &sampleIdx,
259                                           uint64_t startSampleTime, uint64_t &sampleTime)
260 {
261     size_t startIdx = findIdx;
262     size_t endIdx = findIdx + 1;
263     size_t samplesCount = profileInfo_->samples.size();
264     uint64_t endSampleTime = startSampleTime;                 // end sample timestamp
265     uint64_t startNapiTime = napiCallTimeVec_[napiCallIdx];   // call napi start timestamp
266     uint64_t endNapiTime = napiCallTimeVec_[napiCallIdx + 1]; // call napi end timestamp
267     // get a continuous sample, accumulate endSampleTime but lack last timeDeltas
268     for (; endIdx < samplesCount && profileInfo_->samples[endIdx - 1] == profileInfo_->samples[endIdx]; endIdx++) {
269         endSampleTime += static_cast<uint64_t>(profileInfo_->timeDeltas[endIdx]);
270     }
271     // finetune startIdx‘s timedelta
272     FinetuneTimeDeltas(startIdx, startNapiTime, startSampleTime, false);
273     // if the continuous sample' size is 1, endSampleTime need to adjust
274     if (startIdx + 1 == endIdx) {
275         endSampleTime -= (startSampleTime - startNapiTime);
276     }
277     // finetune endIdx's timedelta
278     FinetuneTimeDeltas(endIdx, endNapiTime, endSampleTime, true);
279     sampleTime = endSampleTime;
280     sampleIdx = endIdx;
281 }
282 
283 /*
284  * Description: Finetune time deltas
285  * Parameters:
286  *      1. idx: sample index
287  *      2. napiTime: napi timestamp
288  *      3. sampleTime: sample timestamp
289  *      4. isEndSample: if is endIdx, isEndSample is true, else isEndSample is false
290  * Return: null
291  */
FinetuneTimeDeltas(size_t idx,uint64_t napiTime,uint64_t & sampleTime,bool isEndSample)292 void SamplesRecord::FinetuneTimeDeltas(size_t idx, uint64_t napiTime, uint64_t &sampleTime, bool isEndSample)
293 {
294     // timeDeltas[idx] minus a period of time, timeDeltas[idx+1] needs to add the same time
295     if (isEndSample) {
296         // if is endIdx, sampleTime add endTimeDelta is real current timestamp
297         int endTimeDelta = profileInfo_->timeDeltas[idx];
298         profileInfo_->timeDeltas[idx] -= static_cast<int>(sampleTime - napiTime) + endTimeDelta;
299         profileInfo_->timeDeltas[idx + 1] += static_cast<int>(sampleTime - napiTime) + endTimeDelta;
300     } else {
301         profileInfo_->timeDeltas[idx] -= static_cast<int>(sampleTime - napiTime);
302         profileInfo_->timeDeltas[idx + 1] += static_cast<int>(sampleTime - napiTime);
303     }
304 
305     // if timeDeltas[idx] < 0, timeDeltas[idx] = MIN_TIME_DELTA
306     if (profileInfo_->timeDeltas[idx] < 0) {
307         // timeDelta is added part, needs other sample reduce to balance
308         int timeDelta = MIN_TIME_DELTA - profileInfo_->timeDeltas[idx];
309         // profileInfo_->timeDeltas[idx - 1] to reduce
310         if (idx - 1 >= 0 && profileInfo_->timeDeltas[idx - 1] > timeDelta) {
311             profileInfo_->timeDeltas[idx - 1] -= timeDelta;
312             if (isEndSample) {
313                 sampleTime -= static_cast<uint64_t>(timeDelta);
314             }
315         // if timeDeltas[idx - 1] < timeDelta, timeDeltas[idx - 1] = MIN_TIME_DELTA
316         } else if (idx - 1 >= 0) {
317             // The remaining timeDeltas[idx + 1] to reduce
318             profileInfo_->timeDeltas[idx + 1] -= timeDelta - profileInfo_->timeDeltas[idx - 1] + MIN_TIME_DELTA;
319             if (isEndSample) {
320                 sampleTime -= static_cast<uint64_t>(profileInfo_->timeDeltas[idx - 1] - MIN_TIME_DELTA);
321             }
322             profileInfo_->timeDeltas[idx - 1] = MIN_TIME_DELTA;
323         } else {
324             profileInfo_->timeDeltas[idx + 1] -= timeDelta;
325         }
326         profileInfo_->timeDeltas[idx] = MIN_TIME_DELTA;
327     }
328 
329     // if timeDeltas[idx + 1] < 0, timeDeltas equals MIN_TIME_DELTA, timeDeltas[idx] reduce added part
330     if (profileInfo_->timeDeltas[idx + 1] < 0) {
331         int timeDelta = MIN_TIME_DELTA - profileInfo_->timeDeltas[idx];
332         profileInfo_->timeDeltas[idx] -= timeDelta;
333         profileInfo_->timeDeltas[idx + 1] = MIN_TIME_DELTA;
334     }
335 }
336 
GetMethodNodeCount() const337 int SamplesRecord::GetMethodNodeCount() const
338 {
339     return profileInfo_->nodeCount;
340 }
341 
GetSampleData() const342 std::string SamplesRecord::GetSampleData() const
343 {
344     return sampleData_;
345 }
346 
GetMethodInfo(struct MethodKey & methodKey)347 struct FrameInfo SamplesRecord::GetMethodInfo(struct MethodKey &methodKey)
348 {
349     struct FrameInfo entry;
350     auto iter = stackInfoMap_.find(methodKey);
351     if (iter != stackInfoMap_.end()) {
352         entry = iter->second;
353     }
354     return entry;
355 }
356 
AddRunningState(char * functionName,RunningState state,kungfu::DeoptType type)357 std::string SamplesRecord::AddRunningState(char *functionName, RunningState state, kungfu::DeoptType type)
358 {
359     std::string temp = functionName;
360     if (state == RunningState::AOT && type != kungfu::DeoptType::NOTCHECK) {
361         state = RunningState::AINT;
362     }
363     switch (state) {
364         case RunningState::GC:
365             temp.append("(GC)");
366             break;
367         case RunningState::CINT:
368             if (enableVMTag_) {
369                 temp.append("(CINT)");
370             }
371             break;
372         case RunningState::AINT:
373             if (enableVMTag_) {
374                 temp.append("(AINT)");
375             }
376             break;
377         case RunningState::AOT:
378             if (enableVMTag_) {
379                 temp.append("(AOT)");
380             }
381             break;
382         case RunningState::BUILTIN:
383             temp.append("(BUILTIN)");
384             break;
385         case RunningState::NAPI:
386             temp.append("(NAPI)");
387             break;
388         case RunningState::ARKUI_ENGINE:
389             temp.append("(ARKUI_ENGINE)");
390             break;
391         case RunningState::RUNTIME:
392             if (enableVMTag_) {
393                 temp.append("(RUNTIME)");
394             }
395             break;
396         default:
397             temp.append("(OTHER)");
398             break;
399     }
400     if (type != kungfu::DeoptType::NOTCHECK && enableVMTag_) {
401         std::string typeCheckStr = "(DEOPT:" + Deoptimizier::DisplayItems(type) + ")";
402         temp.append(typeCheckStr);
403     }
404     return temp;
405 }
406 
StatisticStateTime(int timeDelta,RunningState state)407 void SamplesRecord::StatisticStateTime(int timeDelta, RunningState state)
408 {
409     switch (state) {
410         case RunningState::GC: {
411             profileInfo_->gcTime += static_cast<uint64_t>(timeDelta);
412             return;
413         }
414         case RunningState::CINT: {
415             profileInfo_->cInterpreterTime += static_cast<uint64_t>(timeDelta);
416             return;
417         }
418         case RunningState::AINT: {
419             profileInfo_->asmInterpreterTime += static_cast<uint64_t>(timeDelta);
420             return;
421         }
422         case RunningState::AOT: {
423             profileInfo_->aotTime += static_cast<uint64_t>(timeDelta);
424             return;
425         }
426         case RunningState::BUILTIN: {
427             profileInfo_->builtinTime += static_cast<uint64_t>(timeDelta);
428             return;
429         }
430         case RunningState::NAPI: {
431             profileInfo_->napiTime += static_cast<uint64_t>(timeDelta);
432             return;
433         }
434         case RunningState::ARKUI_ENGINE: {
435             profileInfo_->arkuiEngineTime += static_cast<uint64_t>(timeDelta);
436             return;
437         }
438         case RunningState::RUNTIME: {
439             profileInfo_->runtimeTime += static_cast<uint64_t>(timeDelta);
440             return;
441         }
442         default: {
443             profileInfo_->otherTime += static_cast<uint64_t>(timeDelta);
444             return;
445         }
446     }
447 }
448 
SetThreadStartTime(uint64_t threadStartTime)449 void SamplesRecord::SetThreadStartTime(uint64_t threadStartTime)
450 {
451     profileInfo_->startTime = threadStartTime;
452 }
453 
SetThreadStopTime()454 void SamplesRecord::SetThreadStopTime()
455 {
456     profileInfo_->stopTime = previousTimeStamp_;
457 }
458 
SetStartsampleData(std::string sampleData)459 void SamplesRecord::SetStartsampleData(std::string sampleData)
460 {
461     sampleData_ += sampleData;
462 }
463 
SetFileName(std::string & fileName)464 void SamplesRecord::SetFileName(std::string &fileName)
465 {
466     fileName_ = fileName;
467 }
468 
GetFileName() const469 const std::string SamplesRecord::GetFileName() const
470 {
471     return fileName_;
472 }
473 
ClearSampleData()474 void SamplesRecord::ClearSampleData()
475 {
476     sampleData_.clear();
477 }
478 
GetProfileInfo()479 std::unique_ptr<struct ProfileInfo> SamplesRecord::GetProfileInfo()
480 {
481     return std::move(profileInfo_);
482 }
483 
SetIsBreakSampleFlag(bool sampleFlag)484 void SamplesRecord::SetIsBreakSampleFlag(bool sampleFlag)
485 {
486     isBreakSample_.store(sampleFlag);
487 }
488 
SetBeforeGetCallNapiStackFlag(bool flag)489 void SamplesRecord::SetBeforeGetCallNapiStackFlag(bool flag)
490 {
491     beforeCallNapi_.store(flag);
492 }
493 
GetBeforeGetCallNapiStackFlag()494 bool SamplesRecord::GetBeforeGetCallNapiStackFlag()
495 {
496     return beforeCallNapi_.load();
497 }
498 
SetAfterGetCallNapiStackFlag(bool flag)499 void SamplesRecord::SetAfterGetCallNapiStackFlag(bool flag)
500 {
501     afterCallNapi_.store(flag);
502 }
503 
GetAfterGetCallNapiStackFlag()504 bool SamplesRecord::GetAfterGetCallNapiStackFlag()
505 {
506     return afterCallNapi_.load();
507 }
508 
SetCallNapiFlag(bool flag)509 void SamplesRecord::SetCallNapiFlag(bool flag)
510 {
511     callNapi_.store(flag);
512 }
513 
GetCallNapiFlag()514 bool SamplesRecord::GetCallNapiFlag()
515 {
516     return callNapi_.load();
517 }
518 
SemInit(int index,int pshared,int value)519 int SamplesRecord::SemInit(int index, int pshared, int value)
520 {
521     return sem_init(&sem_[index], pshared, value);
522 }
523 
SemPost(int index)524 int SamplesRecord::SemPost(int index)
525 {
526     return sem_post(&sem_[index]);
527 }
528 
SemWait(int index)529 int SamplesRecord::SemWait(int index)
530 {
531     return sem_wait(&sem_[index]);
532 }
533 
SemDestroy(int index)534 int SamplesRecord::SemDestroy(int index)
535 {
536     return sem_destroy(&sem_[index]);
537 }
538 
GetStackInfo() const539 const CMap<struct MethodKey, struct FrameInfo> &SamplesRecord::GetStackInfo() const
540 {
541     return stackInfoMap_;
542 }
543 
InsertStackInfo(struct MethodKey & methodKey,struct FrameInfo & codeEntry)544 void SamplesRecord::InsertStackInfo(struct MethodKey &methodKey, struct FrameInfo &codeEntry)
545 {
546     stackInfoMap_.emplace(methodKey, codeEntry);
547 }
548 
PushFrameStack(struct MethodKey & methodKey)549 bool SamplesRecord::PushFrameStack(struct MethodKey &methodKey)
550 {
551     if (UNLIKELY(frameStackLength_ >= MAX_STACK_SIZE)) {
552         return false;
553     }
554     frameStack_[frameStackLength_++] = methodKey;
555     return true;
556 }
557 
PushNapiFrameStack(struct MethodKey & methodKey)558 bool SamplesRecord::PushNapiFrameStack(struct MethodKey &methodKey)
559 {
560     if (UNLIKELY(napiFrameStack_.size() >= MAX_STACK_SIZE)) {
561         return false;
562     }
563     napiFrameStack_.push_back(methodKey);
564     return true;
565 }
566 
ClearNapiStack()567 void SamplesRecord::ClearNapiStack()
568 {
569     napiFrameStack_.clear();
570     napiFrameInfoTemps_.clear();
571 }
572 
ClearNapiCall()573 void SamplesRecord::ClearNapiCall()
574 {
575     napiCallTimeVec_.clear();
576     napiCallAddrVec_.clear();
577 }
578 
GetNapiFrameStackLength()579 int SamplesRecord::GetNapiFrameStackLength()
580 {
581     return napiFrameStack_.size();
582 }
583 
GetGcState() const584 bool SamplesRecord::GetGcState() const
585 {
586     return gcState_.load();
587 }
588 
SetGcState(bool gcState)589 void SamplesRecord::SetGcState(bool gcState)
590 {
591     gcState_.store(gcState);
592 }
593 
GetRuntimeState() const594 bool SamplesRecord::GetRuntimeState() const
595 {
596     return runtimeState_.load();
597 }
598 
SetRuntimeState(bool runtimeState)599 void SamplesRecord::SetRuntimeState(bool runtimeState)
600 {
601     runtimeState_.store(runtimeState);
602 }
603 
GetIsStart() const604 bool SamplesRecord::GetIsStart() const
605 {
606     return isStart_.load();
607 }
608 
SetIsStart(bool isStart)609 void SamplesRecord::SetIsStart(bool isStart)
610 {
611     isStart_.store(isStart);
612 }
613 
PushStackInfo(const FrameInfoTemp & frameInfoTemp)614 bool SamplesRecord::PushStackInfo(const FrameInfoTemp &frameInfoTemp)
615 {
616     if (UNLIKELY(frameInfoTempLength_ >= MAX_STACK_SIZE)) {
617         return false;
618     }
619     frameInfoTemps_[frameInfoTempLength_++] = frameInfoTemp;
620     return true;
621 }
622 
PushNapiStackInfo(const FrameInfoTemp & frameInfoTemp)623 bool SamplesRecord::PushNapiStackInfo(const FrameInfoTemp &frameInfoTemp)
624 {
625     if (UNLIKELY(napiFrameInfoTemps_.size() == MAX_STACK_SIZE)) {
626         return false;
627     }
628     napiFrameInfoTemps_.push_back(frameInfoTemp);
629     return true;
630 }
631 
FrameInfoTempToMap(FrameInfoTemp * frameInfoTemps,int frameInfoTempLength)632 void SamplesRecord::FrameInfoTempToMap(FrameInfoTemp *frameInfoTemps, int frameInfoTempLength)
633 {
634     if (frameInfoTempLength == 0) {
635         return;
636     }
637     struct FrameInfo frameInfo;
638     for (int i = 0; i < frameInfoTempLength; ++i) {
639         frameInfo.url = frameInfoTemps[i].url;
640         auto iter = scriptIdMap_.find(frameInfo.url);
641         if (iter == scriptIdMap_.end()) {
642             scriptIdMap_.emplace(frameInfo.url, scriptIdMap_.size() + 1);
643             frameInfo.scriptId = static_cast<int>(scriptIdMap_.size());
644         } else {
645             frameInfo.scriptId = iter->second;
646         }
647         frameInfo.functionName = AddRunningState(frameInfoTemps[i].functionName,
648                                                  frameInfoTemps[i].methodKey.state,
649                                                  frameInfoTemps[i].methodKey.deoptType);
650         frameInfo.codeType = frameInfoTemps[i].codeType;
651         frameInfo.columnNumber = frameInfoTemps[i].columnNumber;
652         frameInfo.lineNumber = frameInfoTemps[i].lineNumber;
653         stackInfoMap_.emplace(frameInfoTemps[i].methodKey, frameInfo);
654     }
655     frameInfoTempLength_ = 0;
656 }
657 
NapiFrameInfoTempToMap()658 void SamplesRecord::NapiFrameInfoTempToMap()
659 {
660     size_t length = napiFrameInfoTemps_.size();
661     if (length == 0) {
662         return;
663     }
664     struct FrameInfo frameInfo;
665     for (size_t i = 0; i < length; ++i) {
666         frameInfo.url = napiFrameInfoTemps_[i].url;
667         auto iter = scriptIdMap_.find(frameInfo.url);
668         if (iter == scriptIdMap_.end()) {
669             scriptIdMap_.emplace(frameInfo.url, scriptIdMap_.size() + 1);
670             frameInfo.scriptId = static_cast<int>(scriptIdMap_.size());
671         } else {
672             frameInfo.scriptId = iter->second;
673         }
674         frameInfo.functionName = AddRunningState(napiFrameInfoTemps_[i].functionName,
675                                                  napiFrameInfoTemps_[i].methodKey.state,
676                                                  napiFrameInfoTemps_[i].methodKey.deoptType);
677         frameInfo.codeType = napiFrameInfoTemps_[i].codeType;
678         frameInfo.columnNumber = napiFrameInfoTemps_[i].columnNumber;
679         frameInfo.lineNumber = napiFrameInfoTemps_[i].lineNumber;
680         stackInfoMap_.emplace(napiFrameInfoTemps_[i].methodKey, frameInfo);
681     }
682 }
683 
GetframeStackLength() const684 int SamplesRecord::GetframeStackLength() const
685 {
686     return frameStackLength_;
687 }
688 
RecordCallNapiTime(uint64_t currentTime)689 void SamplesRecord::RecordCallNapiTime(uint64_t currentTime)
690 {
691     napiCallTimeVec_.emplace_back(currentTime);
692 }
693 
RecordCallNapiAddr(const std::string & methodAddr)694 void SamplesRecord::RecordCallNapiAddr(const std::string &methodAddr)
695 {
696     napiCallAddrVec_.emplace_back(methodAddr);
697 }
698 
PostFrame()699 void SamplesRecord::PostFrame()
700 {
701     samplesQueue_->PostFrame(frameInfoTemps_, frameStack_, frameInfoTempLength_, frameStackLength_);
702 }
703 
PostNapiFrame()704 void SamplesRecord::PostNapiFrame()
705 {
706     samplesQueue_->PostNapiFrame(napiFrameInfoTemps_, napiFrameStack_);
707 }
708 
ResetFrameLength()709 void SamplesRecord::ResetFrameLength()
710 {
711     frameStackLength_ = 0;
712     frameInfoTempLength_ = 0;
713 }
714 
GetCallTimeStamp()715 uint64_t SamplesRecord::GetCallTimeStamp()
716 {
717     return callTimeStamp_;
718 }
719 
SetCallTimeStamp(uint64_t timeStamp)720 void SamplesRecord::SetCallTimeStamp(uint64_t timeStamp)
721 {
722     callTimeStamp_ = timeStamp;
723 }
724 
725 // SamplesQueue
PostFrame(FrameInfoTemp * frameInfoTemps,MethodKey * frameStack,int frameInfoTempsLength,int frameStackLength)726 void SamplesQueue::PostFrame(FrameInfoTemp *frameInfoTemps, MethodKey *frameStack,
727                              int frameInfoTempsLength, int frameStackLength)
728 {
729     os::memory::LockHolder holder(mtx_);
730     if (!IsFull()) {
731         // frameInfoTemps
732         for (int i = 0; i < frameInfoTempsLength; i++) {
733             CheckAndCopy(frames_[rear_].frameInfoTemps[i].functionName,
734                 sizeof(frames_[rear_].frameInfoTemps[i].functionName), frameInfoTemps[i].functionName);
735             frames_[rear_].frameInfoTemps[i].columnNumber = frameInfoTemps[i].columnNumber;
736             frames_[rear_].frameInfoTemps[i].lineNumber = frameInfoTemps[i].lineNumber;
737             frames_[rear_].frameInfoTemps[i].scriptId = frameInfoTemps[i].scriptId;
738             CheckAndCopy(frames_[rear_].frameInfoTemps[i].url,
739                 sizeof(frames_[rear_].frameInfoTemps[i].url), frameInfoTemps[i].url);
740             frames_[rear_].frameInfoTemps[i].methodKey.methodIdentifier = frameInfoTemps[i].methodKey.methodIdentifier;
741             frames_[rear_].frameInfoTemps[i].methodKey.state = frameInfoTemps[i].methodKey.state;
742         }
743         // frameStack
744         for (int i = 0; i < frameStackLength; i++) {
745             frames_[rear_].frameStack[i].methodIdentifier = frameStack[i].methodIdentifier;
746             frames_[rear_].frameStack[i].state = frameStack[i].state;
747         }
748         // frameStackLength
749         frames_[rear_].frameStackLength = frameStackLength;
750         // frameInfoTempsLength
751         frames_[rear_].frameInfoTempsLength = frameInfoTempsLength;
752         // timeStamp
753         frames_[rear_].timeStamp = lastPostTime_ = SamplingProcessor::GetMicrosecondsTimeStamp();
754 
755         rear_ = (rear_ + 1) % QUEUE_CAPACITY;
756     }
757 }
758 
PostNapiFrame(CVector<FrameInfoTemp> & napiFrameInfoTemps,CVector<MethodKey> & napiFrameStack)759 void SamplesQueue::PostNapiFrame(CVector<FrameInfoTemp> &napiFrameInfoTemps,
760                                  CVector<MethodKey> &napiFrameStack)
761 {
762     os::memory::LockHolder holder(mtx_);
763     if (!IsFull()) {
764         int frameInfoTempsLength = static_cast<int>(napiFrameInfoTemps.size());
765         int frameStackLength = static_cast<int>(napiFrameStack.size());
766         // napiFrameInfoTemps
767         for (int i = 0; i < frameInfoTempsLength; i++) {
768             CheckAndCopy(frames_[rear_].frameInfoTemps[i].functionName,
769                 sizeof(frames_[rear_].frameInfoTemps[i].functionName), napiFrameInfoTemps[i].functionName);
770             frames_[rear_].frameInfoTemps[i].columnNumber = napiFrameInfoTemps[i].columnNumber;
771             frames_[rear_].frameInfoTemps[i].lineNumber = napiFrameInfoTemps[i].lineNumber;
772             frames_[rear_].frameInfoTemps[i].scriptId = napiFrameInfoTemps[i].scriptId;
773             CheckAndCopy(frames_[rear_].frameInfoTemps[i].url,
774                 sizeof(frames_[rear_].frameInfoTemps[i].url), napiFrameInfoTemps[i].url);
775             frames_[rear_].frameInfoTemps[i].methodKey.methodIdentifier =
776                 napiFrameInfoTemps[i].methodKey.methodIdentifier;
777             frames_[rear_].frameInfoTemps[i].methodKey.state = napiFrameInfoTemps[i].methodKey.state;
778         }
779         // napiFrameStack
780         for (int i = 0; i < frameStackLength; i++) {
781             frames_[rear_].frameStack[i].methodIdentifier = napiFrameStack[i].methodIdentifier;
782             frames_[rear_].frameStack[i].state = napiFrameStack[i].state;
783         }
784         // frameStackLength
785         frames_[rear_].frameStackLength = frameStackLength;
786         // frameInfoTempsLength
787         frames_[rear_].frameInfoTempsLength = frameInfoTempsLength;
788         // timeStamp
789         frames_[rear_].timeStamp = lastPostTime_ = SamplingProcessor::GetMicrosecondsTimeStamp();
790 
791         rear_ = (rear_ + 1) % QUEUE_CAPACITY;
792     }
793 }
794 
PopFrame()795 FrameStackAndInfo *SamplesQueue::PopFrame()
796 {
797     os::memory::LockHolder holder(mtx_);
798     if (!IsEmpty()) {
799         FrameStackAndInfo *frame = &frames_[front_];
800         front_ = (front_ + 1) % QUEUE_CAPACITY;
801         return frame;
802     }
803     return nullptr;
804 }
805 
IsEmpty()806 bool SamplesQueue::IsEmpty()
807 {
808     return front_ == rear_;
809 }
810 
IsFull()811 bool SamplesQueue::IsFull()
812 {
813     return (rear_ + 1) % QUEUE_CAPACITY == front_;
814 }
815 
GetSize()816 int SamplesQueue::GetSize()
817 {
818     return (rear_ + QUEUE_CAPACITY - front_) % QUEUE_CAPACITY;
819 }
820 
GetFrontIndex()821 int SamplesQueue::GetFrontIndex()
822 {
823     return front_;
824 }
825 
GetRearIndex()826 int SamplesQueue::GetRearIndex()
827 {
828     return rear_;
829 }
830 
CheckAndCopy(char * dest,size_t length,const char * src) const831 bool SamplesQueue::CheckAndCopy(char *dest, size_t length, const char *src) const
832 {
833     int srcLength = strlen(src);
834     if (length <= static_cast<size_t>(srcLength) || strcpy_s(dest, srcLength + 1, src) != EOK) {
835         LOG_ECMA(ERROR) << "SamplesQueue PostFrame strcpy_s failed, maybe srcLength more than destLength";
836         return false;
837     }
838     dest[srcLength] = '\0';
839     return true;
840 }
841 
GetFront()842 FrameStackAndInfo SamplesQueue::GetFront()
843 {
844     return frames_[front_];
845 }
846 
GetRear()847 FrameStackAndInfo SamplesQueue::GetRear()
848 {
849     return frames_[rear_];
850 }
GetLastPostTime()851 uint64_t SamplesQueue::GetLastPostTime()
852 {
853     return lastPostTime_;
854 }
855 } // namespace panda::ecmascript
856