Chromium Code Reviews| Index: base/profiler/stack_sampling_profiler.cc |
| diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc |
| index e25440f80c56b32896b0f018b38e2514086f933d..d3e1945ef15764cf5faedd78511b424fdba383ec 100644 |
| --- a/base/profiler/stack_sampling_profiler.cc |
| +++ b/base/profiler/stack_sampling_profiler.cc |
| @@ -82,6 +82,22 @@ void AsyncRunner::RunCallbackAndDeleteInstance( |
| task_runner->DeleteSoon(FROM_HERE, object_to_be_deleted.release()); |
| } |
| +void ChangeAtomicFlags(subtle::Atomic32* flags, |
| + subtle::Atomic32 set, |
| + subtle::Atomic32 clear) { |
| + DCHECK(set != 0 || clear != 0); |
| + DCHECK_EQ(0, set & clear); |
| + |
| + subtle::Atomic32 bits = subtle::NoBarrier_Load(flags); |
| + while (true) { |
| + subtle::Atomic32 existing = |
| + subtle::NoBarrier_CompareAndSwap(flags, bits, (bits | set) & ~clear); |
| + if (existing == bits) |
| + break; |
| + bits = existing; |
| + } |
| +} |
|
Alexei Svitkine (slow)
2016/11/07 23:22:07
We have other functions elsewhere:
https://cs.chr
bcwhite
2016/11/08 01:02:36
Those are different beasts. They're effectively a
|
| + |
| } // namespace |
| // StackSamplingProfiler::Module ---------------------------------------------- |
| @@ -106,6 +122,21 @@ StackSamplingProfiler::Frame::Frame() |
| : instruction_pointer(0), module_index(kUnknownModuleIndex) { |
| } |
| +// StackSamplingProfiler::Sample ---------------------------------------------- |
| + |
| +StackSamplingProfiler::Sample::Sample() {} |
| + |
| +StackSamplingProfiler::Sample::Sample(const Sample& sample) = default; |
| + |
| +StackSamplingProfiler::Sample::~Sample() {} |
| + |
| +StackSamplingProfiler::Sample::Sample(const Frame& frame) { |
| + frames.push_back(std::move(frame)); |
| +} |
| + |
| +StackSamplingProfiler::Sample::Sample(const std::vector<Frame>& frames) |
| + : frames(frames) {} |
| + |
| // StackSamplingProfiler::CallStackProfile ------------------------------------ |
| StackSamplingProfiler::CallStackProfile::CallStackProfile() {} |
| @@ -184,7 +215,8 @@ void StackSamplingProfiler::SamplingThread::CollectProfile( |
| } |
| ElapsedTimer sample_timer; |
| profile->samples.push_back(Sample()); |
| - native_sampler_->RecordStackSample(&profile->samples.back()); |
| + Sample& sample = profile->samples.back(); |
| + native_sampler_->RecordStackSample(&sample); |
| previous_elapsed_sample_time = sample_timer.Elapsed(); |
| } |
| @@ -229,6 +261,9 @@ void StackSamplingProfiler::SamplingThread::Stop() { |
| // StackSamplingProfiler ------------------------------------------------------ |
| +subtle::Atomic32 StackSamplingProfiler::process_phases_ = 0; |
| +subtle::Atomic32 StackSamplingProfiler::current_activities_ = 0; |
| + |
| StackSamplingProfiler::SamplingParams::SamplingParams() |
| : initial_delay(TimeDelta::FromMilliseconds(0)), |
| bursts(1), |
| @@ -272,7 +307,8 @@ void StackSamplingProfiler::Start() { |
| return; |
| std::unique_ptr<NativeStackSampler> native_sampler = |
| - NativeStackSampler::Create(thread_id_, test_delegate_); |
| + NativeStackSampler::Create(thread_id_, &RecordAnnotations, |
| + test_delegate_); |
| if (!native_sampler) |
| return; |
| @@ -288,6 +324,43 @@ void StackSamplingProfiler::Stop() { |
| sampling_thread_->Stop(); |
| } |
| +// static |
| +void StackSamplingProfiler::SetProcessPhase(int phase) { |
| + DCHECK_LE(0, phase); |
| + DCHECK_GT(static_cast<int>(sizeof(process_phases_) * 8), phase); |
| + DCHECK_EQ(0, subtle::NoBarrier_Load(&process_phases_) & (1 << phase)); |
| + ChangeAtomicFlags(&process_phases_, 1 << phase, 0); |
| +} |
| + |
| +// static |
| +void StackSamplingProfiler::RecordActivityBegin(int activity) { |
| + DCHECK_LE(0, activity); |
| + DCHECK_GT(static_cast<int>(sizeof(current_activities_) * 8), activity); |
| + ChangeAtomicFlags(¤t_activities_, 1 << activity, 0); |
| +} |
| + |
| +// static |
| +void StackSamplingProfiler::RecordActivityEnd(int activity) { |
| + DCHECK_LE(0, activity); |
| + DCHECK_GT(static_cast<int>(sizeof(current_activities_) * 8), activity); |
| + ChangeAtomicFlags(¤t_activities_, 0, 1 << activity); |
| +} |
| + |
| +// static |
| +void StackSamplingProfiler::ResetPhaseAndActivityForTesting() { |
| + subtle::NoBarrier_Store(&process_phases_, 0u); |
| + subtle::NoBarrier_Store(¤t_activities_, 0u); |
| +} |
| + |
| +// The code inside this method must not do anything that could acquire a mutex, |
| +// including allocating memory (which includes LOG messages) because that mutex |
| +// could be held by a stopped thread, thus resulting in deadlock. |
| +// static |
| +void StackSamplingProfiler::RecordAnnotations(Sample* sample) { |
| + sample->process_phases = subtle::NoBarrier_Load(&process_phases_); |
| + sample->current_activities = subtle::NoBarrier_Load(¤t_activities_); |
| +} |
| + |
| // StackSamplingProfiler::Frame global functions ------------------------------ |
| bool operator==(const StackSamplingProfiler::Module& a, |
| @@ -296,6 +369,32 @@ bool operator==(const StackSamplingProfiler::Module& a, |
| a.filename == b.filename; |
| } |
| +bool operator==(const StackSamplingProfiler::Sample& a, |
| + const StackSamplingProfiler::Sample& b) { |
| + return a.process_phases == b.process_phases && |
| + a.current_activities == b.current_activities && a.frames == b.frames; |
| +} |
| + |
| +bool operator!=(const StackSamplingProfiler::Sample& a, |
| + const StackSamplingProfiler::Sample& b) { |
| + return !(a == b); |
| +} |
| + |
| +bool operator<(const StackSamplingProfiler::Sample& a, |
| + const StackSamplingProfiler::Sample& b) { |
| + if (a.process_phases < b.process_phases) |
| + return true; |
| + if (a.process_phases > b.process_phases) |
| + return false; |
| + |
| + if (a.current_activities < b.current_activities) |
| + return true; |
| + if (a.current_activities > b.current_activities) |
| + return false; |
| + |
| + return a.frames < b.frames; |
| +} |
| + |
| bool operator==(const StackSamplingProfiler::Frame &a, |
| const StackSamplingProfiler::Frame &b) { |
| return a.instruction_pointer == b.instruction_pointer && |