• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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