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