| OLD | NEW |
| (Empty) |
| 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 #include "base/profiler/stack_sampling_profiler.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/callback.h" | |
| 11 #include "base/memory/singleton.h" | |
| 12 #include "base/profiler/native_stack_sampler.h" | |
| 13 #include "base/synchronization/lock.h" | |
| 14 #include "base/timer/elapsed_timer.h" | |
| 15 | |
| 16 namespace base { | |
| 17 | |
| 18 // DefaultProfileProcessor ---------------------------------------------------- | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // Singleton class responsible for providing the default processing for profiles | |
| 23 // (i.e. for profiles generated by profilers without their own completed | |
| 24 // callback). | |
| 25 class DefaultProfileProcessor { | |
| 26 public: | |
| 27 using CompletedCallback = StackSamplingProfiler::CompletedCallback; | |
| 28 | |
| 29 ~DefaultProfileProcessor(); | |
| 30 | |
| 31 static DefaultProfileProcessor* GetInstance(); | |
| 32 | |
| 33 // Sets the callback to use for processing profiles captured without a | |
| 34 // per-profiler completed callback. Pending completed profiles are stored in | |
| 35 // this object until a non-null callback is provided here. This function is | |
| 36 // thread-safe. | |
| 37 void SetCompletedCallback(CompletedCallback callback); | |
| 38 | |
| 39 // Processes |profiles|. This function is thread safe. | |
| 40 void ProcessProfiles( | |
| 41 const StackSamplingProfiler::CallStackProfiles& profiles); | |
| 42 | |
| 43 private: | |
| 44 friend struct DefaultSingletonTraits<DefaultProfileProcessor>; | |
| 45 | |
| 46 DefaultProfileProcessor(); | |
| 47 | |
| 48 // Copies the pending profiles from |profiles_| into |profiles|, and clears | |
| 49 // |profiles_|. This function may be called on any thread. | |
| 50 void GetAndClearPendingProfiles( | |
| 51 StackSamplingProfiler::CallStackProfiles* profiles); | |
| 52 | |
| 53 // Gets the current completed callback, with proper locking. | |
| 54 CompletedCallback GetCompletedCallback() const; | |
| 55 | |
| 56 mutable Lock callback_lock_; | |
| 57 CompletedCallback default_completed_callback_; | |
| 58 | |
| 59 Lock profiles_lock_; | |
| 60 StackSamplingProfiler::CallStackProfiles profiles_; | |
| 61 | |
| 62 DISALLOW_COPY_AND_ASSIGN(DefaultProfileProcessor); | |
| 63 }; | |
| 64 | |
| 65 DefaultProfileProcessor::~DefaultProfileProcessor() {} | |
| 66 | |
| 67 // static | |
| 68 DefaultProfileProcessor* DefaultProfileProcessor::GetInstance() { | |
| 69 return Singleton<DefaultProfileProcessor>::get(); | |
| 70 } | |
| 71 | |
| 72 void DefaultProfileProcessor::SetCompletedCallback(CompletedCallback callback) { | |
| 73 { | |
| 74 AutoLock scoped_lock(callback_lock_); | |
| 75 default_completed_callback_ = callback; | |
| 76 } | |
| 77 | |
| 78 if (!callback.is_null()) { | |
| 79 // Provide any pending profiles to the callback immediately. | |
| 80 StackSamplingProfiler::CallStackProfiles profiles; | |
| 81 GetAndClearPendingProfiles(&profiles); | |
| 82 if (!profiles.empty()) | |
| 83 callback.Run(profiles); | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 void DefaultProfileProcessor::ProcessProfiles( | |
| 88 const StackSamplingProfiler::CallStackProfiles& profiles) { | |
| 89 CompletedCallback callback = GetCompletedCallback(); | |
| 90 | |
| 91 // Store pending profiles if we don't have a valid callback. | |
| 92 if (!callback.is_null()) { | |
| 93 callback.Run(profiles); | |
| 94 } else { | |
| 95 AutoLock scoped_lock(profiles_lock_); | |
| 96 profiles_.insert(profiles_.end(), profiles.begin(), profiles.end()); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 DefaultProfileProcessor::DefaultProfileProcessor() {} | |
| 101 | |
| 102 void DefaultProfileProcessor::GetAndClearPendingProfiles( | |
| 103 StackSamplingProfiler::CallStackProfiles* profiles) { | |
| 104 profiles->clear(); | |
| 105 | |
| 106 AutoLock scoped_lock(profiles_lock_); | |
| 107 profiles_.swap(*profiles); | |
| 108 } | |
| 109 | |
| 110 DefaultProfileProcessor::CompletedCallback | |
| 111 DefaultProfileProcessor::GetCompletedCallback() const { | |
| 112 AutoLock scoped_lock(callback_lock_); | |
| 113 return default_completed_callback_; | |
| 114 } | |
| 115 | |
| 116 } // namespace | |
| 117 | |
| 118 // StackSamplingProfiler::Module ---------------------------------------------- | |
| 119 | |
| 120 StackSamplingProfiler::Module::Module() : base_address(nullptr) {} | |
| 121 StackSamplingProfiler::Module::Module(const void* base_address, | |
| 122 const std::string& id, | |
| 123 const FilePath& filename) | |
| 124 : base_address(base_address), id(id), filename(filename) {} | |
| 125 | |
| 126 StackSamplingProfiler::Module::~Module() {} | |
| 127 | |
| 128 // StackSamplingProfiler::Frame ----------------------------------------------- | |
| 129 | |
| 130 StackSamplingProfiler::Frame::Frame(const void* instruction_pointer, | |
| 131 size_t module_index) | |
| 132 : instruction_pointer(instruction_pointer), | |
| 133 module_index(module_index) {} | |
| 134 | |
| 135 StackSamplingProfiler::Frame::~Frame() {} | |
| 136 | |
| 137 // StackSamplingProfiler::CallStackProfile ------------------------------------ | |
| 138 | |
| 139 StackSamplingProfiler::CallStackProfile::CallStackProfile() | |
| 140 : preserve_sample_ordering(false), user_data(0) {} | |
| 141 | |
| 142 StackSamplingProfiler::CallStackProfile::~CallStackProfile() {} | |
| 143 | |
| 144 // StackSamplingProfiler::SamplingThread -------------------------------------- | |
| 145 | |
| 146 StackSamplingProfiler::SamplingThread::SamplingThread( | |
| 147 scoped_ptr<NativeStackSampler> native_sampler, | |
| 148 const SamplingParams& params, | |
| 149 CompletedCallback completed_callback) | |
| 150 : native_sampler_(native_sampler.Pass()), | |
| 151 params_(params), | |
| 152 stop_event_(false, false), | |
| 153 completed_callback_(completed_callback) { | |
| 154 } | |
| 155 | |
| 156 StackSamplingProfiler::SamplingThread::~SamplingThread() {} | |
| 157 | |
| 158 void StackSamplingProfiler::SamplingThread::ThreadMain() { | |
| 159 PlatformThread::SetName("Chrome_SamplingProfilerThread"); | |
| 160 | |
| 161 CallStackProfiles profiles; | |
| 162 CollectProfiles(&profiles); | |
| 163 completed_callback_.Run(profiles); | |
| 164 } | |
| 165 | |
| 166 // Depending on how long the sampling takes and the length of the sampling | |
| 167 // interval, a burst of samples could take arbitrarily longer than | |
| 168 // samples_per_burst * sampling_interval. In this case, we (somewhat | |
| 169 // arbitrarily) honor the number of samples requested rather than strictly | |
| 170 // adhering to the sampling intervals. Once we have established users for the | |
| 171 // StackSamplingProfiler and the collected data to judge, we may go the other | |
| 172 // way or make this behavior configurable. | |
| 173 bool StackSamplingProfiler::SamplingThread::CollectProfile( | |
| 174 CallStackProfile* profile, | |
| 175 TimeDelta* elapsed_time) { | |
| 176 ElapsedTimer profile_timer; | |
| 177 CallStackProfile current_profile; | |
| 178 native_sampler_->ProfileRecordingStarting(¤t_profile.modules); | |
| 179 current_profile.sampling_period = params_.sampling_interval; | |
| 180 bool burst_completed = true; | |
| 181 TimeDelta previous_elapsed_sample_time; | |
| 182 for (int i = 0; i < params_.samples_per_burst; ++i) { | |
| 183 if (i != 0) { | |
| 184 // Always wait, even if for 0 seconds, so we can observe a signal on | |
| 185 // stop_event_. | |
| 186 if (stop_event_.TimedWait( | |
| 187 std::max(params_.sampling_interval - previous_elapsed_sample_time, | |
| 188 TimeDelta()))) { | |
| 189 burst_completed = false; | |
| 190 break; | |
| 191 } | |
| 192 } | |
| 193 ElapsedTimer sample_timer; | |
| 194 current_profile.samples.push_back(Sample()); | |
| 195 native_sampler_->RecordStackSample(¤t_profile.samples.back()); | |
| 196 previous_elapsed_sample_time = sample_timer.Elapsed(); | |
| 197 } | |
| 198 | |
| 199 *elapsed_time = profile_timer.Elapsed(); | |
| 200 current_profile.profile_duration = *elapsed_time; | |
| 201 current_profile.preserve_sample_ordering = params_.preserve_sample_ordering; | |
| 202 current_profile.user_data = params_.user_data; | |
| 203 native_sampler_->ProfileRecordingStopped(); | |
| 204 | |
| 205 if (burst_completed) | |
| 206 *profile = current_profile; | |
| 207 | |
| 208 return burst_completed; | |
| 209 } | |
| 210 | |
| 211 // In an analogous manner to CollectProfile() and samples exceeding the expected | |
| 212 // total sampling time, bursts may also exceed the burst_interval. We adopt the | |
| 213 // same wait-and-see approach here. | |
| 214 void StackSamplingProfiler::SamplingThread::CollectProfiles( | |
| 215 CallStackProfiles* profiles) { | |
| 216 if (stop_event_.TimedWait(params_.initial_delay)) | |
| 217 return; | |
| 218 | |
| 219 TimeDelta previous_elapsed_profile_time; | |
| 220 for (int i = 0; i < params_.bursts; ++i) { | |
| 221 if (i != 0) { | |
| 222 // Always wait, even if for 0 seconds, so we can observe a signal on | |
| 223 // stop_event_. | |
| 224 if (stop_event_.TimedWait( | |
| 225 std::max(params_.burst_interval - previous_elapsed_profile_time, | |
| 226 TimeDelta()))) | |
| 227 return; | |
| 228 } | |
| 229 | |
| 230 CallStackProfile profile; | |
| 231 if (!CollectProfile(&profile, &previous_elapsed_profile_time)) | |
| 232 return; | |
| 233 profiles->push_back(profile); | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 void StackSamplingProfiler::SamplingThread::Stop() { | |
| 238 stop_event_.Signal(); | |
| 239 } | |
| 240 | |
| 241 // StackSamplingProfiler ------------------------------------------------------ | |
| 242 | |
| 243 StackSamplingProfiler::SamplingParams::SamplingParams() | |
| 244 : initial_delay(TimeDelta::FromMilliseconds(0)), | |
| 245 bursts(1), | |
| 246 burst_interval(TimeDelta::FromMilliseconds(10000)), | |
| 247 samples_per_burst(300), | |
| 248 sampling_interval(TimeDelta::FromMilliseconds(100)), | |
| 249 preserve_sample_ordering(false), | |
| 250 user_data(0) { | |
| 251 } | |
| 252 | |
| 253 StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id, | |
| 254 const SamplingParams& params) | |
| 255 : thread_id_(thread_id), params_(params) {} | |
| 256 | |
| 257 StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id, | |
| 258 const SamplingParams& params, | |
| 259 CompletedCallback callback) | |
| 260 : thread_id_(thread_id), params_(params), completed_callback_(callback) {} | |
| 261 | |
| 262 StackSamplingProfiler::~StackSamplingProfiler() { | |
| 263 Stop(); | |
| 264 if (!sampling_thread_handle_.is_null()) | |
| 265 PlatformThread::Join(sampling_thread_handle_); | |
| 266 } | |
| 267 | |
| 268 void StackSamplingProfiler::Start() { | |
| 269 scoped_ptr<NativeStackSampler> native_sampler = | |
| 270 NativeStackSampler::Create(thread_id_); | |
| 271 if (!native_sampler) | |
| 272 return; | |
| 273 | |
| 274 CompletedCallback callback = | |
| 275 !completed_callback_.is_null() ? completed_callback_ : | |
| 276 Bind(&DefaultProfileProcessor::ProcessProfiles, | |
| 277 Unretained(DefaultProfileProcessor::GetInstance())); | |
| 278 sampling_thread_.reset( | |
| 279 new SamplingThread(native_sampler.Pass(), params_, callback)); | |
| 280 if (!PlatformThread::Create(0, sampling_thread_.get(), | |
| 281 &sampling_thread_handle_)) | |
| 282 sampling_thread_.reset(); | |
| 283 } | |
| 284 | |
| 285 void StackSamplingProfiler::Stop() { | |
| 286 if (sampling_thread_) | |
| 287 sampling_thread_->Stop(); | |
| 288 } | |
| 289 | |
| 290 // static | |
| 291 void StackSamplingProfiler::SetDefaultCompletedCallback( | |
| 292 CompletedCallback callback) { | |
| 293 DefaultProfileProcessor::GetInstance()->SetCompletedCallback(callback); | |
| 294 } | |
| 295 | |
| 296 // StackSamplingProfiler::Frame global functions ------------------------------ | |
| 297 | |
| 298 bool operator==(const StackSamplingProfiler::Frame &a, | |
| 299 const StackSamplingProfiler::Frame &b) { | |
| 300 return a.instruction_pointer == b.instruction_pointer && | |
| 301 a.module_index == b.module_index; | |
| 302 } | |
| 303 | |
| 304 bool operator<(const StackSamplingProfiler::Frame &a, | |
| 305 const StackSamplingProfiler::Frame &b) { | |
| 306 return (a.module_index < b.module_index) || | |
| 307 (a.module_index == b.module_index && | |
| 308 a.instruction_pointer < b.instruction_pointer); | |
| 309 } | |
| 310 | |
| 311 } // namespace base | |
| OLD | NEW |