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