1 /* 2 * Copyright (c) 2021-2025 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 PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLING_PROFILER_H 17 #define PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLING_PROFILER_H 18 19 #include <atomic> 20 #include <csignal> 21 22 #include "libpandabase/macros.h" 23 #include "libpandabase/os/pipe.h" 24 #include "runtime/include/panda_vm.h" 25 #include "runtime/include/runtime_notification.h" 26 #include "runtime/include/mem/panda_containers.h" 27 28 #include "runtime/tooling/sampler/sample_info.h" 29 #include "runtime/tooling/sampler/sample_writer.h" 30 #include "runtime/tooling/sampler/samples_record.h" 31 #include "runtime/tooling/sampler/thread_communicator.h" 32 #include "runtime/tooling/sampler/lock_free_queue.h" 33 34 namespace ark::tooling::sampler { 35 36 namespace test { 37 class SamplerTest; 38 } // namespace test 39 40 // Panda sampling profiler 41 class Sampler final : public RuntimeListener { 42 public: 43 ~Sampler() override = default; 44 45 static PANDA_PUBLIC_API Sampler *Create(); 46 static PANDA_PUBLIC_API void Destroy(Sampler *sampler); 47 48 // Need to get comunicator inside the signal handler GetSampleCommunicator()49 static const ThreadCommunicator &GetSampleCommunicator() 50 { 51 ASSERT(instance_ != nullptr); 52 return instance_->GetCommunicator(); 53 } 54 GetCommunicator()55 const ThreadCommunicator &GetCommunicator() const 56 { 57 return communicator_; 58 } 59 GetSampleQueuePF()60 static const LockFreeQueue &GetSampleQueuePF() 61 { 62 ASSERT(instance_ != nullptr); 63 return instance_->GetQueuePF(); 64 } 65 GetQueuePF()66 const LockFreeQueue &GetQueuePF() 67 { 68 return loadedPfsQueue_; 69 } 70 SetSampleInterval(uint32_t us)71 void SetSampleInterval(uint32_t us) 72 { 73 // Atomic with acquire order reason: To ensure start/stop load correctly 74 ASSERT(isActive_.load(std::memory_order_acquire) == false); 75 sampleInterval_ = static_cast<std::chrono::microseconds>(us); 76 } 77 SetSegvHandlerStatus(bool segvHandlerStatus)78 void SetSegvHandlerStatus(bool segvHandlerStatus) 79 { 80 isSegvHandlerEnable_ = segvHandlerStatus; 81 } 82 IsSegvHandlerEnable()83 bool IsSegvHandlerEnable() const 84 { 85 return isSegvHandlerEnable_; 86 } 87 88 PANDA_PUBLIC_API bool Start(std::unique_ptr<StreamWriter> &&writer); 89 PANDA_PUBLIC_API bool Stop(); 90 91 // Events: Notify profiler that managed thread created or finished 92 void ThreadStart(ManagedThread *managedThread) override; 93 void ThreadEnd(ManagedThread *managedThread) override; 94 void LoadModule(std::string_view name) override; 95 static PANDA_PUBLIC_API uint64_t GetMicrosecondsTimeStamp(); 96 97 static constexpr uint32_t DEFAULT_SAMPLE_INTERVAL_US = 500; 98 99 private: 100 explicit Sampler(); 101 102 void SamplerThreadEntry(); 103 void ListenerThreadEntry(std::unique_ptr<StreamWriter> writerPtr); 104 105 void AddThreadHandle(ManagedThread *thread); 106 void EraseThreadHandle(ManagedThread *thread); 107 108 void CollectThreads(); 109 void CollectModules(); 110 111 void WriteLoadedPandaFiles(StreamWriter *writerPtr); 112 ClearManagedThreadSet()113 void ClearManagedThreadSet() 114 { 115 os::memory::LockHolder holder(managedThreadsLock_); 116 managedThreads_.clear(); 117 } 118 ClearLoadedPfs()119 void ClearLoadedPfs() 120 { 121 os::memory::LockHolder holder(loadedPfsLock_); 122 loadedPfs_.clear(); 123 } 124 125 static Sampler *instance_; 126 127 Runtime *runtime_ {nullptr}; 128 // Remember agent thread id for security 129 os::thread::NativeHandleType listenerTid_ {0}; 130 os::thread::NativeHandleType samplerTid_ {0}; 131 std::unique_ptr<std::thread> samplerThread_ {nullptr}; 132 std::unique_ptr<std::thread> listenerThread_ {nullptr}; 133 ThreadCommunicator communicator_; 134 135 std::atomic<bool> isActive_ {false}; 136 bool isSegvHandlerEnable_ {true}; 137 138 PandaSet<os::thread::ThreadId> managedThreads_ GUARDED_BY(managedThreadsLock_); 139 os::memory::Mutex managedThreadsLock_; 140 141 LockFreeQueue loadedPfsQueue_; 142 143 PandaVector<FileInfo> loadedPfs_ GUARDED_BY(loadedPfsLock_); 144 os::memory::Mutex loadedPfsLock_; 145 146 std::chrono::microseconds sampleInterval_; 147 148 friend class test::SamplerTest; 149 150 NO_COPY_SEMANTIC(Sampler); 151 NO_MOVE_SEMANTIC(Sampler); 152 }; 153 154 } // namespace ark::tooling::sampler 155 156 #endif // PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLING_PROFILER_H 157