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_CPU_PROFILER_H 17 #define ECMASCRIPT_CPU_PROFILER_H 18 19 #include <csignal> 20 21 #include "ecmascript/dfx/cpu_profiler/samples_record.h" 22 #include "ecmascript/interpreter/frame_handler.h" 23 #include "ecmascript/js_thread.h" 24 25 #include "os/mutex.h" 26 27 namespace panda::ecmascript { 28 using JSTaggedType = uint64_t; 29 class SamplesRecord; 30 31 struct CurrentProcessInfo { 32 uint64_t nowTimeStamp = 0; 33 uint64_t tts = 0; 34 pid_t pid = 0; 35 pthread_t tid = 0; 36 }; 37 38 class GcStateScope { 39 public: GcStateScope(JSThread * thread)40 inline explicit GcStateScope(JSThread *thread) 41 { 42 thread_ = thread; 43 thread_->SetGcState(true); 44 } 45 ~GcStateScope()46 inline ~GcStateScope() 47 { 48 thread_->SetGcState(false); 49 } 50 private: 51 JSThread *thread_ = nullptr; 52 }; 53 54 class RuntimeStateScope { 55 public: RuntimeStateScope(JSThread * thread)56 inline explicit RuntimeStateScope(JSThread *thread) 57 { 58 thread_ = thread; 59 oldState_ = thread_->GetRuntimeState(); 60 thread_->SetRuntimeState(true); 61 } 62 ~RuntimeStateScope()63 inline ~RuntimeStateScope() 64 { 65 thread_->SetRuntimeState(oldState_); 66 } 67 private: 68 bool oldState_ = false; 69 JSThread *thread_ = nullptr; 70 }; 71 72 class CpuProfiler { 73 public: 74 static const int CPUPROFILER_DEFAULT_INTERVAL = 500; // 500:Default Sampling interval 500 microseconds 75 static const int INTERVAL_OF_ACTIVE_SAMPLING = 300; // 300:interval of active sampling 76 77 bool InHeaderOrTail(uint64_t pc, uint64_t entryBegin, uint64_t entryDuration, uint64_t headerSize, 78 uint64_t tailSize) const; 79 bool IsEntryFrameHeaderOrTail(JSThread *thread, uint64_t pc) const; 80 void GetStackCallNapi(JSThread *thread, bool beforeCallNapi); 81 static void GetStackSignalHandler(int signal, siginfo_t *siginfo, void *context); 82 83 void StartCpuProfilerForInfo(); 84 std::unique_ptr<struct ProfileInfo> StopCpuProfilerForInfo(); 85 void StartCpuProfilerForFile(const std::string &fileName); 86 void StopCpuProfilerForFile(); 87 void SetCpuSamplingInterval(int interval); 88 void SetCallNapiGetStack(bool getStack); 89 void RecordCallNapiInfo(const std::string &methodAddr); 90 void SetBuildNapiStack(bool flag); 91 bool GetBuildNapiStack(); 92 explicit CpuProfiler(const EcmaVM *vm, const int interval = CPUPROFILER_DEFAULT_INTERVAL); 93 virtual ~CpuProfiler(); 94 95 static CMap<pthread_t, const EcmaVM *> profilerMap_; 96 private: 97 static os::memory::Mutex synchronizationMutex_; 98 99 void GetStack(FrameIterator &it); 100 bool ParseMethodInfo(struct MethodKey &methodKey, const FrameIterator &it, 101 const JSPandaFile *jsPandaFile, bool isCallNapi); 102 void GetNativeStack(const FrameIterator &it, char *functionName, size_t size); 103 static uint64_t GetPcFromContext(void *context); 104 bool IsAddrAtStubOrAot(uint64_t pc) const; 105 bool CheckFrameType(JSThread *thread, JSTaggedType *sp); 106 void SetProfileStart(uint64_t nowTimeStamp); 107 void GetCurrentProcessInfo(struct CurrentProcessInfo ¤tProcessInfo); 108 bool CheckFileName(const std::string &fileName, std::string &absoluteFilePath) const; 109 bool CheckAndCopy(char *dest, size_t length, const char *src) const; 110 void GetNativeMethodCallPos(FrameIterator &it, FrameInfoTemp &codeEntry); 111 void *GetMethodIdentifier(Method *method, const FrameIterator &it); 112 RunningState GetRunningState(const FrameIterator &it, const JSPandaFile *jsPandaFile, bool topFrame) const; 113 bool isProfiling_ = false; 114 bool outToFile_ = false; 115 std::string fileName_ = ""; 116 SamplesRecord *generator_ = nullptr; 117 pthread_t tid_ = 0; 118 const EcmaVM *vm_ = nullptr; 119 uint32_t interval_ = 0; 120 bool callNapiGetStack_ = true; 121 uint64_t beforeCallNapiTimeStamp_ = 0; 122 std::atomic_bool isBuildNapiStack_ {false}; 123 }; 124 125 class CallNapiScope { 126 public: CallNapiScope(CpuProfiler * profiler)127 inline explicit CallNapiScope(CpuProfiler *profiler) 128 { 129 profiler_ = profiler; 130 profiler_->SetBuildNapiStack(true); 131 } 132 ~CallNapiScope()133 inline ~CallNapiScope() 134 { 135 profiler_->SetBuildNapiStack(false); 136 } 137 private: 138 CpuProfiler *profiler_ {nullptr}; 139 }; 140 } // namespace panda::ecmascript 141 #endif // ECMASCRIPT_CPU_PROFILE_H