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_CPU_PROFILER_H 17 #define ECMASCRIPT_DFX_CPU_PROFILER_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 const int THRESHOLD_GROWTH_FACTORY = 2; // 2:TimeDelta Threshold Growth Factory 29 const int THRESHOLD_FIXED_INCREMENT = 2000; // 2000:TimeDelta Threshold Fixed Increment 30 using JSTaggedType = uint64_t; 31 class SamplesRecord; 32 33 struct CurrentProcessInfo { 34 uint64_t nowTimeStamp = 0; 35 uint64_t tts = 0; 36 pid_t pid = 0; 37 pthread_t tid = 0; 38 }; 39 40 class GcStateScope { 41 public: GcStateScope(JSThread * thread)42 inline explicit GcStateScope(JSThread *thread) 43 { 44 thread_ = thread; 45 thread_->SetGcState(true); 46 } 47 ~GcStateScope()48 inline ~GcStateScope() 49 { 50 thread_->SetGcState(false); 51 } 52 private: 53 JSThread *thread_ = nullptr; 54 }; 55 56 class RuntimeStateScope { 57 public: RuntimeStateScope(JSThread * thread)58 inline explicit RuntimeStateScope(JSThread *thread) 59 { 60 thread_ = thread; 61 oldState_ = thread_->GetRuntimeState(); 62 thread_->SetRuntimeState(true); 63 } 64 ~RuntimeStateScope()65 inline ~RuntimeStateScope() 66 { 67 thread_->SetRuntimeState(oldState_); 68 } 69 private: 70 bool oldState_ = false; 71 JSThread *thread_ = nullptr; 72 }; 73 74 class CpuProfiler { 75 public: 76 static const int CPUPROFILER_DEFAULT_INTERVAL = 500; // 500:Default Sampling interval 500 microseconds 77 static const int INTERVAL_OF_ACTIVE_SAMPLING = 300; // 300:interval of active sampling 78 static const int INTERVAL_OF_INNER_START = 100; // 100:interval of inner start(stake in runtime) sampling 79 80 bool InHeaderOrTail(uint64_t pc, uint64_t entryBegin, uint64_t entryDuration, uint64_t headerSize, 81 uint64_t tailSize) const; 82 bool IsEntryFrameHeaderOrTail(JSThread *thread, uint64_t pc) const; 83 bool GetStackBeforeCallNapi(JSThread *thread); 84 void GetStackAfterCallNapi(JSThread *thread); 85 bool GetStackCallNapi(JSThread *thread, bool beforeCallNapi); 86 static void GetStackSignalHandler(int signal, siginfo_t *siginfo, void *context); 87 88 void StartCpuProfilerForInfo(); 89 std::unique_ptr<struct ProfileInfo> StopCpuProfilerForInfo(); 90 void StartCpuProfilerForFile(const std::string &fileName); 91 void StopCpuProfilerForFile(); 92 void SetCpuSamplingInterval(int interval); 93 void RecordCallNapiInfo(const std::string &methodAddr); 94 void SetBuildNapiStack(bool flag); 95 bool GetBuildNapiStack(); 96 explicit CpuProfiler(const EcmaVM *vm, const int interval = CPUPROFILER_DEFAULT_INTERVAL); 97 virtual ~CpuProfiler(); 98 99 static CMap<pthread_t, const EcmaVM *> profilerMap_; 100 private: 101 static os::memory::Mutex synchronizationMutex_; 102 103 void GetStack(FrameIterator &it); 104 static uint64_t GetPcFromContext(void *context); 105 bool IsAddrAtStubOrAot(uint64_t pc) const; 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 isProfiling_ = false; 110 bool outToFile_ = false; 111 std::string fileName_ = ""; 112 SamplesRecord *generator_ = nullptr; 113 pthread_t tid_ = 0; 114 const EcmaVM *vm_ = nullptr; 115 uint32_t interval_ = 0; 116 uint64_t beforeCallNapiTimeStamp_ = 0; 117 std::atomic_bool isBuildNapiStack_ {false}; 118 bool enableVMTag_ {false}; 119 }; 120 121 class CallNapiScope { 122 public: CallNapiScope(CpuProfiler * profiler)123 inline explicit CallNapiScope(CpuProfiler *profiler) 124 { 125 profiler_ = profiler; 126 profiler_->SetBuildNapiStack(true); 127 } 128 ~CallNapiScope()129 inline ~CallNapiScope() 130 { 131 profiler_->SetBuildNapiStack(false); 132 } 133 private: 134 CpuProfiler *profiler_ {nullptr}; 135 }; 136 } // namespace panda::ecmascript 137 #endif // ECMASCRIPT_DFX_CPU_PROFILER_CPU_PROFILER_H