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