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