xref: /aosp_15_r20/external/cronet/base/profiler/stack_sampler.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_PROFILER_STACK_SAMPLER_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_PROFILER_STACK_SAMPLER_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <memory>
9*6777b538SAndroid Build Coastguard Worker #include <vector>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/containers/circular_deque.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/profiler/frame.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/profiler/register_context.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/profiler/sampling_profiler_thread_token.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/profiler/stack_copier.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/profiler/stack_sampler.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
21*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker namespace base {
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker class Unwinder;
26*6777b538SAndroid Build Coastguard Worker class ModuleCache;
27*6777b538SAndroid Build Coastguard Worker class ProfileBuilder;
28*6777b538SAndroid Build Coastguard Worker class StackBuffer;
29*6777b538SAndroid Build Coastguard Worker class StackSamplerTestDelegate;
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker // StackSampler is an implementation detail of StackSamplingProfiler. It
32*6777b538SAndroid Build Coastguard Worker // abstracts the native implementation required to record a set of stack frames
33*6777b538SAndroid Build Coastguard Worker // for a given thread. It delegates to StackCopier for the
34*6777b538SAndroid Build Coastguard Worker // platform-specific stack copying implementation.
35*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT StackSampler {
36*6777b538SAndroid Build Coastguard Worker  public:
37*6777b538SAndroid Build Coastguard Worker   // Factory for generating a set of Unwinders for use by the profiler.
38*6777b538SAndroid Build Coastguard Worker   using UnwindersFactory =
39*6777b538SAndroid Build Coastguard Worker       OnceCallback<std::vector<std::unique_ptr<Unwinder>>()>;
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker   // Creates a stack sampler that records samples for thread with
42*6777b538SAndroid Build Coastguard Worker   // |thread_token|. Unwinders in |unwinders| must be stored in increasing
43*6777b538SAndroid Build Coastguard Worker   // priority to guide unwind attempts. Only the unwinder with the lowest
44*6777b538SAndroid Build Coastguard Worker   // priority is allowed to return with UnwindResult::kCompleted. Returns null
45*6777b538SAndroid Build Coastguard Worker   // if this platform does not support stack sampling.
46*6777b538SAndroid Build Coastguard Worker   static std::unique_ptr<StackSampler> Create(
47*6777b538SAndroid Build Coastguard Worker       SamplingProfilerThreadToken thread_token,
48*6777b538SAndroid Build Coastguard Worker       ModuleCache* module_cache,
49*6777b538SAndroid Build Coastguard Worker       UnwindersFactory core_unwinders_factory,
50*6777b538SAndroid Build Coastguard Worker       RepeatingClosure record_sample_callback,
51*6777b538SAndroid Build Coastguard Worker       StackSamplerTestDelegate* test_delegate);
52*6777b538SAndroid Build Coastguard Worker 
53*6777b538SAndroid Build Coastguard Worker   ~StackSampler();
54*6777b538SAndroid Build Coastguard Worker 
55*6777b538SAndroid Build Coastguard Worker   StackSampler(const StackSampler&) = delete;
56*6777b538SAndroid Build Coastguard Worker   StackSampler& operator=(const StackSampler&) = delete;
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker   // Gets the required size of the stack buffer.
59*6777b538SAndroid Build Coastguard Worker   static size_t GetStackBufferSize();
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker   // Creates an instance of the a stack buffer that can be used for calls to
62*6777b538SAndroid Build Coastguard Worker   // any StackSampler object.
63*6777b538SAndroid Build Coastguard Worker   static std::unique_ptr<StackBuffer> CreateStackBuffer();
64*6777b538SAndroid Build Coastguard Worker 
65*6777b538SAndroid Build Coastguard Worker   // The following functions are all called on the SamplingThread (not the
66*6777b538SAndroid Build Coastguard Worker   // thread being sampled).
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker   // Performs post-construction initialization on the SamplingThread.
69*6777b538SAndroid Build Coastguard Worker   void Initialize();
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker   // Adds an auxiliary unwinder to handle additional, non-native-code unwind
72*6777b538SAndroid Build Coastguard Worker   // scenarios. Unwinders must be inserted in increasing priority, following
73*6777b538SAndroid Build Coastguard Worker   // |unwinders| provided in Create(), to guide unwind attempts.
74*6777b538SAndroid Build Coastguard Worker   void AddAuxUnwinder(std::unique_ptr<Unwinder> unwinder);
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   // Records a set of frames and returns them.
77*6777b538SAndroid Build Coastguard Worker   void RecordStackFrames(StackBuffer* stack_buffer,
78*6777b538SAndroid Build Coastguard Worker                          ProfileBuilder* profile_builder,
79*6777b538SAndroid Build Coastguard Worker                          PlatformThreadId thread_id);
80*6777b538SAndroid Build Coastguard Worker 
81*6777b538SAndroid Build Coastguard Worker   // Exposes the internal function for unit testing.
82*6777b538SAndroid Build Coastguard Worker   static std::vector<Frame> WalkStackForTesting(
83*6777b538SAndroid Build Coastguard Worker       ModuleCache* module_cache,
84*6777b538SAndroid Build Coastguard Worker       RegisterContext* thread_context,
85*6777b538SAndroid Build Coastguard Worker       uintptr_t stack_top,
86*6777b538SAndroid Build Coastguard Worker       const base::circular_deque<std::unique_ptr<Unwinder>>& unwinders);
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker   // Create a StackSampler, overriding the platform-specific components.
89*6777b538SAndroid Build Coastguard Worker   static std::unique_ptr<StackSampler> CreateForTesting(
90*6777b538SAndroid Build Coastguard Worker       std::unique_ptr<StackCopier> stack_copier,
91*6777b538SAndroid Build Coastguard Worker       UnwindersFactory core_unwinders_factory,
92*6777b538SAndroid Build Coastguard Worker       ModuleCache* module_cache,
93*6777b538SAndroid Build Coastguard Worker       RepeatingClosure record_sample_callback = RepeatingClosure(),
94*6777b538SAndroid Build Coastguard Worker       StackSamplerTestDelegate* test_delegate = nullptr);
95*6777b538SAndroid Build Coastguard Worker 
96*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
97*6777b538SAndroid Build Coastguard Worker   // How often to record the "Memory.StackSamplingProfiler.StackSampleSize2" UMA
98*6777b538SAndroid Build Coastguard Worker   // histogram. Specifically, only 1 in kUMAHistogramDownsampleAmount calls to
99*6777b538SAndroid Build Coastguard Worker   // RecordStackFrames will add a sample to the histogram. RecordStackFrames is
100*6777b538SAndroid Build Coastguard Worker   // called many times a second. We don't need multiple samples per second to
101*6777b538SAndroid Build Coastguard Worker   // get a good understanding of average stack sizes, and it's a lot of data to
102*6777b538SAndroid Build Coastguard Worker   // record. kUMAHistogramDownsampleAmount should give us about 1 sample per 10
103*6777b538SAndroid Build Coastguard Worker   // seconds per process, which is plenty. 199 is prime which should avoid any
104*6777b538SAndroid Build Coastguard Worker   // aliasing issues (e.g. if stacks are larger on second boundaries or some
105*6777b538SAndroid Build Coastguard Worker   // such weirdness).
106*6777b538SAndroid Build Coastguard Worker   static constexpr uint32_t kUMAHistogramDownsampleAmount = 199;
107*6777b538SAndroid Build Coastguard Worker #endif
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker  private:
110*6777b538SAndroid Build Coastguard Worker   StackSampler(std::unique_ptr<StackCopier> stack_copier,
111*6777b538SAndroid Build Coastguard Worker                UnwindersFactory core_unwinders_factory,
112*6777b538SAndroid Build Coastguard Worker                ModuleCache* module_cache,
113*6777b538SAndroid Build Coastguard Worker                RepeatingClosure record_sample_callback,
114*6777b538SAndroid Build Coastguard Worker                StackSamplerTestDelegate* test_delegate);
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   static std::vector<Frame> WalkStack(
117*6777b538SAndroid Build Coastguard Worker       ModuleCache* module_cache,
118*6777b538SAndroid Build Coastguard Worker       RegisterContext* thread_context,
119*6777b538SAndroid Build Coastguard Worker       uintptr_t stack_top,
120*6777b538SAndroid Build Coastguard Worker       const base::circular_deque<std::unique_ptr<Unwinder>>& unwinders);
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker   const std::unique_ptr<StackCopier> stack_copier_;
123*6777b538SAndroid Build Coastguard Worker   UnwindersFactory unwinders_factory_;
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker   // Unwinders are stored in decreasing priority order.
126*6777b538SAndroid Build Coastguard Worker   base::circular_deque<std::unique_ptr<Unwinder>> unwinders_;
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker   const raw_ptr<ModuleCache> module_cache_;
129*6777b538SAndroid Build Coastguard Worker   const RepeatingClosure record_sample_callback_;
130*6777b538SAndroid Build Coastguard Worker   const raw_ptr<StackSamplerTestDelegate> test_delegate_;
131*6777b538SAndroid Build Coastguard Worker 
132*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
133*6777b538SAndroid Build Coastguard Worker   // Counter for "Memory.StackSamplingProfiler.StackSampleSize2" UMA histogram.
134*6777b538SAndroid Build Coastguard Worker   // See comments above kUMAHistogramDownsampleAmount. Unsigned so that overflow
135*6777b538SAndroid Build Coastguard Worker   // isn't undefined behavior.
136*6777b538SAndroid Build Coastguard Worker   uint32_t stack_size_histogram_sampling_counter_ = 0;
137*6777b538SAndroid Build Coastguard Worker #endif
138*6777b538SAndroid Build Coastguard Worker 
139*6777b538SAndroid Build Coastguard Worker   // True if ownership of the object has been passed to the profiling thread and
140*6777b538SAndroid Build Coastguard Worker   // initialization has occurred there. If that's the case then any further aux
141*6777b538SAndroid Build Coastguard Worker   // unwinder that's provided needs to be set up within AddAuxUnwinder().
142*6777b538SAndroid Build Coastguard Worker   bool was_initialized_ = false;
143*6777b538SAndroid Build Coastguard Worker };
144*6777b538SAndroid Build Coastguard Worker 
145*6777b538SAndroid Build Coastguard Worker // StackSamplerTestDelegate provides seams for test code to execute during stack
146*6777b538SAndroid Build Coastguard Worker // collection.
147*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT StackSamplerTestDelegate {
148*6777b538SAndroid Build Coastguard Worker  public:
149*6777b538SAndroid Build Coastguard Worker   StackSamplerTestDelegate(const StackSamplerTestDelegate&) = delete;
150*6777b538SAndroid Build Coastguard Worker   StackSamplerTestDelegate& operator=(const StackSamplerTestDelegate&) = delete;
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   virtual ~StackSamplerTestDelegate();
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker   // Called after copying the stack and resuming the target thread, but prior to
155*6777b538SAndroid Build Coastguard Worker   // walking the stack. Invoked on the SamplingThread.
156*6777b538SAndroid Build Coastguard Worker   virtual void OnPreStackWalk() = 0;
157*6777b538SAndroid Build Coastguard Worker 
158*6777b538SAndroid Build Coastguard Worker  protected:
159*6777b538SAndroid Build Coastguard Worker   StackSamplerTestDelegate();
160*6777b538SAndroid Build Coastguard Worker };
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker }  // namespace base
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker #endif  // BASE_PROFILER_STACK_SAMPLER_H_
165