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