Home | History | Annotate | Download | only in debug
      1 // Copyright 2014 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/debug/trace_event_synthetic_delay.h"
      6 #include "base/memory/singleton.h"
      7 
      8 namespace {
      9 const int kMaxSyntheticDelays = 32;
     10 }  // namespace
     11 
     12 namespace base {
     13 namespace debug {
     14 
     15 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
     16 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
     17 
     18 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
     19  public:
     20   static TraceEventSyntheticDelayRegistry* GetInstance();
     21 
     22   TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
     23   void ResetAllDelays();
     24 
     25   // TraceEventSyntheticDelayClock implementation.
     26   virtual base::TimeTicks Now() OVERRIDE;
     27 
     28  private:
     29   TraceEventSyntheticDelayRegistry();
     30 
     31   friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
     32 
     33   Lock lock_;
     34   TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
     35   TraceEventSyntheticDelay dummy_delay_;
     36   base::subtle::Atomic32 delay_count_;
     37 
     38   DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
     39 };
     40 
     41 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
     42     : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
     43 
     44 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
     45 
     46 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
     47     const std::string& name) {
     48   return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
     49       name.c_str());
     50 }
     51 
     52 void TraceEventSyntheticDelay::Initialize(
     53     const std::string& name,
     54     TraceEventSyntheticDelayClock* clock) {
     55   name_ = name;
     56   clock_ = clock;
     57 }
     58 
     59 void TraceEventSyntheticDelay::SetTargetDuration(
     60     base::TimeDelta target_duration) {
     61   AutoLock lock(lock_);
     62   target_duration_ = target_duration;
     63   trigger_count_ = 0;
     64   begin_count_ = 0;
     65 }
     66 
     67 void TraceEventSyntheticDelay::SetMode(Mode mode) {
     68   AutoLock lock(lock_);
     69   mode_ = mode;
     70 }
     71 
     72 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
     73   AutoLock lock(lock_);
     74   clock_ = clock;
     75 }
     76 
     77 void TraceEventSyntheticDelay::Begin() {
     78   // Note that we check for a non-zero target duration without locking to keep
     79   // things quick for the common case when delays are disabled. Since the delay
     80   // calculation is done with a lock held, it will always be correct. The only
     81   // downside of this is that we may fail to apply some delays when the target
     82   // duration changes.
     83   ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
     84   if (!target_duration_.ToInternalValue())
     85     return;
     86 
     87   base::TimeTicks start_time = clock_->Now();
     88   {
     89     AutoLock lock(lock_);
     90     if (++begin_count_ != 1)
     91       return;
     92     end_time_ = CalculateEndTimeLocked(start_time);
     93   }
     94 }
     95 
     96 void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) {
     97   // See note in Begin().
     98   ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
     99   if (!target_duration_.ToInternalValue()) {
    100     *out_end_time = base::TimeTicks();
    101     return;
    102   }
    103 
    104   base::TimeTicks start_time = clock_->Now();
    105   {
    106     AutoLock lock(lock_);
    107     *out_end_time = CalculateEndTimeLocked(start_time);
    108   }
    109 }
    110 
    111 void TraceEventSyntheticDelay::End() {
    112   // See note in Begin().
    113   ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
    114   if (!target_duration_.ToInternalValue())
    115     return;
    116 
    117   base::TimeTicks end_time;
    118   {
    119     AutoLock lock(lock_);
    120     if (!begin_count_ || --begin_count_ != 0)
    121       return;
    122     end_time = end_time_;
    123   }
    124   if (!end_time.is_null())
    125     ApplyDelay(end_time);
    126 }
    127 
    128 void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
    129   if (!end_time.is_null())
    130     ApplyDelay(end_time);
    131 }
    132 
    133 base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
    134     base::TimeTicks start_time) {
    135   if (mode_ == ONE_SHOT && trigger_count_++)
    136     return base::TimeTicks();
    137   else if (mode_ == ALTERNATING && trigger_count_++ % 2)
    138     return base::TimeTicks();
    139   return start_time + target_duration_;
    140 }
    141 
    142 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
    143   TRACE_EVENT0("synthetic_delay", name_.c_str());
    144   while (clock_->Now() < end_time) {
    145     // Busy loop.
    146   }
    147 }
    148 
    149 TraceEventSyntheticDelayRegistry*
    150 TraceEventSyntheticDelayRegistry::GetInstance() {
    151   return Singleton<
    152       TraceEventSyntheticDelayRegistry,
    153       LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
    154 }
    155 
    156 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
    157     : delay_count_(0) {}
    158 
    159 TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
    160     const char* name) {
    161   // Try to find an existing delay first without locking to make the common case
    162   // fast.
    163   int delay_count = base::subtle::Acquire_Load(&delay_count_);
    164   for (int i = 0; i < delay_count; ++i) {
    165     if (!strcmp(name, delays_[i].name_.c_str()))
    166       return &delays_[i];
    167   }
    168 
    169   AutoLock lock(lock_);
    170   delay_count = base::subtle::Acquire_Load(&delay_count_);
    171   for (int i = 0; i < delay_count; ++i) {
    172     if (!strcmp(name, delays_[i].name_.c_str()))
    173       return &delays_[i];
    174   }
    175 
    176   DCHECK(delay_count < kMaxSyntheticDelays)
    177       << "must increase kMaxSyntheticDelays";
    178   if (delay_count >= kMaxSyntheticDelays)
    179     return &dummy_delay_;
    180 
    181   delays_[delay_count].Initialize(std::string(name), this);
    182   base::subtle::Release_Store(&delay_count_, delay_count + 1);
    183   return &delays_[delay_count];
    184 }
    185 
    186 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
    187   return base::TimeTicks::HighResNow();
    188 }
    189 
    190 void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
    191   AutoLock lock(lock_);
    192   int delay_count = base::subtle::Acquire_Load(&delay_count_);
    193   for (int i = 0; i < delay_count; ++i) {
    194     delays_[i].SetTargetDuration(base::TimeDelta());
    195     delays_[i].SetClock(this);
    196   }
    197 }
    198 
    199 void ResetTraceEventSyntheticDelays() {
    200   TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
    201 }
    202 
    203 }  // namespace debug
    204 }  // namespace base
    205 
    206 namespace trace_event_internal {
    207 
    208 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name,
    209                                            base::subtle::AtomicWord* impl_ptr)
    210     : delay_impl_(GetOrCreateDelay(name, impl_ptr)) {
    211   delay_impl_->BeginParallel(&end_time_);
    212 }
    213 
    214 ScopedSyntheticDelay::~ScopedSyntheticDelay() {
    215   delay_impl_->EndParallel(end_time_);
    216 }
    217 
    218 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay(
    219     const char* name,
    220     base::subtle::AtomicWord* impl_ptr) {
    221   base::debug::TraceEventSyntheticDelay* delay_impl =
    222       reinterpret_cast<base::debug::TraceEventSyntheticDelay*>(
    223           base::subtle::Acquire_Load(impl_ptr));
    224   if (!delay_impl) {
    225     delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance()
    226                      ->GetOrCreateDelay(name);
    227     base::subtle::Release_Store(
    228         impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
    229   }
    230   return delay_impl;
    231 }
    232 
    233 }  // namespace trace_event_internal
    234