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