• 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 #ifndef ECMASCRIPT_SAMPLES_RECORD_H
17 #define ECMASCRIPT_SAMPLES_RECORD_H
18 
19 #include <atomic>
20 #include <ctime>
21 #include <cstring>
22 #include <fstream>
23 #include <semaphore.h>
24 
25 #include "ecmascript/compiler/gate_meta_data.h"
26 #include "ecmascript/deoptimizer/deoptimizer.h"
27 #include "ecmascript/js_thread.h"
28 #include "ecmascript/jspandafile/method_literal.h"
29 #include "ecmascript/mem/c_containers.h"
30 #include "libpandabase/os/mutex.h"
31 
32 namespace panda::ecmascript {
33 const int MAX_STACK_SIZE = 128; // 128:the maximum size of the js stack
34 const int MAX_NODE_COUNT = 20000; // 20000:the maximum size of the array
35 const int MIN_TIME_DELTA = 10; // 10: the minimum value of the time delta
36 const int QUEUE_CAPACITY = 51; // the capacity of the circular queue is QUEUE_CAPACITY - 1
37 const size_t NAPI_CALL_SETP = 2; // 2: step size of the variable napiCallIdx in while loop
38 const size_t PRE_IDX_RANGE = 5; // 5: length of variable preIdx looping backward
39 enum class RunningState : size_t {
40     OTHER = 0,
41     GC,
42     CINT,
43     AINT,
44     AOT,
45     BUILTIN,
46     NAPI,
47     ARKUI_ENGINE,
48     RUNTIME
49 };
50 
51 struct MethodKey {
52     void *methodIdentifier = nullptr;
53     RunningState state = RunningState::OTHER;
54     kungfu::DeoptType deoptType = kungfu::DeoptType::NOTCHECK;
55     bool operator < (const MethodKey &methodKey) const
56     {
57         return state < methodKey.state ||
58                (state == methodKey.state && methodIdentifier < methodKey.methodIdentifier) ||
59                (state == methodKey.state && methodIdentifier == methodKey.methodIdentifier &&
60                deoptType < methodKey.deoptType);
61     }
62 };
63 
64 struct NodeKey {
65     struct MethodKey methodKey = {0};
66     int parentId = 0;
67     bool operator < (const NodeKey &nodeKey) const
68     {
69         return parentId < nodeKey.parentId ||
70                (parentId == nodeKey.parentId && methodKey < nodeKey.methodKey);
71     }
72 };
73 
74 struct FrameInfo {
75     std::string codeType = "";
76     std::string functionName = "";
77     int columnNumber = 0;
78     int lineNumber = 0;
79     int scriptId = 0;
80     std::string url = "";
81 };
82 
83 struct CpuProfileNode {
84     int id = 0;
85     int parentId = 0;
86     int hitCount = 0;
87     struct FrameInfo codeEntry;
88     CVector<int> children;
89 };
90 
91 struct ProfileInfo {
92     uint64_t tid = 0;
93     uint64_t startTime = 0;
94     uint64_t stopTime = 0;
95     struct CpuProfileNode nodes[MAX_NODE_COUNT];
96     int nodeCount = 0;
97     CVector<int> samples;
98     CVector<int> timeDeltas;
99     // state time statistic
100     uint64_t gcTime = 0;
101     uint64_t cInterpreterTime = 0;
102     uint64_t asmInterpreterTime = 0;
103     uint64_t aotTime = 0;
104     uint64_t builtinTime = 0;
105     uint64_t napiTime = 0;
106     uint64_t arkuiEngineTime = 0;
107     uint64_t runtimeTime = 0;
108     uint64_t otherTime = 0;
109 };
110 
111 struct FrameInfoTemp {
112     char codeType[20] = {0}; // 20:the maximum size of the codeType
113     char functionName[100] = {0}; // 100:the maximum size of the functionName
114     int columnNumber = 0;
115     int lineNumber = 0;
116     int scriptId = 0;
117     char url[500] = {0}; // 500:the maximum size of the url
118     struct MethodKey methodKey = {0};
119 };
120 
121 struct FrameStackAndInfo {
122     struct FrameInfoTemp frameInfoTemps[MAX_STACK_SIZE] = {};
123     struct MethodKey frameStack[MAX_STACK_SIZE] = {};
124     int frameInfoTempsLength {};
125     int frameStackLength {};
126     uint64_t timeStamp {};
127 };
128 
129 class SamplesQueue {
130 public:
131     SamplesQueue() = default;
132     ~SamplesQueue() = default;
133 
134     NO_COPY_SEMANTIC(SamplesQueue);
135     NO_MOVE_SEMANTIC(SamplesQueue);
136 
137     void PostFrame(FrameInfoTemp *frameInfoTemps, MethodKey *frameStack,
138                    int frameInfoTempsLength, int frameStackLength);
139     void PostNapiFrame(CVector<FrameInfoTemp> &napiFrameInfoTemps,
140                        CVector<MethodKey> &napiFrameStack);
141     FrameStackAndInfo *PopFrame();
142     bool IsEmpty();
143     bool IsFull();
144     int GetSize();
145     int GetFrontIndex();
146     int GetRearIndex();
147     bool CheckAndCopy(char *dest, size_t length, const char *src) const;
148     FrameStackAndInfo GetFront();
149     FrameStackAndInfo GetRear();
150     uint64_t GetLastPostTime();
151 
152 private:
153     FrameStackAndInfo frames_[QUEUE_CAPACITY] = {};
154     int front_ = 0;
155     int rear_ = 0;
156     os::memory::Mutex mtx_;
157     uint64_t lastPostTime_ = 0;
158 };
159 
160 class SamplesRecord {
161 public:
162     explicit SamplesRecord();
163     virtual ~SamplesRecord();
164 
165     void AddSample(FrameStackAndInfo *frame);
166     void AddRootSample();
167     void StringifySampleData();
168     int GetMethodNodeCount() const;
169     int GetframeStackLength() const;
170     std::string GetSampleData() const;
171     void SetThreadStartTime(uint64_t threadStartTime);
172     void SetThreadStopTime();
173     void SetStartsampleData(std::string sampleData);
174     void SetFileName(std::string &fileName);
175     const std::string GetFileName() const;
176     void ClearSampleData();
177     std::unique_ptr<struct ProfileInfo> GetProfileInfo();
178     bool GetIsStart() const;
179     void SetIsStart(bool isStart);
180     bool GetGcState() const;
181     void SetGcState(bool gcState);
182     bool GetRuntimeState() const;
183     void SetRuntimeState(bool runtimeState);
184     void SetIsBreakSampleFlag(bool sampleFlag);
185     int SemInit(int index, int pshared, int value);
186     int SemPost(int index);
187     int SemWait(int index);
188     int SemDestroy(int index);
189     const CMap<struct MethodKey, struct FrameInfo> &GetStackInfo() const;
190     void InsertStackInfo(struct MethodKey &methodKey, struct FrameInfo &codeEntry);
191     bool PushFrameStack(struct MethodKey &methodKey);
192     bool PushStackInfo(const FrameInfoTemp &frameInfoTemp);
193     bool GetBeforeGetCallNapiStackFlag();
194     void SetBeforeGetCallNapiStackFlag(bool flag);
195     bool GetAfterGetCallNapiStackFlag();
196     void SetAfterGetCallNapiStackFlag(bool flag);
197     bool GetCallNapiFlag();
198     void SetCallNapiFlag(bool flag);
199     bool PushNapiFrameStack(struct MethodKey &methodKey);
200     bool PushNapiStackInfo(const FrameInfoTemp &frameInfoTemp);
201     int GetNapiFrameStackLength();
202     void ClearNapiStack();
203     void ClearNapiCall();
204     void RecordCallNapiTime(uint64_t currentTime);
205     void RecordCallNapiAddr(const std::string &methodAddrName);
206     void FinetuneSampleData();
207     void FindSampleAndFinetune(size_t findIdx, size_t napiCallIdx, size_t &sampleIdx,
208                                uint64_t startSampleTime, uint64_t &sampleTime);
209     void FinetuneTimeDeltas(size_t idx, uint64_t napiTime, uint64_t &sampleTime, bool isEndSample);
210     void PostFrame();
211     void PostNapiFrame();
212     void ResetFrameLength();
213     uint64_t GetCallTimeStamp();
214     void SetCallTimeStamp(uint64_t timeStamp);
215     std::ofstream fileHandle_;
216     SamplesQueue *samplesQueue_ {nullptr};
217 
SetEnableVMTag(bool flag)218     void SetEnableVMTag(bool flag)
219     {
220         enableVMTag_ = flag;
221     }
222 
223 private:
224     void StringifyStateTimeStatistic();
225     void StringifyNodes();
226     void StringifySamples();
227     struct FrameInfo GetMethodInfo(struct MethodKey &methodKey);
228     std::string AddRunningState(char *functionName, RunningState state, kungfu::DeoptType type);
229     void FrameInfoTempToMap(FrameInfoTemp *frameInfoTemps, int frameInfoTempLength);
230     void NapiFrameInfoTempToMap();
231     void StatisticStateTime(int timeDelta, RunningState state);
232 
233     int previousId_ = 0;
234     RunningState previousState_ = RunningState::OTHER;
235     uint64_t previousTimeStamp_ = 0;
236     std::atomic_bool isBreakSample_ = false;
237     std::atomic_bool gcState_ = false;
238     std::atomic_bool runtimeState_ = false;
239     std::atomic_bool isStart_ = false;
240     std::atomic_bool beforeCallNapi_ = false;
241     std::atomic_bool afterCallNapi_ = false;
242     std::atomic_bool callNapi_ = false;
243     std::unique_ptr<struct ProfileInfo> profileInfo_;
244     CVector<int> stackTopLines_;
245     CMap<struct NodeKey, int> nodeMap_;
246     std::string sampleData_ = "";
247     std::string fileName_ = "";
248     sem_t sem_[3]; // 3 : sem_ size is three.
249     CMap<struct MethodKey, struct FrameInfo> stackInfoMap_;
250     struct MethodKey frameStack_[MAX_STACK_SIZE] = {};
251     int frameStackLength_ = 0;
252     CMap<std::string, int> scriptIdMap_;
253     FrameInfoTemp frameInfoTemps_[MAX_STACK_SIZE] = {};
254     int frameInfoTempLength_ = 0;
255     // napi stack
256     CVector<struct MethodKey> napiFrameStack_;
257     CVector<FrameInfoTemp> napiFrameInfoTemps_;
258     CVector<uint64_t> napiCallTimeVec_;
259     CVector<std::string> napiCallAddrVec_;
260     bool enableVMTag_ {false};
261     uint64_t callTimeStamp_ = 0;
262 };
263 } // namespace panda::ecmascript
264 #endif // ECMASCRIPT_SAMPLES_RECORD_H