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