xref: /aosp_15_r20/external/cronet/base/profiler/stack_sampling_profiler.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_SAMPLING_PROFILER_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <memory>
9*6777b538SAndroid Build Coastguard Worker #include <optional>
10*6777b538SAndroid Build Coastguard Worker #include <vector>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/profiler/profile_builder.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/profiler/sampling_profiler_thread_token.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker namespace base {
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker class Unwinder;
23*6777b538SAndroid Build Coastguard Worker class StackSampler;
24*6777b538SAndroid Build Coastguard Worker class StackSamplerTestDelegate;
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker // StackSamplingProfiler periodically stops a thread to sample its stack, for
27*6777b538SAndroid Build Coastguard Worker // the purpose of collecting information about which code paths are
28*6777b538SAndroid Build Coastguard Worker // executing. This information is used in aggregate by UMA to identify hot
29*6777b538SAndroid Build Coastguard Worker // and/or janky code paths.
30*6777b538SAndroid Build Coastguard Worker //
31*6777b538SAndroid Build Coastguard Worker // Sample StackSamplingProfiler usage:
32*6777b538SAndroid Build Coastguard Worker //
33*6777b538SAndroid Build Coastguard Worker //   // Create and customize params as desired.
34*6777b538SAndroid Build Coastguard Worker //   base::StackStackSamplingProfiler::SamplingParams params;
35*6777b538SAndroid Build Coastguard Worker //
36*6777b538SAndroid Build Coastguard Worker //   // Create a ProfileBuilder subclass to process the profiles.
37*6777b538SAndroid Build Coastguard Worker //   class ProfileBuilder : public base::ProfileBuilder {...}
38*6777b538SAndroid Build Coastguard Worker //
39*6777b538SAndroid Build Coastguard Worker //   // Then create the profiler:
40*6777b538SAndroid Build Coastguard Worker //   base::StackSamplingProfiler profiler(
41*6777b538SAndroid Build Coastguard Worker //       GetSamplingProfilerCurrentThreadToken(),
42*6777b538SAndroid Build Coastguard Worker //       params,
43*6777b538SAndroid Build Coastguard Worker //       std::make_unique<ProfileBuilder>(...));
44*6777b538SAndroid Build Coastguard Worker //
45*6777b538SAndroid Build Coastguard Worker //   // On Android the caller also must provide a factory function for creating
46*6777b538SAndroid Build Coastguard Worker //   // its core stack unwinders. See the ThreadProfiler implementation for an
47*6777b538SAndroid Build Coastguard Worker //   // example of how to do this.
48*6777b538SAndroid Build Coastguard Worker //   base::StackSamplingProfiler profiler(
49*6777b538SAndroid Build Coastguard Worker //       GetSamplingProfilerCurrentThreadToken(),
50*6777b538SAndroid Build Coastguard Worker //       params,
51*6777b538SAndroid Build Coastguard Worker //       std::make_unique<ProfileBuilder>(...),
52*6777b538SAndroid Build Coastguard Worker //       core_unwinders_factory);
53*6777b538SAndroid Build Coastguard Worker //
54*6777b538SAndroid Build Coastguard Worker //   // Then start the profiling.
55*6777b538SAndroid Build Coastguard Worker //   profiler.Start();
56*6777b538SAndroid Build Coastguard Worker //
57*6777b538SAndroid Build Coastguard Worker //   // ... work being done on the target thread here ...
58*6777b538SAndroid Build Coastguard Worker //
59*6777b538SAndroid Build Coastguard Worker //   // Optionally stop collection before complete per params.
60*6777b538SAndroid Build Coastguard Worker //   profiler.Stop();
61*6777b538SAndroid Build Coastguard Worker //
62*6777b538SAndroid Build Coastguard Worker // The default SamplingParams causes stacks to be recorded in a single profile
63*6777b538SAndroid Build Coastguard Worker // at a 10Hz interval for a total of 30 seconds. All of these parameters may be
64*6777b538SAndroid Build Coastguard Worker // altered as desired.
65*6777b538SAndroid Build Coastguard Worker //
66*6777b538SAndroid Build Coastguard Worker // When a call stack profile is complete, or the profiler is stopped,
67*6777b538SAndroid Build Coastguard Worker // ProfileBuilder's OnProfileCompleted function is called from a thread created
68*6777b538SAndroid Build Coastguard Worker // by the profiler.
69*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT StackSamplingProfiler {
70*6777b538SAndroid Build Coastguard Worker  public:
71*6777b538SAndroid Build Coastguard Worker   // Factory for generating a set of Unwinders for use by the profiler. More
72*6777b538SAndroid Build Coastguard Worker   // general unwinders should appear before more specific unwinders in the
73*6777b538SAndroid Build Coastguard Worker   // generated vector, e.g. a system unwinder should appear before a Chrome
74*6777b538SAndroid Build Coastguard Worker   // unwinder. The callback will be invoked on the profiler thread.
75*6777b538SAndroid Build Coastguard Worker   using UnwindersFactory =
76*6777b538SAndroid Build Coastguard Worker       OnceCallback<std::vector<std::unique_ptr<Unwinder>>()>;
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker   // Represents parameters that configure the sampling.
79*6777b538SAndroid Build Coastguard Worker   struct BASE_EXPORT SamplingParams {
80*6777b538SAndroid Build Coastguard Worker     // Time to delay before first samples are taken.
81*6777b538SAndroid Build Coastguard Worker     TimeDelta initial_delay = Milliseconds(0);
82*6777b538SAndroid Build Coastguard Worker 
83*6777b538SAndroid Build Coastguard Worker     // Number of samples to record per profile.
84*6777b538SAndroid Build Coastguard Worker     int samples_per_profile = 300;
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker     // Interval between samples during a sampling profile. This is the desired
87*6777b538SAndroid Build Coastguard Worker     // duration from the start of one sample to the start of the next sample.
88*6777b538SAndroid Build Coastguard Worker     TimeDelta sampling_interval = Milliseconds(100);
89*6777b538SAndroid Build Coastguard Worker   };
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker   // Returns true if the profiler is supported on the current platform
92*6777b538SAndroid Build Coastguard Worker   // configuration.
93*6777b538SAndroid Build Coastguard Worker   static bool IsSupportedForCurrentPlatform();
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker   // Creates a profiler for the the thread associated with |thread_token|,
96*6777b538SAndroid Build Coastguard Worker   // generated by GetSamplingProfilerCurrentThreadToken().
97*6777b538SAndroid Build Coastguard Worker   // |core_unwinders_factory| is required on Android since the unwinders are
98*6777b538SAndroid Build Coastguard Worker   // provided outside StackSamplingProfiler, but must be null other platforms.
99*6777b538SAndroid Build Coastguard Worker   // |record_sample_callback| is called for each sample right before recording
100*6777b538SAndroid Build Coastguard Worker   // the stack sample. An optional |test_delegate| can be supplied by tests.
101*6777b538SAndroid Build Coastguard Worker   //
102*6777b538SAndroid Build Coastguard Worker   // The caller must ensure that this object gets destroyed before the thread
103*6777b538SAndroid Build Coastguard Worker   // exits.
104*6777b538SAndroid Build Coastguard Worker   StackSamplingProfiler(
105*6777b538SAndroid Build Coastguard Worker       SamplingProfilerThreadToken thread_token,
106*6777b538SAndroid Build Coastguard Worker       const SamplingParams& params,
107*6777b538SAndroid Build Coastguard Worker       std::unique_ptr<ProfileBuilder> profile_builder,
108*6777b538SAndroid Build Coastguard Worker       UnwindersFactory core_unwinders_factory = UnwindersFactory(),
109*6777b538SAndroid Build Coastguard Worker       RepeatingClosure record_sample_callback = RepeatingClosure(),
110*6777b538SAndroid Build Coastguard Worker       StackSamplerTestDelegate* test_delegate = nullptr);
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker   StackSamplingProfiler(const StackSamplingProfiler&) = delete;
113*6777b538SAndroid Build Coastguard Worker   StackSamplingProfiler& operator=(const StackSamplingProfiler&) = delete;
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker   // Stops any profiling currently taking place before destroying the profiler.
116*6777b538SAndroid Build Coastguard Worker   // This will block until profile_builder_'s OnProfileCompleted function has
117*6777b538SAndroid Build Coastguard Worker   // executed if profiling has started but not already finished.
118*6777b538SAndroid Build Coastguard Worker   ~StackSamplingProfiler();
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker   // Initializes the profiler and starts sampling. Might block on a
121*6777b538SAndroid Build Coastguard Worker   // WaitableEvent if this StackSamplingProfiler was previously started and
122*6777b538SAndroid Build Coastguard Worker   // recently stopped, while the previous profiling phase winds down.
123*6777b538SAndroid Build Coastguard Worker   void Start();
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker   // Stops the profiler and any ongoing sampling. This method will return
126*6777b538SAndroid Build Coastguard Worker   // immediately with the profile_builder_'s OnProfileCompleted function being
127*6777b538SAndroid Build Coastguard Worker   // run asynchronously. At most one more stack sample will be taken after this
128*6777b538SAndroid Build Coastguard Worker   // method returns. Calling this function is optional; if not invoked profiling
129*6777b538SAndroid Build Coastguard Worker   // terminates when all the profiling samples specified in the SamplingParams
130*6777b538SAndroid Build Coastguard Worker   // are completed or the profiler object is destroyed, whichever occurs first.
131*6777b538SAndroid Build Coastguard Worker   void Stop();
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker   // Adds an auxiliary unwinder to handle additional, non-native-code unwind
134*6777b538SAndroid Build Coastguard Worker   // scenarios.
135*6777b538SAndroid Build Coastguard Worker   void AddAuxUnwinder(std::unique_ptr<Unwinder> unwinder);
136*6777b538SAndroid Build Coastguard Worker 
137*6777b538SAndroid Build Coastguard Worker   // Test peer class. These functions are purely for internal testing of
138*6777b538SAndroid Build Coastguard Worker   // StackSamplingProfiler; DO NOT USE within tests outside of this directory.
139*6777b538SAndroid Build Coastguard Worker   // The functions are static because they interact with the sampling thread, a
140*6777b538SAndroid Build Coastguard Worker   // singleton used by all StackSamplingProfiler objects.  The functions can
141*6777b538SAndroid Build Coastguard Worker   // only be called by the same thread that started the sampling.
142*6777b538SAndroid Build Coastguard Worker   class BASE_EXPORT TestPeer {
143*6777b538SAndroid Build Coastguard Worker    public:
144*6777b538SAndroid Build Coastguard Worker     // Resets the internal state to that of a fresh start. This is necessary
145*6777b538SAndroid Build Coastguard Worker     // so that tests don't inherit state from previous tests.
146*6777b538SAndroid Build Coastguard Worker     static void Reset();
147*6777b538SAndroid Build Coastguard Worker 
148*6777b538SAndroid Build Coastguard Worker     // Returns whether the sampling thread is currently running or not.
149*6777b538SAndroid Build Coastguard Worker     static bool IsSamplingThreadRunning();
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker     // Disables inherent idle-shutdown behavior.
152*6777b538SAndroid Build Coastguard Worker     static void DisableIdleShutdown();
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker     // Initiates an idle shutdown task, as though the idle timer had expired,
155*6777b538SAndroid Build Coastguard Worker     // causing the thread to exit. There is no "idle" check so this must be
156*6777b538SAndroid Build Coastguard Worker     // called only when all sampling tasks have completed. This blocks until
157*6777b538SAndroid Build Coastguard Worker     // the task has been executed, though the actual stopping of the thread
158*6777b538SAndroid Build Coastguard Worker     // still happens asynchronously. Watch IsSamplingThreadRunning() to know
159*6777b538SAndroid Build Coastguard Worker     // when the thread has exited. If |simulate_intervening_start| is true then
160*6777b538SAndroid Build Coastguard Worker     // this method will make it appear to the shutdown task that a new profiler
161*6777b538SAndroid Build Coastguard Worker     // was started between when the idle-shutdown was initiated and when it
162*6777b538SAndroid Build Coastguard Worker     // runs.
163*6777b538SAndroid Build Coastguard Worker     static void PerformSamplingThreadIdleShutdown(
164*6777b538SAndroid Build Coastguard Worker         bool simulate_intervening_start);
165*6777b538SAndroid Build Coastguard Worker 
166*6777b538SAndroid Build Coastguard Worker     // Provides access to the method computing the next sample time.
167*6777b538SAndroid Build Coastguard Worker     static TimeTicks GetNextSampleTime(TimeTicks scheduled_current_sample_time,
168*6777b538SAndroid Build Coastguard Worker                                        TimeDelta sampling_interval,
169*6777b538SAndroid Build Coastguard Worker                                        TimeTicks now);
170*6777b538SAndroid Build Coastguard Worker   };
171*6777b538SAndroid Build Coastguard Worker 
172*6777b538SAndroid Build Coastguard Worker  private:
173*6777b538SAndroid Build Coastguard Worker   // SamplingThread is a separate thread used to suspend and sample stacks from
174*6777b538SAndroid Build Coastguard Worker   // the target thread.
175*6777b538SAndroid Build Coastguard Worker   class SamplingThread;
176*6777b538SAndroid Build Coastguard Worker 
177*6777b538SAndroid Build Coastguard Worker   // Friend the global functions from sample_metadata.cc so that it can call
178*6777b538SAndroid Build Coastguard Worker   // into the function below.
179*6777b538SAndroid Build Coastguard Worker   friend void ApplyMetadataToPastSamplesImpl(
180*6777b538SAndroid Build Coastguard Worker       TimeTicks period_start,
181*6777b538SAndroid Build Coastguard Worker       TimeTicks period_end,
182*6777b538SAndroid Build Coastguard Worker       uint64_t name_hash,
183*6777b538SAndroid Build Coastguard Worker       std::optional<int64_t> key,
184*6777b538SAndroid Build Coastguard Worker       int64_t value,
185*6777b538SAndroid Build Coastguard Worker       std::optional<PlatformThreadId> thread_id);
186*6777b538SAndroid Build Coastguard Worker   friend void AddProfileMetadataImpl(uint64_t name_hash,
187*6777b538SAndroid Build Coastguard Worker                                      int64_t key,
188*6777b538SAndroid Build Coastguard Worker                                      int64_t value,
189*6777b538SAndroid Build Coastguard Worker                                      std::optional<PlatformThreadId> thread_id);
190*6777b538SAndroid Build Coastguard Worker 
191*6777b538SAndroid Build Coastguard Worker   // Apply metadata to already recorded samples. See the
192*6777b538SAndroid Build Coastguard Worker   // ApplyMetadataToPastSamples() docs in sample_metadata.h.
193*6777b538SAndroid Build Coastguard Worker   static void ApplyMetadataToPastSamples(
194*6777b538SAndroid Build Coastguard Worker       TimeTicks period_start,
195*6777b538SAndroid Build Coastguard Worker       TimeTicks period_end,
196*6777b538SAndroid Build Coastguard Worker       uint64_t name_hash,
197*6777b538SAndroid Build Coastguard Worker       std::optional<int64_t> key,
198*6777b538SAndroid Build Coastguard Worker       int64_t value,
199*6777b538SAndroid Build Coastguard Worker       std::optional<PlatformThreadId> thread_id);
200*6777b538SAndroid Build Coastguard Worker 
201*6777b538SAndroid Build Coastguard Worker   // Adds metadata as metadata global to the sampling profile.
202*6777b538SAndroid Build Coastguard Worker   static void AddProfileMetadata(uint64_t name_hash,
203*6777b538SAndroid Build Coastguard Worker                                  int64_t key,
204*6777b538SAndroid Build Coastguard Worker                                  int64_t value,
205*6777b538SAndroid Build Coastguard Worker                                  std::optional<PlatformThreadId> thread_id);
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker   // The thread whose stack will be sampled.
208*6777b538SAndroid Build Coastguard Worker   SamplingProfilerThreadToken thread_token_;
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker   const SamplingParams params_;
211*6777b538SAndroid Build Coastguard Worker 
212*6777b538SAndroid Build Coastguard Worker   // Receives the sampling data and builds a profile. The ownership of this
213*6777b538SAndroid Build Coastguard Worker   // object will be transferred to the sampling thread when thread sampling
214*6777b538SAndroid Build Coastguard Worker   // starts.
215*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<ProfileBuilder> profile_builder_;
216*6777b538SAndroid Build Coastguard Worker 
217*6777b538SAndroid Build Coastguard Worker   // Stack sampler which stops the thread and collects stack frames. The
218*6777b538SAndroid Build Coastguard Worker   // ownership of this object will be transferred to the sampling thread when
219*6777b538SAndroid Build Coastguard Worker   // thread sampling starts.
220*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<StackSampler> sampler_;
221*6777b538SAndroid Build Coastguard Worker 
222*6777b538SAndroid Build Coastguard Worker   // This starts "signaled", is reset when sampling begins, and is signaled
223*6777b538SAndroid Build Coastguard Worker   // when that sampling is complete and the profile_builder_'s
224*6777b538SAndroid Build Coastguard Worker   // OnProfileCompleted function has executed.
225*6777b538SAndroid Build Coastguard Worker   WaitableEvent profiling_inactive_;
226*6777b538SAndroid Build Coastguard Worker 
227*6777b538SAndroid Build Coastguard Worker   // An ID uniquely identifying this profiler to the sampling thread. This
228*6777b538SAndroid Build Coastguard Worker   // will be an internal "null" value when no collection has been started.
229*6777b538SAndroid Build Coastguard Worker   int profiler_id_;
230*6777b538SAndroid Build Coastguard Worker };
231*6777b538SAndroid Build Coastguard Worker 
232*6777b538SAndroid Build Coastguard Worker }  // namespace base
233*6777b538SAndroid Build Coastguard Worker 
234*6777b538SAndroid Build Coastguard Worker #endif  // BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
235