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 9namespace { 10const int kMaxSyntheticDelays = 32; 11} // namespace 12 13namespace base { 14namespace trace_event { 15 16TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {} 17TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {} 18 19class 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 42TraceEventSyntheticDelay::TraceEventSyntheticDelay() 43 : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {} 44 45TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {} 46 47TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup( 48 const std::string& name) { 49 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay( 50 name.c_str()); 51} 52 53void TraceEventSyntheticDelay::Initialize( 54 const std::string& name, 55 TraceEventSyntheticDelayClock* clock) { 56 name_ = name; 57 clock_ = clock; 58} 59 60void TraceEventSyntheticDelay::SetTargetDuration(TimeDelta target_duration) { 61 AutoLock lock(lock_); 62 target_duration_ = target_duration; 63 trigger_count_ = 0; 64 begin_count_ = 0; 65} 66 67void TraceEventSyntheticDelay::SetMode(Mode mode) { 68 AutoLock lock(lock_); 69 mode_ = mode; 70} 71 72void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { 73 AutoLock lock(lock_); 74 clock_ = clock; 75} 76 77void 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 95void 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 109void 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 125void TraceEventSyntheticDelay::EndParallel(TimeTicks end_time) { 126 if (!end_time.is_null()) 127 ApplyDelay(end_time); 128} 129 130TimeTicks 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 139void 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 146TraceEventSyntheticDelayRegistry* 147TraceEventSyntheticDelayRegistry::GetInstance() { 148 return Singleton< 149 TraceEventSyntheticDelayRegistry, 150 LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get(); 151} 152 153TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry() 154 : delay_count_(0) {} 155 156TraceEventSyntheticDelay* 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 183TimeTicks TraceEventSyntheticDelayRegistry::Now() { 184 return TimeTicks::Now(); 185} 186 187void 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 196void ResetTraceEventSyntheticDelays() { 197 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays(); 198} 199 200} // namespace trace_event 201} // namespace base 202 203namespace trace_event_internal { 204 205ScopedSyntheticDelay::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 211ScopedSyntheticDelay::~ScopedSyntheticDelay() { 212 delay_impl_->EndParallel(end_time_); 213} 214 215base::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