• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
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_SAMPLER_H_
6 #define BASE_PROFILER_STACK_SAMPLER_H_
7 
8 #include <memory>
9 #include <vector>
10 
11 #include "base/base_export.h"
12 #include "base/containers/circular_deque.h"
13 #include "base/functional/callback.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/profiler/frame.h"
17 #include "base/profiler/register_context.h"
18 #include "base/profiler/sampling_profiler_thread_token.h"
19 #include "base/profiler/stack_copier.h"
20 #include "base/profiler/stack_unwind_data.h"
21 #include "base/threading/platform_thread.h"
22 #include "build/build_config.h"
23 
24 namespace base {
25 
26 class ModuleCache;
27 class StackBuffer;
28 class StackSamplerTestDelegate;
29 class Unwinder;
30 
31 // StackSampler is an implementation detail of StackSamplingProfiler. It
32 // abstracts the native implementation required to record a set of stack frames
33 // for a given thread. It delegates to StackCopier for the
34 // platform-specific stack copying implementation.
35 // This class is used on both the SamplingThread and a worker thread of the
36 // thread pool. Recording stack frames always occurs on the
37 // SamplingThread but unwinding the stack can occur on either the SamplingThread
38 // or a worker thread. Sampling can start before the thread pool is running so
39 // unwinding will occur on the SamplingThread until the thread pool is ready.
40 class BASE_EXPORT StackSampler {
41  public:
42   // Factory for generating a set of Unwinders for use by the profiler.
43   using UnwindersFactory =
44       OnceCallback<std::vector<std::unique_ptr<Unwinder>>()>;
45 
46   // Creates a stack sampler that records samples for thread with
47   // |thread_token|. Unwinders in |unwinders| must be stored in increasing
48   // priority to guide unwind attempts. Only the unwinder with the lowest
49   // priority is allowed to return with UnwindResult::kCompleted. Returns null
50   // if this platform does not support stack sampling.
51   static std::unique_ptr<StackSampler> Create(
52       SamplingProfilerThreadToken thread_token,
53       std::unique_ptr<StackUnwindData> stack_unwind_data,
54       UnwindersFactory core_unwinders_factory,
55       RepeatingClosure record_sample_callback,
56       StackSamplerTestDelegate* test_delegate);
57 
58   ~StackSampler();
59 
60   StackSampler(const StackSampler&) = delete;
61   StackSampler& operator=(const StackSampler&) = delete;
62 
63   // Gets the required size of the stack buffer.
64   static size_t GetStackBufferSize();
65 
66   // Creates an instance of the a stack buffer that can be used for calls to
67   // any StackSampler object.
68   static std::unique_ptr<StackBuffer> CreateStackBuffer();
69 
70   // The following functions are all called on the SamplingThread (not the
71   // thread being sampled).
72 
73   // Performs post-construction initialization on the SamplingThread.
74   void Initialize();
75 
76   // Stops the sampler.
77   void Stop(OnceClosure done_callback);
78 
79   // Adds an auxiliary unwinder to handle additional, non-native-code unwind
80   // scenarios. Unwinders must be inserted in increasing priority, following
81   // |unwinders| provided in Create(), to guide unwind attempts.
82   void AddAuxUnwinder(std::unique_ptr<Unwinder> unwinder);
83 
84   // Records a set of frames and returns them.
85   void RecordStackFrames(StackBuffer* stack_buffer,
86                          PlatformThreadId thread_id,
87                          OnceClosure done_callback);
88 
89   StackUnwindData* GetStackUnwindData();
90 
91   // Exposes the internal function for unit testing.
92   static std::vector<Frame> WalkStackForTesting(
93       ModuleCache* module_cache,
94       RegisterContext* thread_context,
95       uintptr_t stack_top,
96       std::vector<UnwinderCapture> unwinders);
97 
98   // Create a StackSampler, overriding the platform-specific components.
99   static std::unique_ptr<StackSampler> CreateForTesting(
100       std::unique_ptr<StackCopier> stack_copier,
101       std::unique_ptr<StackUnwindData> stack_unwind_data,
102       UnwindersFactory core_unwinders_factory,
103       RepeatingClosure record_sample_callback = RepeatingClosure(),
104       StackSamplerTestDelegate* test_delegate = nullptr);
105 
106 #if BUILDFLAG(IS_CHROMEOS)
107   // How often to record the "Memory.StackSamplingProfiler.StackSampleSize2" UMA
108   // histogram. Specifically, only 1 in kUMAHistogramDownsampleAmount calls to
109   // RecordStackFrames will add a sample to the histogram. RecordStackFrames is
110   // called many times a second. We don't need multiple samples per second to
111   // get a good understanding of average stack sizes, and it's a lot of data to
112   // record. kUMAHistogramDownsampleAmount should give us about 1 sample per 10
113   // seconds per process, which is plenty. 199 is prime which should avoid any
114   // aliasing issues (e.g. if stacks are larger on second boundaries or some
115   // such weirdness).
116   static constexpr uint32_t kUMAHistogramDownsampleAmount = 199;
117 #endif
118 
119  private:
120   FRIEND_TEST_ALL_PREFIXES(StackSamplerTest,
121                            AuxUnwinderInvokedWhileRecordingStackFrames);
122 
123   StackSampler(std::unique_ptr<StackCopier> stack_copier,
124                std::unique_ptr<StackUnwindData> stack_unwind_data,
125                UnwindersFactory core_unwinders_factory,
126                RepeatingClosure record_sample_callback,
127                StackSamplerTestDelegate* test_delegate);
128 
129   static std::vector<Frame> WalkStack(ModuleCache* module_cache,
130                                       RegisterContext* thread_context,
131                                       uintptr_t stack_top,
132                                       std::vector<UnwinderCapture> unwinders);
133 
134   void UnwindComplete(TimeTicks timestamp,
135                       OnceClosure done_callback,
136                       std::vector<Frame> frames);
137   void AddAuxUnwinderWithoutInit(std::unique_ptr<Unwinder> unwinder);
138   void ThreadPoolRunning();
139 
140   const std::unique_ptr<StackCopier> stack_copier_;
141   UnwindersFactory unwinders_factory_;
142 
143   const RepeatingClosure record_sample_callback_;
144   const raw_ptr<StackSamplerTestDelegate> test_delegate_;
145 
146 #if BUILDFLAG(IS_CHROMEOS)
147   // Counter for "Memory.StackSamplingProfiler.StackSampleSize2" UMA histogram.
148   // See comments above kUMAHistogramDownsampleAmount. Unsigned so that overflow
149   // isn't undefined behavior.
150   uint32_t stack_size_histogram_sampling_counter_ = 0;
151 #endif
152 
153   scoped_refptr<SequencedTaskRunner> thread_pool_runner_;
154 
155   // The StackUnwindData will be in released on the `thread_pool_runner_` if it
156   // is non-null.
157   std::unique_ptr<StackUnwindData> unwind_data_;
158 
159   bool was_initialized_ = false;
160   bool thread_pool_ready_ = false;
161 
162   base::WeakPtrFactory<StackSampler> weak_ptr_factory_{this};
163 };
164 
165 // StackSamplerTestDelegate provides seams for test code to execute during stack
166 // collection.
167 class BASE_EXPORT StackSamplerTestDelegate {
168  public:
169   StackSamplerTestDelegate(const StackSamplerTestDelegate&) = delete;
170   StackSamplerTestDelegate& operator=(const StackSamplerTestDelegate&) = delete;
171 
172   virtual ~StackSamplerTestDelegate();
173 
174   // Called after copying the stack and resuming the target thread, but prior to
175   // walking the stack. Invoked on the SamplingThread.
176   virtual void OnPreStackWalk() = 0;
177 
178  protected:
179   StackSamplerTestDelegate();
180 };
181 
182 }  // namespace base
183 
184 #endif  // BASE_PROFILER_STACK_SAMPLER_H_
185