| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/profiler/stack_sampling_profiler.h" | 5 #include "base/profiler/stack_sampling_profiler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 void AsyncRunner::RunCallbackAndDeleteInstance( | 74 void AsyncRunner::RunCallbackAndDeleteInstance( |
| 75 std::unique_ptr<AsyncRunner> object_to_be_deleted, | 75 std::unique_ptr<AsyncRunner> object_to_be_deleted, |
| 76 const StackSamplingProfiler::CompletedCallback& callback, | 76 const StackSamplingProfiler::CompletedCallback& callback, |
| 77 scoped_refptr<SingleThreadTaskRunner> task_runner, | 77 scoped_refptr<SingleThreadTaskRunner> task_runner, |
| 78 const StackSamplingProfiler::CallStackProfiles& profiles) { | 78 const StackSamplingProfiler::CallStackProfiles& profiles) { |
| 79 callback.Run(profiles); | 79 callback.Run(profiles); |
| 80 // Delete the instance on the original calling thread. | 80 // Delete the instance on the original calling thread. |
| 81 task_runner->DeleteSoon(FROM_HERE, object_to_be_deleted.release()); | 81 task_runner->DeleteSoon(FROM_HERE, object_to_be_deleted.release()); |
| 82 } | 82 } |
| 83 | 83 |
| 84 void ChangeAtomicFlags(subtle::Atomic32* flags, |
| 85 subtle::Atomic32 set, |
| 86 subtle::Atomic32 clear) { |
| 87 DCHECK(set != 0 || clear != 0); |
| 88 DCHECK_EQ(0, set & clear); |
| 89 |
| 90 subtle::Atomic32 bits = subtle::NoBarrier_Load(flags); |
| 91 while (true) { |
| 92 subtle::Atomic32 existing = |
| 93 subtle::NoBarrier_CompareAndSwap(flags, bits, (bits | set) & ~clear); |
| 94 if (existing == bits) |
| 95 break; |
| 96 bits = existing; |
| 97 } |
| 98 } |
| 99 |
| 84 } // namespace | 100 } // namespace |
| 85 | 101 |
| 86 // StackSamplingProfiler::Module ---------------------------------------------- | 102 // StackSamplingProfiler::Module ---------------------------------------------- |
| 87 | 103 |
| 88 StackSamplingProfiler::Module::Module() : base_address(0u) {} | 104 StackSamplingProfiler::Module::Module() : base_address(0u) {} |
| 89 StackSamplingProfiler::Module::Module(uintptr_t base_address, | 105 StackSamplingProfiler::Module::Module(uintptr_t base_address, |
| 90 const std::string& id, | 106 const std::string& id, |
| 91 const FilePath& filename) | 107 const FilePath& filename) |
| 92 : base_address(base_address), id(id), filename(filename) {} | 108 : base_address(base_address), id(id), filename(filename) {} |
| 93 | 109 |
| 94 StackSamplingProfiler::Module::~Module() {} | 110 StackSamplingProfiler::Module::~Module() {} |
| 95 | 111 |
| 96 // StackSamplingProfiler::Frame ----------------------------------------------- | 112 // StackSamplingProfiler::Frame ----------------------------------------------- |
| 97 | 113 |
| 98 StackSamplingProfiler::Frame::Frame(uintptr_t instruction_pointer, | 114 StackSamplingProfiler::Frame::Frame(uintptr_t instruction_pointer, |
| 99 size_t module_index) | 115 size_t module_index) |
| 100 : instruction_pointer(instruction_pointer), module_index(module_index) {} | 116 : instruction_pointer(instruction_pointer), module_index(module_index) {} |
| 101 | 117 |
| 102 StackSamplingProfiler::Frame::~Frame() {} | 118 StackSamplingProfiler::Frame::~Frame() {} |
| 103 | 119 |
| 104 StackSamplingProfiler::Frame::Frame() | 120 StackSamplingProfiler::Frame::Frame() |
| 105 : instruction_pointer(0), module_index(kUnknownModuleIndex) { | 121 : instruction_pointer(0), module_index(kUnknownModuleIndex) { |
| 106 } | 122 } |
| 107 | 123 |
| 124 // StackSamplingProfiler::Sample ---------------------------------------------- |
| 125 |
| 126 StackSamplingProfiler::Sample::Sample() {} |
| 127 |
| 128 StackSamplingProfiler::Sample::Sample(const Sample& sample) = default; |
| 129 |
| 130 StackSamplingProfiler::Sample::~Sample() {} |
| 131 |
| 132 StackSamplingProfiler::Sample::Sample(const Frame& frame) { |
| 133 frames.push_back(std::move(frame)); |
| 134 } |
| 135 |
| 136 StackSamplingProfiler::Sample::Sample(const std::vector<Frame>& frames) |
| 137 : frames(frames) {} |
| 138 |
| 108 // StackSamplingProfiler::CallStackProfile ------------------------------------ | 139 // StackSamplingProfiler::CallStackProfile ------------------------------------ |
| 109 | 140 |
| 110 StackSamplingProfiler::CallStackProfile::CallStackProfile() {} | 141 StackSamplingProfiler::CallStackProfile::CallStackProfile() {} |
| 111 | 142 |
| 112 StackSamplingProfiler::CallStackProfile::CallStackProfile( | 143 StackSamplingProfiler::CallStackProfile::CallStackProfile( |
| 113 const CallStackProfile& other) = default; | 144 const CallStackProfile& other) = default; |
| 114 | 145 |
| 115 StackSamplingProfiler::CallStackProfile::~CallStackProfile() {} | 146 StackSamplingProfiler::CallStackProfile::~CallStackProfile() {} |
| 116 | 147 |
| 117 // StackSamplingProfiler::SamplingThread -------------------------------------- | 148 // StackSamplingProfiler::SamplingThread -------------------------------------- |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 // stop_event_. | 195 // stop_event_. |
| 165 if (stop_event_.TimedWait( | 196 if (stop_event_.TimedWait( |
| 166 std::max(params_.sampling_interval - previous_elapsed_sample_time, | 197 std::max(params_.sampling_interval - previous_elapsed_sample_time, |
| 167 TimeDelta()))) { | 198 TimeDelta()))) { |
| 168 *was_stopped = true; | 199 *was_stopped = true; |
| 169 break; | 200 break; |
| 170 } | 201 } |
| 171 } | 202 } |
| 172 ElapsedTimer sample_timer; | 203 ElapsedTimer sample_timer; |
| 173 profile->samples.push_back(Sample()); | 204 profile->samples.push_back(Sample()); |
| 174 native_sampler_->RecordStackSample(&profile->samples.back()); | 205 Sample& sample = profile->samples.back(); |
| 206 native_sampler_->RecordStackSample(&sample); |
| 175 previous_elapsed_sample_time = sample_timer.Elapsed(); | 207 previous_elapsed_sample_time = sample_timer.Elapsed(); |
| 176 } | 208 } |
| 177 | 209 |
| 178 *elapsed_time = profile_timer.Elapsed(); | 210 *elapsed_time = profile_timer.Elapsed(); |
| 179 profile->profile_duration = *elapsed_time; | 211 profile->profile_duration = *elapsed_time; |
| 180 native_sampler_->ProfileRecordingStopped(); | 212 native_sampler_->ProfileRecordingStopped(); |
| 181 } | 213 } |
| 182 | 214 |
| 183 // In an analogous manner to CollectProfile() and samples exceeding the expected | 215 // In an analogous manner to CollectProfile() and samples exceeding the expected |
| 184 // total sampling time, bursts may also exceed the burst_interval. We adopt the | 216 // total sampling time, bursts may also exceed the burst_interval. We adopt the |
| (...skipping 24 matching lines...) Expand all Loading... |
| 209 return; | 241 return; |
| 210 } | 242 } |
| 211 } | 243 } |
| 212 | 244 |
| 213 void StackSamplingProfiler::SamplingThread::Stop() { | 245 void StackSamplingProfiler::SamplingThread::Stop() { |
| 214 stop_event_.Signal(); | 246 stop_event_.Signal(); |
| 215 } | 247 } |
| 216 | 248 |
| 217 // StackSamplingProfiler ------------------------------------------------------ | 249 // StackSamplingProfiler ------------------------------------------------------ |
| 218 | 250 |
| 251 subtle::Atomic32 StackSamplingProfiler::process_phases_ = 0; |
| 252 subtle::Atomic32 StackSamplingProfiler::current_activities_ = 0; |
| 253 |
| 219 StackSamplingProfiler::SamplingParams::SamplingParams() | 254 StackSamplingProfiler::SamplingParams::SamplingParams() |
| 220 : initial_delay(TimeDelta::FromMilliseconds(0)), | 255 : initial_delay(TimeDelta::FromMilliseconds(0)), |
| 221 bursts(1), | 256 bursts(1), |
| 222 burst_interval(TimeDelta::FromMilliseconds(10000)), | 257 burst_interval(TimeDelta::FromMilliseconds(10000)), |
| 223 samples_per_burst(300), | 258 samples_per_burst(300), |
| 224 sampling_interval(TimeDelta::FromMilliseconds(100)) { | 259 sampling_interval(TimeDelta::FromMilliseconds(100)) { |
| 225 } | 260 } |
| 226 | 261 |
| 227 StackSamplingProfiler::StackSamplingProfiler( | 262 StackSamplingProfiler::StackSamplingProfiler( |
| 228 PlatformThreadId thread_id, | 263 PlatformThreadId thread_id, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 252 const CompletedCallback& callback) { | 287 const CompletedCallback& callback) { |
| 253 CHECK(ThreadTaskRunnerHandle::Get()); | 288 CHECK(ThreadTaskRunnerHandle::Get()); |
| 254 AsyncRunner::Run(thread_id, params, callback); | 289 AsyncRunner::Run(thread_id, params, callback); |
| 255 } | 290 } |
| 256 | 291 |
| 257 void StackSamplingProfiler::Start() { | 292 void StackSamplingProfiler::Start() { |
| 258 if (completed_callback_.is_null()) | 293 if (completed_callback_.is_null()) |
| 259 return; | 294 return; |
| 260 | 295 |
| 261 std::unique_ptr<NativeStackSampler> native_sampler = | 296 std::unique_ptr<NativeStackSampler> native_sampler = |
| 262 NativeStackSampler::Create(thread_id_, test_delegate_); | 297 NativeStackSampler::Create(thread_id_, Bind(&RecordAnnotations), |
| 298 test_delegate_); |
| 263 if (!native_sampler) | 299 if (!native_sampler) |
| 264 return; | 300 return; |
| 265 | 301 |
| 266 sampling_thread_.reset(new SamplingThread(std::move(native_sampler), params_, | 302 sampling_thread_.reset(new SamplingThread(std::move(native_sampler), params_, |
| 267 completed_callback_)); | 303 completed_callback_)); |
| 268 if (!PlatformThread::Create(0, sampling_thread_.get(), | 304 if (!PlatformThread::Create(0, sampling_thread_.get(), |
| 269 &sampling_thread_handle_)) | 305 &sampling_thread_handle_)) |
| 270 sampling_thread_.reset(); | 306 sampling_thread_.reset(); |
| 271 } | 307 } |
| 272 | 308 |
| 273 void StackSamplingProfiler::Stop() { | 309 void StackSamplingProfiler::Stop() { |
| 274 if (sampling_thread_) | 310 if (sampling_thread_) |
| 275 sampling_thread_->Stop(); | 311 sampling_thread_->Stop(); |
| 276 } | 312 } |
| 277 | 313 |
| 314 // static |
| 315 void StackSamplingProfiler::SetProcessPhase(ProcessPhase phase) { |
| 316 DCHECK_EQ(0, subtle::NoBarrier_Load(&process_phases_) & (1 << phase)); |
| 317 ChangeAtomicFlags(&process_phases_, 1 << phase, 0); |
| 318 } |
| 319 |
| 320 // static |
| 321 void StackSamplingProfiler::RecordActivityBegin(ProcessActivity activity) { |
| 322 ChangeAtomicFlags(¤t_activities_, 1 << activity, 0); |
| 323 } |
| 324 |
| 325 // static |
| 326 void StackSamplingProfiler::RecordActivityEnd(ProcessActivity activity) { |
| 327 ChangeAtomicFlags(¤t_activities_, 0, 1 << activity); |
| 328 } |
| 329 |
| 330 // static |
| 331 void StackSamplingProfiler::RecordAnnotations(Sample* sample) { |
| 332 sample->process_phases = subtle::NoBarrier_Load(&process_phases_); |
| 333 sample->current_activities = subtle::NoBarrier_Load(¤t_activities_); |
| 334 } |
| 335 |
| 278 // StackSamplingProfiler::Frame global functions ------------------------------ | 336 // StackSamplingProfiler::Frame global functions ------------------------------ |
| 279 | 337 |
| 280 bool operator==(const StackSamplingProfiler::Module& a, | 338 bool operator==(const StackSamplingProfiler::Module& a, |
| 281 const StackSamplingProfiler::Module& b) { | 339 const StackSamplingProfiler::Module& b) { |
| 282 return a.base_address == b.base_address && a.id == b.id && | 340 return a.base_address == b.base_address && a.id == b.id && |
| 283 a.filename == b.filename; | 341 a.filename == b.filename; |
| 284 } | 342 } |
| 285 | 343 |
| 344 bool operator==(const StackSamplingProfiler::Sample& a, |
| 345 const StackSamplingProfiler::Sample& b) { |
| 346 return a.process_phases == b.process_phases && |
| 347 a.current_activities == b.current_activities && a.frames == b.frames; |
| 348 } |
| 349 |
| 350 bool operator!=(const StackSamplingProfiler::Sample& a, |
| 351 const StackSamplingProfiler::Sample& b) { |
| 352 return !(a == b); |
| 353 } |
| 354 |
| 355 bool operator<(const StackSamplingProfiler::Sample& a, |
| 356 const StackSamplingProfiler::Sample& b) { |
| 357 if (a.process_phases < b.process_phases) |
| 358 return true; |
| 359 if (a.process_phases > b.process_phases) |
| 360 return false; |
| 361 |
| 362 if (a.current_activities < b.current_activities) |
| 363 return true; |
| 364 if (a.current_activities > b.current_activities) |
| 365 return false; |
| 366 |
| 367 return a.frames < b.frames; |
| 368 } |
| 369 |
| 286 bool operator==(const StackSamplingProfiler::Frame &a, | 370 bool operator==(const StackSamplingProfiler::Frame &a, |
| 287 const StackSamplingProfiler::Frame &b) { | 371 const StackSamplingProfiler::Frame &b) { |
| 288 return a.instruction_pointer == b.instruction_pointer && | 372 return a.instruction_pointer == b.instruction_pointer && |
| 289 a.module_index == b.module_index; | 373 a.module_index == b.module_index; |
| 290 } | 374 } |
| 291 | 375 |
| 292 bool operator<(const StackSamplingProfiler::Frame &a, | 376 bool operator<(const StackSamplingProfiler::Frame &a, |
| 293 const StackSamplingProfiler::Frame &b) { | 377 const StackSamplingProfiler::Frame &b) { |
| 294 return (a.module_index < b.module_index) || | 378 return (a.module_index < b.module_index) || |
| 295 (a.module_index == b.module_index && | 379 (a.module_index == b.module_index && |
| 296 a.instruction_pointer < b.instruction_pointer); | 380 a.instruction_pointer < b.instruction_pointer); |
| 297 } | 381 } |
| 298 | 382 |
| 299 } // namespace base | 383 } // namespace base |
| OLD | NEW |