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