xref: /aosp_15_r20/external/libchrome/base/profiler/stack_sampling_profiler.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
6 #define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
7 
8 #include <stddef.h>
9 
10 #include <map>
11 #include <memory>
12 #include <string>
13 #include <vector>
14 
15 #include "base/base_export.h"
16 #include "base/files/file_path.h"
17 #include "base/macros.h"
18 #include "base/strings/string16.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/threading/platform_thread.h"
21 #include "base/time/time.h"
22 
23 namespace base {
24 
25 // Identifies an unknown module.
26 BASE_EXPORT extern const size_t kUnknownModuleIndex;
27 
28 class NativeStackSamplerTestDelegate;
29 
30 // StackSamplingProfiler periodically stops a thread to sample its stack, for
31 // the purpose of collecting information about which code paths are
32 // executing. This information is used in aggregate by UMA to identify hot
33 // and/or janky code paths.
34 //
35 // Sample StackSamplingProfiler usage:
36 //
37 //   // Create and customize params as desired.
38 //   base::StackStackSamplingProfiler::SamplingParams params;
39 //
40 //   // To process the profiles, use a custom ProfileBuilder subclass:
41 //   class SubProfileBuilder :
42 //       public base::StackSamplingProfiler::ProfileBuilder{...}
43 //   base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
44 //       params, std::make_unique<SubProfileBuilder>(...));
45 //
46 //   profiler.Start();
47 //   // ... work being done on the target thread here ...
48 //   profiler.Stop();  // optional, stops collection before complete per params
49 //
50 // The default SamplingParams causes stacks to be recorded in a single profile
51 // at a 10Hz interval for a total of 30 seconds. All of these parameters may be
52 // altered as desired.
53 //
54 // When a call stack profile is complete, or the profiler is stopped,
55 // ProfileBuilder's OnProfileCompleted function is called from a thread created
56 // by the profiler.
57 class BASE_EXPORT StackSamplingProfiler {
58  public:
59   // Module represents the module (DLL or exe) corresponding to a stack frame.
60   struct BASE_EXPORT Module {
61     Module();
62     Module(uintptr_t base_address,
63            const std::string& id,
64            const FilePath& filename);
65     ~Module();
66 
67     // Points to the base address of the module.
68     uintptr_t base_address;
69 
70     // An opaque binary string that uniquely identifies a particular program
71     // version with high probability. This is parsed from headers of the loaded
72     // module.
73     // For binaries generated by GNU tools:
74     //   Contents of the .note.gnu.build-id field.
75     // On Windows:
76     //   GUID + AGE in the debug image headers of a module.
77     std::string id;
78 
79     // The filename of the module.
80     FilePath filename;
81   };
82 
83   // InternalModule represents the module (DLL or exe) and its validness state.
84   // Different from Module, it has an additional field "is_valid".
85   //
86   // This struct is only used for sampling data transfer from NativeStackSampler
87   // to ProfileBuilder.
88   struct BASE_EXPORT InternalModule {
89     InternalModule();
90     InternalModule(uintptr_t base_address,
91                    const std::string& id,
92                    const FilePath& filename);
93     ~InternalModule();
94 
95     // Points to the base address of the module.
96     uintptr_t base_address;
97 
98     // An opaque binary string that uniquely identifies a particular program
99     // version with high probability. This is parsed from headers of the loaded
100     // module.
101     // For binaries generated by GNU tools:
102     //   Contents of the .note.gnu.build-id field.
103     // On Windows:
104     //   GUID + AGE in the debug image headers of a module.
105     std::string id;
106 
107     // The filename of the module.
108     FilePath filename;
109 
110     // The validness of the module.
111     bool is_valid;
112   };
113 
114   // Frame represents an individual sampled stack frame with module information.
115   struct BASE_EXPORT Frame {
116     Frame(uintptr_t instruction_pointer, size_t module_index);
117     ~Frame();
118 
119     // Default constructor to satisfy IPC macros. Do not use explicitly.
120     Frame();
121 
122     // The sampled instruction pointer within the function.
123     uintptr_t instruction_pointer;
124 
125     // Index of the module in CallStackProfile::modules. We don't represent
126     // module state directly here to save space.
127     size_t module_index;
128   };
129 
130   // InternalFrame represents an individual sampled stack frame with full module
131   // information. This is different from Frame which only contains module index.
132   //
133   // This struct is only used for sampling data transfer from NativeStackSampler
134   // to ProfileBuilder.
135   struct BASE_EXPORT InternalFrame {
136     InternalFrame(uintptr_t instruction_pointer,
137                   InternalModule internal_module);
138     ~InternalFrame();
139 
140     // The sampled instruction pointer within the function.
141     uintptr_t instruction_pointer;
142 
143     // The module information.
144     InternalModule internal_module;
145   };
146 
147   // Sample represents a set of stack frames with some extra information.
148   struct BASE_EXPORT Sample {
149     Sample();
150     Sample(const Sample& sample);
151     ~Sample();
152 
153     // These constructors are used only during testing.
154     Sample(const Frame& frame);
155     Sample(const std::vector<Frame>& frames);
156 
157     // The entire stack frame when the sample is taken.
158     std::vector<Frame> frames;
159 
160     // A bit-field indicating which process milestones have passed. This can be
161     // used to tell where in the process lifetime the samples are taken. Just
162     // as a "lifetime" can only move forward, these bits mark the milestones of
163     // the processes life as they occur. Bits can be set but never reset. The
164     // actual definition of the individual bits is left to the user of this
165     // module.
166     uint32_t process_milestones = 0;
167   };
168 
169   // CallStackProfile represents a set of samples.
170   struct BASE_EXPORT CallStackProfile {
171     CallStackProfile();
172     CallStackProfile(CallStackProfile&& other);
173     ~CallStackProfile();
174 
175     CallStackProfile& operator=(CallStackProfile&& other);
176 
177     CallStackProfile CopyForTesting() const;
178 
179     std::vector<Module> modules;
180     std::vector<Sample> samples;
181 
182     // Duration of this profile.
183     TimeDelta profile_duration;
184 
185     // Time between samples.
186     TimeDelta sampling_period;
187 
188    private:
189     // Copying is possible but expensive so disallow it except for internal use
190     // (i.e. CopyForTesting); use std::move instead.
191     CallStackProfile(const CallStackProfile& other);
192 
193     DISALLOW_ASSIGN(CallStackProfile);
194   };
195 
196   // Represents parameters that configure the sampling.
197   struct BASE_EXPORT SamplingParams {
198     // Time to delay before first samples are taken.
199     TimeDelta initial_delay = TimeDelta::FromMilliseconds(0);
200 
201     // Number of samples to record per profile.
202     int samples_per_profile = 300;
203 
204     // Interval between samples during a sampling profile. This is the desired
205     // duration from the start of one sample to the start of the next sample.
206     TimeDelta sampling_interval = TimeDelta::FromMilliseconds(100);
207   };
208 
209   // Testing support. These methods are static beause they interact with the
210   // sampling thread, a singleton used by all StackSamplingProfiler objects.
211   // These methods can only be called by the same thread that started the
212   // sampling.
213   class BASE_EXPORT TestAPI {
214    public:
215     // Resets the internal state to that of a fresh start. This is necessary
216     // so that tests don't inherit state from previous tests.
217     static void Reset();
218 
219     // Returns whether the sampling thread is currently running or not.
220     static bool IsSamplingThreadRunning();
221 
222     // Disables inherent idle-shutdown behavior.
223     static void DisableIdleShutdown();
224 
225     // Initiates an idle shutdown task, as though the idle timer had expired,
226     // causing the thread to exit. There is no "idle" check so this must be
227     // called only when all sampling tasks have completed. This blocks until
228     // the task has been executed, though the actual stopping of the thread
229     // still happens asynchronously. Watch IsSamplingThreadRunning() to know
230     // when the thread has exited. If |simulate_intervening_start| is true then
231     // this method will make it appear to the shutdown task that a new profiler
232     // was started between when the idle-shutdown was initiated and when it
233     // runs.
234     static void PerformSamplingThreadIdleShutdown(
235         bool simulate_intervening_start);
236   };
237 
238   // The ProfileBuilder interface allows the user to record profile information
239   // on the fly in whatever format is desired. Functions are invoked by the
240   // profiler on its own thread so must not block or perform expensive
241   // operations.
242   class BASE_EXPORT ProfileBuilder {
243    public:
244     ProfileBuilder() = default;
245     virtual ~ProfileBuilder() = default;
246 
247     // Metadata associated with the sample to be saved off.
248     // The code implementing this method must not do anything that could acquire
249     // a mutex, including allocating memory (which includes LOG messages)
250     // because that mutex could be held by a stopped thread, thus resulting in
251     // deadlock.
252     virtual void RecordAnnotations() = 0;
253 
254     // Records a new set of internal frames. Invoked when sampling a sample
255     // completes.
256     virtual void OnSampleCompleted(
257         std::vector<InternalFrame> internal_frames) = 0;
258 
259     // Finishes the profile construction with |profile_duration| and
260     // |sampling_period|. Invoked when sampling a profile completes.
261     virtual void OnProfileCompleted(TimeDelta profile_duration,
262                                     TimeDelta sampling_period) = 0;
263 
264    private:
265     DISALLOW_COPY_AND_ASSIGN(ProfileBuilder);
266   };
267 
268   // Creates a profiler for the CURRENT thread. An optional |test_delegate| can
269   // be supplied by tests. The caller must ensure that this object gets
270   // destroyed before the current thread exits.
271   StackSamplingProfiler(
272       const SamplingParams& params,
273       std::unique_ptr<ProfileBuilder> profile_builder,
274       NativeStackSamplerTestDelegate* test_delegate = nullptr);
275 
276   // Creates a profiler for ANOTHER thread. An optional |test_delegate| can be
277   // supplied by tests.
278   //
279   // IMPORTANT: The caller must ensure that the thread being sampled does not
280   // exit before this object gets destructed or Bad Things(tm) may occur.
281   StackSamplingProfiler(
282       PlatformThreadId thread_id,
283       const SamplingParams& params,
284       std::unique_ptr<ProfileBuilder> profile_builder,
285       NativeStackSamplerTestDelegate* test_delegate = nullptr);
286 
287   // Stops any profiling currently taking place before destroying the profiler.
288   // This will block until profile_builder_'s OnProfileCompleted function has
289   // executed if profiling has started but not already finished.
290   ~StackSamplingProfiler();
291 
292   // Initializes the profiler and starts sampling. Might block on a
293   // WaitableEvent if this StackSamplingProfiler was previously started and
294   // recently stopped, while the previous profiling phase winds down.
295   void Start();
296 
297   // Stops the profiler and any ongoing sampling. This method will return
298   // immediately with the profile_builder_'s OnProfileCompleted function being
299   // run asynchronously. At most one more stack sample will be taken after this
300   // method returns. Calling this function is optional; if not invoked profiling
301   // terminates when all the profiling samples specified in the SamplingParams
302   // are completed or the profiler object is destroyed, whichever occurs first.
303   void Stop();
304 
305  private:
306   friend class TestAPI;
307 
308   // SamplingThread is a separate thread used to suspend and sample stacks from
309   // the target thread.
310   class SamplingThread;
311 
312   // The thread whose stack will be sampled.
313   PlatformThreadId thread_id_;
314 
315   const SamplingParams params_;
316 
317   // Receives the sampling data and builds a CallStackProfile. The ownership of
318   // this object will be transferred to the sampling thread when thread sampling
319   // starts.
320   std::unique_ptr<ProfileBuilder> profile_builder_;
321 
322   // This starts "signaled", is reset when sampling begins, and is signaled
323   // when that sampling is complete and the profile_builder_'s
324   // OnProfileCompleted function has executed.
325   WaitableEvent profiling_inactive_;
326 
327   // An ID uniquely identifying this profiler to the sampling thread. This
328   // will be an internal "null" value when no collection has been started.
329   int profiler_id_;
330 
331   // Stored until it can be passed to the NativeStackSampler created in Start().
332   NativeStackSamplerTestDelegate* const test_delegate_;
333 
334   DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
335 };
336 
337 // These operators permit types to be compared and used in a map of Samples, as
338 // done in tests and by the metrics provider code.
339 BASE_EXPORT bool operator==(const StackSamplingProfiler::Module& a,
340                             const StackSamplingProfiler::Module& b);
341 BASE_EXPORT bool operator==(const StackSamplingProfiler::Sample& a,
342                             const StackSamplingProfiler::Sample& b);
343 BASE_EXPORT bool operator!=(const StackSamplingProfiler::Sample& a,
344                             const StackSamplingProfiler::Sample& b);
345 BASE_EXPORT bool operator<(const StackSamplingProfiler::Sample& a,
346                            const StackSamplingProfiler::Sample& b);
347 BASE_EXPORT bool operator==(const StackSamplingProfiler::Frame& a,
348                             const StackSamplingProfiler::Frame& b);
349 BASE_EXPORT bool operator<(const StackSamplingProfiler::Frame& a,
350                            const StackSamplingProfiler::Frame& b);
351 
352 }  // namespace base
353 
354 #endif  // BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
355