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