OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013 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 #include "base/synchronization/lock.h" |
| 8 #include "base/threading/platform_thread.h" |
| 9 |
| 10 namespace { |
| 11 const int kMaxSyntheticDelays = 32; |
| 12 } // namespace |
| 13 |
| 14 namespace base { |
| 15 namespace debug { |
| 16 |
| 17 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {} |
| 18 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {} |
| 19 |
| 20 class TraceEventSyntheticDelayRegistry |
| 21 : public TraceEventSyntheticDelayClock { |
| 22 public: |
| 23 static TraceEventSyntheticDelayRegistry* GetInstance(); |
| 24 |
| 25 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name); |
| 26 |
| 27 // TraceEventSyntheticDelayClock implementation. |
| 28 virtual base::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 base::subtle::Atomic32 delay_count_; |
| 39 |
| 40 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry); |
| 41 }; |
| 42 |
| 43 TraceEventSyntheticDelay::TraceEventSyntheticDelay() |
| 44 : mode_(STATIC), generation_(0), clock_(NULL) {} |
| 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 DCHECK(!thread_state_.Get()); |
| 56 name_ = name; |
| 57 clock_ = clock; |
| 58 } |
| 59 |
| 60 void TraceEventSyntheticDelay::SetTargetDuration( |
| 61 base::TimeDelta target_duration) { |
| 62 AutoLock lock(lock_); |
| 63 target_duration_ = target_duration; |
| 64 generation_++; |
| 65 } |
| 66 |
| 67 void TraceEventSyntheticDelay::SetMode(Mode mode) { |
| 68 AutoLock lock(lock_); |
| 69 mode_ = mode; |
| 70 generation_++; |
| 71 } |
| 72 |
| 73 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { |
| 74 AutoLock lock(lock_); |
| 75 clock_ = clock; |
| 76 generation_++; |
| 77 } |
| 78 |
| 79 TraceEventSyntheticDelay::ThreadState::ThreadState() |
| 80 : trigger_count(0u), generation(0) {} |
| 81 |
| 82 void TraceEventSyntheticDelay::Activate() { |
| 83 // Note that we check for a non-zero target duration without locking to keep |
| 84 // things quick for the common case when delays are disabled. Since the delay |
| 85 // calculation is done with a lock held, it will always be correct. The only |
| 86 // downside of this is that we may fail to apply some delays when the target |
| 87 // duration changes. |
| 88 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
| 89 if (!target_duration_.ToInternalValue()) |
| 90 return; |
| 91 |
| 92 // Store the start time in a thread local struct so the same delay can be |
| 93 // applied to multiple threads simultaneously. Note that the structs are |
| 94 // leaked at program exit. |
| 95 ThreadState* thread_state = EnsureThreadState(); |
| 96 if (!thread_state->start_time.ToInternalValue()) |
| 97 thread_state->start_time = clock_->Now(); |
| 98 } |
| 99 |
| 100 TraceEventSyntheticDelay::ThreadState* |
| 101 TraceEventSyntheticDelay::EnsureThreadState() { |
| 102 ThreadState* thread_state = thread_state_.Get(); |
| 103 if (!thread_state) |
| 104 thread_state_.Set((thread_state = new ThreadState())); |
| 105 return thread_state; |
| 106 } |
| 107 |
| 108 void TraceEventSyntheticDelay::Apply() { |
| 109 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
| 110 if (!target_duration_.ToInternalValue()) |
| 111 return; |
| 112 |
| 113 ThreadState* thread_state = EnsureThreadState(); |
| 114 if (!thread_state->start_time.ToInternalValue()) |
| 115 return; |
| 116 base::TimeTicks now = clock_->Now(); |
| 117 base::TimeTicks start_time = thread_state->start_time; |
| 118 base::TimeTicks end_time; |
| 119 thread_state->start_time = base::TimeTicks(); |
| 120 |
| 121 { |
| 122 AutoLock lock(lock_); |
| 123 if (thread_state->generation != generation_) { |
| 124 thread_state->trigger_count = 0; |
| 125 thread_state->generation = generation_; |
| 126 } |
| 127 |
| 128 if (mode_ == ONE_SHOT && thread_state->trigger_count++) |
| 129 return; |
| 130 else if (mode_ == ALTERNATING && thread_state->trigger_count++ % 2) |
| 131 return; |
| 132 |
| 133 end_time = start_time + target_duration_; |
| 134 if (now >= end_time) |
| 135 return; |
| 136 } |
| 137 ApplyDelay(end_time); |
| 138 } |
| 139 |
| 140 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) { |
| 141 TRACE_EVENT0("synthetic_delay", name_.c_str()); |
| 142 while (clock_->Now() < end_time) { |
| 143 // Busy loop. |
| 144 } |
| 145 } |
| 146 |
| 147 TraceEventSyntheticDelayRegistry* |
| 148 TraceEventSyntheticDelayRegistry::GetInstance() { |
| 149 return Singleton< |
| 150 TraceEventSyntheticDelayRegistry, |
| 151 LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get(); |
| 152 } |
| 153 |
| 154 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry() |
| 155 : delay_count_(0) {} |
| 156 |
| 157 TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay( |
| 158 const char* name) { |
| 159 // Try to find an existing delay first without locking to make the common case |
| 160 // fast. |
| 161 int delay_count = base::subtle::Acquire_Load(&delay_count_); |
| 162 for (int i = 0; i < delay_count; ++i) { |
| 163 if (!strcmp(name, delays_[i].name_.c_str())) |
| 164 return &delays_[i]; |
| 165 } |
| 166 |
| 167 AutoLock lock(lock_); |
| 168 delay_count = base::subtle::Acquire_Load(&delay_count_); |
| 169 for (int i = 0; i < delay_count; ++i) { |
| 170 if (!strcmp(name, delays_[i].name_.c_str())) |
| 171 return &delays_[i]; |
| 172 } |
| 173 |
| 174 DCHECK(delay_count < kMaxSyntheticDelays) |
| 175 << "must increase kMaxSyntheticDelays"; |
| 176 if (delay_count >= kMaxSyntheticDelays) |
| 177 return &dummy_delay_; |
| 178 |
| 179 delays_[delay_count].Initialize(std::string(name), this); |
| 180 base::subtle::Release_Store(&delay_count_, delay_count + 1); |
| 181 return &delays_[delay_count]; |
| 182 } |
| 183 |
| 184 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() { |
| 185 return base::TimeTicks::HighResNow(); |
| 186 } |
| 187 |
| 188 } // namespace debug |
| 189 } // namespace base |
| 190 |
| 191 namespace trace_event_internal { |
| 192 |
| 193 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, |
| 194 base::subtle::AtomicWord* impl_ptr) |
| 195 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) { |
| 196 delay_impl_->Activate(); |
| 197 } |
| 198 |
| 199 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->Apply(); } |
| 200 |
| 201 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay( |
| 202 const char* name, |
| 203 base::subtle::AtomicWord* impl_ptr) { |
| 204 base::debug::TraceEventSyntheticDelay* delay_impl = |
| 205 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>( |
| 206 base::subtle::NoBarrier_Load(impl_ptr)); |
| 207 if (!delay_impl) { |
| 208 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance() |
| 209 ->GetOrCreateDelay(name); |
| 210 base::subtle::NoBarrier_Store( |
| 211 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl)); |
| 212 } |
| 213 return delay_impl; |
| 214 } |
| 215 |
| 216 } // namespace trace_event_internal |
OLD | NEW |