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