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