Index: base/debug/trace_event_synthetic_delay.cc |
diff --git a/base/debug/trace_event_synthetic_delay.cc b/base/debug/trace_event_synthetic_delay.cc |
index 939d9602653ed55e59cba6de2f85fa38e830d6c2..0d07a70c6a5fc3e3fd5414bd378462ad2674a286 100644 |
--- a/base/debug/trace_event_synthetic_delay.cc |
+++ b/base/debug/trace_event_synthetic_delay.cc |
@@ -4,8 +4,6 @@ |
#include "base/debug/trace_event_synthetic_delay.h" |
#include "base/memory/singleton.h" |
-#include "base/threading/platform_thread.h" |
-#include "base/threading/thread_local.h" |
namespace { |
const int kMaxSyntheticDelays = 32; |
@@ -17,24 +15,12 @@ namespace debug { |
TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {} |
TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {} |
-// Thread-local state for each synthetic delay point. This allows the same delay |
-// to be applied to multiple threads simultaneously. |
-struct ThreadState { |
- ThreadState(); |
- |
- base::TimeTicks start_time; |
- unsigned trigger_count; |
- int generation; |
-}; |
- |
-ThreadState::ThreadState() : trigger_count(0u), generation(0) {} |
- |
class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock { |
public: |
static TraceEventSyntheticDelayRegistry* GetInstance(); |
TraceEventSyntheticDelay* GetOrCreateDelay(const char* name); |
- ThreadState* GetThreadState(int index); |
+ void ResetAllDelays(); |
// TraceEventSyntheticDelayClock implementation. |
virtual base::TimeTicks Now() OVERRIDE; |
@@ -49,13 +35,11 @@ class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock { |
TraceEventSyntheticDelay dummy_delay_; |
base::subtle::Atomic32 delay_count_; |
- ThreadLocalPointer<ThreadState> thread_states_; |
- |
DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry); |
}; |
TraceEventSyntheticDelay::TraceEventSyntheticDelay() |
- : mode_(STATIC), generation_(0), thread_state_index_(0), clock_(NULL) {} |
+ : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {} |
TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {} |
@@ -67,33 +51,30 @@ TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup( |
void TraceEventSyntheticDelay::Initialize( |
const std::string& name, |
- TraceEventSyntheticDelayClock* clock, |
- int thread_state_index) { |
+ TraceEventSyntheticDelayClock* clock) { |
name_ = name; |
clock_ = clock; |
- thread_state_index_ = thread_state_index; |
} |
void TraceEventSyntheticDelay::SetTargetDuration( |
base::TimeDelta target_duration) { |
AutoLock lock(lock_); |
target_duration_ = target_duration; |
- generation_++; |
+ trigger_count_ = 0; |
+ begin_count_ = 0; |
} |
void TraceEventSyntheticDelay::SetMode(Mode mode) { |
AutoLock lock(lock_); |
mode_ = mode; |
- generation_++; |
} |
void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { |
AutoLock lock(lock_); |
clock_ = clock; |
- generation_++; |
} |
-void TraceEventSyntheticDelay::Activate() { |
+void TraceEventSyntheticDelay::Begin() { |
// Note that we check for a non-zero target duration without locking to keep |
// things quick for the common case when delays are disabled. Since the delay |
// calculation is done with a lock held, it will always be correct. The only |
@@ -103,45 +84,59 @@ void TraceEventSyntheticDelay::Activate() { |
if (!target_duration_.ToInternalValue()) |
return; |
- ThreadState* thread_state = |
- TraceEventSyntheticDelayRegistry::GetInstance()-> |
- GetThreadState(thread_state_index_); |
- if (!thread_state->start_time.ToInternalValue()) |
- thread_state->start_time = clock_->Now(); |
+ base::TimeTicks start_time = clock_->Now(); |
+ { |
+ AutoLock lock(lock_); |
+ if (++begin_count_ != 1) |
+ return; |
+ end_time_ = CalculateEndTimeLocked(start_time); |
+ } |
} |
-void TraceEventSyntheticDelay::Apply() { |
+void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) { |
+ // See note in Begin(). |
ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
- if (!target_duration_.ToInternalValue()) |
- return; |
- |
- ThreadState* thread_state = |
- TraceEventSyntheticDelayRegistry::GetInstance()-> |
- GetThreadState(thread_state_index_); |
- if (!thread_state->start_time.ToInternalValue()) |
+ if (!target_duration_.ToInternalValue()) { |
+ *out_end_time = base::TimeTicks(); |
return; |
- base::TimeTicks now = clock_->Now(); |
- base::TimeTicks start_time = thread_state->start_time; |
- base::TimeTicks end_time; |
- thread_state->start_time = base::TimeTicks(); |
+ } |
+ base::TimeTicks start_time = clock_->Now(); |
{ |
AutoLock lock(lock_); |
- if (thread_state->generation != generation_) { |
- thread_state->trigger_count = 0; |
- thread_state->generation = generation_; |
- } |
+ *out_end_time = CalculateEndTimeLocked(start_time); |
+ } |
+} |
- if (mode_ == ONE_SHOT && thread_state->trigger_count++) |
- return; |
- else if (mode_ == ALTERNATING && thread_state->trigger_count++ % 2) |
- return; |
+void TraceEventSyntheticDelay::End() { |
+ // See note in Begin(). |
+ ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
+ if (!target_duration_.ToInternalValue()) |
+ return; |
- end_time = start_time + target_duration_; |
- if (now >= end_time) |
+ base::TimeTicks end_time; |
+ { |
+ AutoLock lock(lock_); |
+ if (!begin_count_ || --begin_count_ != 0) |
return; |
+ end_time = end_time_; |
} |
- ApplyDelay(end_time); |
+ if (!end_time.is_null()) |
+ ApplyDelay(end_time); |
+} |
+ |
+void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) { |
+ if (!end_time.is_null()) |
+ ApplyDelay(end_time); |
+} |
+ |
+base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked( |
+ base::TimeTicks start_time) { |
+ if (mode_ == ONE_SHOT && trigger_count_++) |
+ return base::TimeTicks(); |
+ else if (mode_ == ALTERNATING && trigger_count_++ % 2) |
+ return base::TimeTicks(); |
+ return start_time + target_duration_; |
} |
void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) { |
@@ -183,26 +178,24 @@ TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay( |
if (delay_count >= kMaxSyntheticDelays) |
return &dummy_delay_; |
- delays_[delay_count].Initialize(std::string(name), this, delay_count); |
+ delays_[delay_count].Initialize(std::string(name), this); |
base::subtle::Release_Store(&delay_count_, delay_count + 1); |
return &delays_[delay_count]; |
} |
-ThreadState* TraceEventSyntheticDelayRegistry::GetThreadState(int index) { |
- DCHECK(index >= 0 && index < kMaxSyntheticDelays); |
- if (index < 0 || index >= kMaxSyntheticDelays) |
- return NULL; |
+base::TimeTicks TraceEventSyntheticDelayRegistry::Now() { |
+ return base::TimeTicks::HighResNow(); |
+} |
- // Note that these thread states are leaked at program exit. They will only |
- // get allocated if synthetic delays are actually used. |
- ThreadState* thread_states = thread_states_.Get(); |
- if (!thread_states) |
- thread_states_.Set((thread_states = new ThreadState[kMaxSyntheticDelays])); |
- return &thread_states[index]; |
+void TraceEventSyntheticDelayRegistry::ResetAllDelays() { |
+ AutoLock lock(lock_); |
+ int delay_count = base::subtle::Acquire_Load(&delay_count_); |
+ for (int i = 0; i < delay_count; ++i) |
+ delays_[i].SetTargetDuration(base::TimeDelta()); |
} |
-base::TimeTicks TraceEventSyntheticDelayRegistry::Now() { |
- return base::TimeTicks::HighResNow(); |
+void ResetTraceEventSyntheticDelays() { |
+ TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays(); |
} |
} // namespace debug |
@@ -213,10 +206,12 @@ namespace trace_event_internal { |
ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, |
base::subtle::AtomicWord* impl_ptr) |
: delay_impl_(GetOrCreateDelay(name, impl_ptr)) { |
- delay_impl_->Activate(); |
+ delay_impl_->BeginParallel(&end_time_); |
} |
-ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->Apply(); } |
+ScopedSyntheticDelay::~ScopedSyntheticDelay() { |
+ delay_impl_->EndParallel(end_time_); |
+} |
base::debug::TraceEventSyntheticDelay* GetOrCreateDelay( |
const char* name, |