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