OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 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 #include "base/threading/platform_thread.h" |
| 8 #include "base/threading/thread_local.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 // Thread-local state for each synthetic delay point. This allows the same delay |
| 21 // to be applied to multiple threads simultaneously. |
| 22 struct ThreadState { |
| 23 ThreadState(); |
| 24 |
| 25 base::TimeTicks start_time; |
| 26 unsigned trigger_count; |
| 27 int generation; |
| 28 }; |
| 29 |
| 30 ThreadState::ThreadState() : trigger_count(0u), generation(0) {} |
| 31 |
| 32 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock { |
| 33 public: |
| 34 static TraceEventSyntheticDelayRegistry* GetInstance(); |
| 35 |
| 36 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name); |
| 37 ThreadState* GetThreadState(int index); |
| 38 |
| 39 // TraceEventSyntheticDelayClock implementation. |
| 40 virtual base::TimeTicks Now() OVERRIDE; |
| 41 |
| 42 private: |
| 43 TraceEventSyntheticDelayRegistry(); |
| 44 |
| 45 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>; |
| 46 |
| 47 Lock lock_; |
| 48 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays]; |
| 49 TraceEventSyntheticDelay dummy_delay_; |
| 50 base::subtle::Atomic32 delay_count_; |
| 51 |
| 52 ThreadLocalPointer<ThreadState> thread_states_; |
| 53 |
| 54 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry); |
| 55 }; |
| 56 |
| 57 TraceEventSyntheticDelay::TraceEventSyntheticDelay() |
| 58 : mode_(STATIC), generation_(0), thread_state_index_(0), clock_(NULL) {} |
| 59 |
| 60 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {} |
| 61 |
| 62 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup( |
| 63 const std::string& name) { |
| 64 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay( |
| 65 name.c_str()); |
| 66 } |
| 67 |
| 68 void TraceEventSyntheticDelay::Initialize( |
| 69 const std::string& name, |
| 70 TraceEventSyntheticDelayClock* clock, |
| 71 int thread_state_index) { |
| 72 name_ = name; |
| 73 clock_ = clock; |
| 74 thread_state_index_ = thread_state_index; |
| 75 } |
| 76 |
| 77 void TraceEventSyntheticDelay::SetTargetDuration( |
| 78 base::TimeDelta target_duration) { |
| 79 AutoLock lock(lock_); |
| 80 target_duration_ = target_duration; |
| 81 generation_++; |
| 82 } |
| 83 |
| 84 void TraceEventSyntheticDelay::SetMode(Mode mode) { |
| 85 AutoLock lock(lock_); |
| 86 mode_ = mode; |
| 87 generation_++; |
| 88 } |
| 89 |
| 90 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { |
| 91 AutoLock lock(lock_); |
| 92 clock_ = clock; |
| 93 generation_++; |
| 94 } |
| 95 |
| 96 void TraceEventSyntheticDelay::Activate() { |
| 97 // Note that we check for a non-zero target duration without locking to keep |
| 98 // things quick for the common case when delays are disabled. Since the delay |
| 99 // calculation is done with a lock held, it will always be correct. The only |
| 100 // downside of this is that we may fail to apply some delays when the target |
| 101 // duration changes. |
| 102 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
| 103 if (!target_duration_.ToInternalValue()) |
| 104 return; |
| 105 |
| 106 ThreadState* thread_state = |
| 107 TraceEventSyntheticDelayRegistry::GetInstance()-> |
| 108 GetThreadState(thread_state_index_); |
| 109 if (!thread_state->start_time.ToInternalValue()) |
| 110 thread_state->start_time = clock_->Now(); |
| 111 } |
| 112 |
| 113 void TraceEventSyntheticDelay::Apply() { |
| 114 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
| 115 if (!target_duration_.ToInternalValue()) |
| 116 return; |
| 117 |
| 118 ThreadState* thread_state = |
| 119 TraceEventSyntheticDelayRegistry::GetInstance()-> |
| 120 GetThreadState(thread_state_index_); |
| 121 if (!thread_state->start_time.ToInternalValue()) |
| 122 return; |
| 123 base::TimeTicks now = clock_->Now(); |
| 124 base::TimeTicks start_time = thread_state->start_time; |
| 125 base::TimeTicks end_time; |
| 126 thread_state->start_time = base::TimeTicks(); |
| 127 |
| 128 { |
| 129 AutoLock lock(lock_); |
| 130 if (thread_state->generation != generation_) { |
| 131 thread_state->trigger_count = 0; |
| 132 thread_state->generation = generation_; |
| 133 } |
| 134 |
| 135 if (mode_ == ONE_SHOT && thread_state->trigger_count++) |
| 136 return; |
| 137 else if (mode_ == ALTERNATING && thread_state->trigger_count++ % 2) |
| 138 return; |
| 139 |
| 140 end_time = start_time + target_duration_; |
| 141 if (now >= end_time) |
| 142 return; |
| 143 } |
| 144 ApplyDelay(end_time); |
| 145 } |
| 146 |
| 147 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) { |
| 148 TRACE_EVENT0("synthetic_delay", name_.c_str()); |
| 149 while (clock_->Now() < end_time) { |
| 150 // Busy loop. |
| 151 } |
| 152 } |
| 153 |
| 154 TraceEventSyntheticDelayRegistry* |
| 155 TraceEventSyntheticDelayRegistry::GetInstance() { |
| 156 return Singleton< |
| 157 TraceEventSyntheticDelayRegistry, |
| 158 LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get(); |
| 159 } |
| 160 |
| 161 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry() |
| 162 : delay_count_(0) {} |
| 163 |
| 164 TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay( |
| 165 const char* name) { |
| 166 // Try to find an existing delay first without locking to make the common case |
| 167 // fast. |
| 168 int 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 AutoLock lock(lock_); |
| 175 delay_count = base::subtle::Acquire_Load(&delay_count_); |
| 176 for (int i = 0; i < delay_count; ++i) { |
| 177 if (!strcmp(name, delays_[i].name_.c_str())) |
| 178 return &delays_[i]; |
| 179 } |
| 180 |
| 181 DCHECK(delay_count < kMaxSyntheticDelays) |
| 182 << "must increase kMaxSyntheticDelays"; |
| 183 if (delay_count >= kMaxSyntheticDelays) |
| 184 return &dummy_delay_; |
| 185 |
| 186 delays_[delay_count].Initialize(std::string(name), this, delay_count); |
| 187 base::subtle::Release_Store(&delay_count_, delay_count + 1); |
| 188 return &delays_[delay_count]; |
| 189 } |
| 190 |
| 191 ThreadState* TraceEventSyntheticDelayRegistry::GetThreadState(int index) { |
| 192 DCHECK(index >= 0 && index < kMaxSyntheticDelays); |
| 193 if (index < 0 || index >= kMaxSyntheticDelays) |
| 194 return NULL; |
| 195 |
| 196 // Note that these thread states are leaked at program exit. They will only |
| 197 // get allocated if synthetic delays are actually used. |
| 198 ThreadState* thread_states = thread_states_.Get(); |
| 199 if (!thread_states) |
| 200 thread_states_.Set((thread_states = new ThreadState[kMaxSyntheticDelays])); |
| 201 return &thread_states[index]; |
| 202 } |
| 203 |
| 204 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() { |
| 205 return base::TimeTicks::HighResNow(); |
| 206 } |
| 207 |
| 208 } // namespace debug |
| 209 } // namespace base |
| 210 |
| 211 namespace trace_event_internal { |
| 212 |
| 213 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, |
| 214 base::subtle::AtomicWord* impl_ptr) |
| 215 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) { |
| 216 delay_impl_->Activate(); |
| 217 } |
| 218 |
| 219 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->Apply(); } |
| 220 |
| 221 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay( |
| 222 const char* name, |
| 223 base::subtle::AtomicWord* impl_ptr) { |
| 224 base::debug::TraceEventSyntheticDelay* delay_impl = |
| 225 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>( |
| 226 base::subtle::NoBarrier_Load(impl_ptr)); |
| 227 if (!delay_impl) { |
| 228 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance() |
| 229 ->GetOrCreateDelay(name); |
| 230 base::subtle::NoBarrier_Store( |
| 231 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl)); |
| 232 } |
| 233 return delay_impl; |
| 234 } |
| 235 |
| 236 } // namespace trace_event_internal |
OLD | NEW |