OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/trace_event_synthetic_delay.h" | 5 #include "base/debug/trace_event_synthetic_delay.h" |
6 #include "base/memory/singleton.h" | 6 #include "base/memory/singleton.h" |
7 #include "base/threading/platform_thread.h" | |
8 #include "base/threading/thread_local.h" | |
9 | 7 |
10 namespace { | 8 namespace { |
11 const int kMaxSyntheticDelays = 32; | 9 const int kMaxSyntheticDelays = 32; |
12 } // namespace | 10 } // namespace |
13 | 11 |
14 namespace base { | 12 namespace base { |
15 namespace debug { | 13 namespace debug { |
16 | 14 |
17 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {} | 15 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {} |
18 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {} | 16 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {} |
19 | 17 |
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 { | 18 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock { |
33 public: | 19 public: |
34 static TraceEventSyntheticDelayRegistry* GetInstance(); | 20 static TraceEventSyntheticDelayRegistry* GetInstance(); |
35 | 21 |
36 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name); | 22 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name); |
37 ThreadState* GetThreadState(int index); | |
38 void ResetAllDelays(); | 23 void ResetAllDelays(); |
39 | 24 |
40 // TraceEventSyntheticDelayClock implementation. | 25 // TraceEventSyntheticDelayClock implementation. |
41 virtual base::TimeTicks Now() OVERRIDE; | 26 virtual base::TimeTicks Now() OVERRIDE; |
42 | 27 |
43 private: | 28 private: |
44 TraceEventSyntheticDelayRegistry(); | 29 TraceEventSyntheticDelayRegistry(); |
45 | 30 |
46 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>; | 31 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>; |
47 | 32 |
48 Lock lock_; | 33 Lock lock_; |
49 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays]; | 34 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays]; |
50 TraceEventSyntheticDelay dummy_delay_; | 35 TraceEventSyntheticDelay dummy_delay_; |
51 base::subtle::Atomic32 delay_count_; | 36 base::subtle::Atomic32 delay_count_; |
52 | 37 |
53 ThreadLocalPointer<ThreadState> thread_states_; | |
54 | |
55 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry); | 38 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry); |
56 }; | 39 }; |
57 | 40 |
58 TraceEventSyntheticDelay::TraceEventSyntheticDelay() | 41 TraceEventSyntheticDelay::TraceEventSyntheticDelay() |
59 : mode_(STATIC), generation_(0), thread_state_index_(0), clock_(NULL) {} | 42 : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {} |
60 | 43 |
61 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {} | 44 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {} |
62 | 45 |
63 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup( | 46 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup( |
64 const std::string& name) { | 47 const std::string& name) { |
65 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay( | 48 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay( |
66 name.c_str()); | 49 name.c_str()); |
67 } | 50 } |
68 | 51 |
69 void TraceEventSyntheticDelay::Initialize( | 52 void TraceEventSyntheticDelay::Initialize( |
70 const std::string& name, | 53 const std::string& name, |
71 TraceEventSyntheticDelayClock* clock, | 54 TraceEventSyntheticDelayClock* clock) { |
72 int thread_state_index) { | |
73 name_ = name; | 55 name_ = name; |
74 clock_ = clock; | 56 clock_ = clock; |
75 thread_state_index_ = thread_state_index; | |
76 } | 57 } |
77 | 58 |
78 void TraceEventSyntheticDelay::SetTargetDuration( | 59 void TraceEventSyntheticDelay::SetTargetDuration( |
79 base::TimeDelta target_duration) { | 60 base::TimeDelta target_duration) { |
80 AutoLock lock(lock_); | 61 AutoLock lock(lock_); |
81 target_duration_ = target_duration; | 62 target_duration_ = target_duration; |
82 generation_++; | 63 trigger_count_ = 0; |
64 begin_count_ = 0; | |
83 } | 65 } |
84 | 66 |
85 void TraceEventSyntheticDelay::SetMode(Mode mode) { | 67 void TraceEventSyntheticDelay::SetMode(Mode mode) { |
86 AutoLock lock(lock_); | 68 AutoLock lock(lock_); |
87 mode_ = mode; | 69 mode_ = mode; |
88 generation_++; | |
89 } | 70 } |
90 | 71 |
91 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { | 72 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { |
92 AutoLock lock(lock_); | 73 AutoLock lock(lock_); |
93 clock_ = clock; | 74 clock_ = clock; |
94 generation_++; | |
95 } | 75 } |
96 | 76 |
97 void TraceEventSyntheticDelay::Activate() { | 77 void TraceEventSyntheticDelay::Begin() { |
98 // Note that we check for a non-zero target duration without locking to keep | 78 // Note that we check for a non-zero target duration without locking to keep |
99 // things quick for the common case when delays are disabled. Since the delay | 79 // things quick for the common case when delays are disabled. Since the delay |
100 // calculation is done with a lock held, it will always be correct. The only | 80 // calculation is done with a lock held, it will always be correct. The only |
101 // downside of this is that we may fail to apply some delays when the target | 81 // downside of this is that we may fail to apply some delays when the target |
102 // duration changes. | 82 // duration changes. |
103 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); | 83 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
104 if (!target_duration_.ToInternalValue()) | 84 if (!target_duration_.ToInternalValue()) |
105 return; | 85 return; |
106 | 86 |
107 ThreadState* thread_state = | 87 BeginInternal(1, false); |
108 TraceEventSyntheticDelayRegistry::GetInstance()-> | |
109 GetThreadState(thread_state_index_); | |
110 if (!thread_state->start_time.ToInternalValue()) | |
111 thread_state->start_time = clock_->Now(); | |
112 } | 88 } |
113 | 89 |
114 void TraceEventSyntheticDelay::Apply() { | 90 void TraceEventSyntheticDelay::BeginInternal(int begin_delta, bool reset) { |
brianderson
2013/12/10 02:25:39
When reset is true, is it possible that there is a
| |
91 AutoLock lock(lock_); | |
92 if (reset) | |
93 begin_count_ = begin_delta; | |
94 else | |
95 begin_count_ += begin_delta; | |
96 | |
97 if (!reset && begin_count_ - begin_delta > 0) | |
98 return; | |
99 start_time_ = clock_->Now(); | |
100 } | |
101 | |
102 void TraceEventSyntheticDelay::End() { | |
115 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); | 103 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
116 if (!target_duration_.ToInternalValue()) | 104 if (!target_duration_.ToInternalValue()) |
117 return; | 105 return; |
118 | 106 |
119 ThreadState* thread_state = | |
120 TraceEventSyntheticDelayRegistry::GetInstance()-> | |
121 GetThreadState(thread_state_index_); | |
122 if (!thread_state->start_time.ToInternalValue()) | |
123 return; | |
124 base::TimeTicks now = clock_->Now(); | |
125 base::TimeTicks start_time = thread_state->start_time; | |
126 base::TimeTicks end_time; | 107 base::TimeTicks end_time; |
127 thread_state->start_time = base::TimeTicks(); | |
128 | |
129 { | 108 { |
130 AutoLock lock(lock_); | 109 AutoLock lock(lock_); |
131 if (thread_state->generation != generation_) { | 110 if (!begin_count_ || --begin_count_ > 0) |
132 thread_state->trigger_count = 0; | 111 return; |
133 thread_state->generation = generation_; | 112 base::TimeTicks now = clock_->Now(); |
134 } | |
135 | 113 |
136 if (mode_ == ONE_SHOT && thread_state->trigger_count++) | 114 if (mode_ == ONE_SHOT && trigger_count_++) |
137 return; | 115 return; |
138 else if (mode_ == ALTERNATING && thread_state->trigger_count++ % 2) | 116 else if (mode_ == ALTERNATING && trigger_count_++ % 2) |
139 return; | 117 return; |
140 | 118 |
141 end_time = start_time + target_duration_; | 119 end_time = start_time_ + target_duration_; |
142 if (now >= end_time) | 120 if (now >= end_time) |
143 return; | 121 return; |
144 } | 122 } |
145 ApplyDelay(end_time); | 123 ApplyDelay(end_time); |
146 } | 124 } |
147 | 125 |
126 void TraceEventSyntheticDelay::ResetAndBeginMultiple(int begin_count) { | |
127 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); | |
128 if (!target_duration_.ToInternalValue()) | |
129 return; | |
130 BeginInternal(begin_count, true); | |
131 } | |
132 | |
148 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) { | 133 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) { |
149 TRACE_EVENT0("synthetic_delay", name_.c_str()); | 134 TRACE_EVENT0("synthetic_delay", name_.c_str()); |
150 while (clock_->Now() < end_time) { | 135 while (clock_->Now() < end_time) { |
151 // Busy loop. | 136 // Busy loop. |
152 } | 137 } |
153 } | 138 } |
154 | 139 |
155 TraceEventSyntheticDelayRegistry* | 140 TraceEventSyntheticDelayRegistry* |
156 TraceEventSyntheticDelayRegistry::GetInstance() { | 141 TraceEventSyntheticDelayRegistry::GetInstance() { |
157 return Singleton< | 142 return Singleton< |
(...skipping 19 matching lines...) Expand all Loading... | |
177 for (int i = 0; i < delay_count; ++i) { | 162 for (int i = 0; i < delay_count; ++i) { |
178 if (!strcmp(name, delays_[i].name_.c_str())) | 163 if (!strcmp(name, delays_[i].name_.c_str())) |
179 return &delays_[i]; | 164 return &delays_[i]; |
180 } | 165 } |
181 | 166 |
182 DCHECK(delay_count < kMaxSyntheticDelays) | 167 DCHECK(delay_count < kMaxSyntheticDelays) |
183 << "must increase kMaxSyntheticDelays"; | 168 << "must increase kMaxSyntheticDelays"; |
184 if (delay_count >= kMaxSyntheticDelays) | 169 if (delay_count >= kMaxSyntheticDelays) |
185 return &dummy_delay_; | 170 return &dummy_delay_; |
186 | 171 |
187 delays_[delay_count].Initialize(std::string(name), this, delay_count); | 172 delays_[delay_count].Initialize(std::string(name), this); |
188 base::subtle::Release_Store(&delay_count_, delay_count + 1); | 173 base::subtle::Release_Store(&delay_count_, delay_count + 1); |
189 return &delays_[delay_count]; | 174 return &delays_[delay_count]; |
190 } | 175 } |
191 | 176 |
192 ThreadState* TraceEventSyntheticDelayRegistry::GetThreadState(int index) { | |
193 DCHECK(index >= 0 && index < kMaxSyntheticDelays); | |
194 if (index < 0 || index >= kMaxSyntheticDelays) | |
195 return NULL; | |
196 | |
197 // Note that these thread states are leaked at program exit. They will only | |
198 // get allocated if synthetic delays are actually used. | |
199 ThreadState* thread_states = thread_states_.Get(); | |
200 if (!thread_states) | |
201 thread_states_.Set((thread_states = new ThreadState[kMaxSyntheticDelays])); | |
202 return &thread_states[index]; | |
203 } | |
204 | |
205 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() { | 177 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() { |
206 return base::TimeTicks::HighResNow(); | 178 return base::TimeTicks::HighResNow(); |
207 } | 179 } |
208 | 180 |
209 void TraceEventSyntheticDelayRegistry::ResetAllDelays() { | 181 void TraceEventSyntheticDelayRegistry::ResetAllDelays() { |
210 AutoLock lock(lock_); | 182 AutoLock lock(lock_); |
211 int delay_count = base::subtle::Acquire_Load(&delay_count_); | 183 int delay_count = base::subtle::Acquire_Load(&delay_count_); |
212 for (int i = 0; i < delay_count; ++i) | 184 for (int i = 0; i < delay_count; ++i) |
213 delays_[i].SetTargetDuration(base::TimeDelta()); | 185 delays_[i].SetTargetDuration(base::TimeDelta()); |
214 } | 186 } |
215 | 187 |
216 void ResetTraceEventSyntheticDelays() { | 188 void ResetTraceEventSyntheticDelays() { |
217 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays(); | 189 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays(); |
218 } | 190 } |
219 | 191 |
220 } // namespace debug | 192 } // namespace debug |
221 } // namespace base | 193 } // namespace base |
222 | 194 |
223 namespace trace_event_internal { | 195 namespace trace_event_internal { |
224 | 196 |
225 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, | 197 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, |
226 base::subtle::AtomicWord* impl_ptr) | 198 base::subtle::AtomicWord* impl_ptr) |
227 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) { | 199 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) { |
228 delay_impl_->Activate(); | 200 delay_impl_->Begin(); |
229 } | 201 } |
230 | 202 |
231 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->Apply(); } | 203 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->End(); } |
232 | 204 |
233 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay( | 205 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay( |
234 const char* name, | 206 const char* name, |
235 base::subtle::AtomicWord* impl_ptr) { | 207 base::subtle::AtomicWord* impl_ptr) { |
236 base::debug::TraceEventSyntheticDelay* delay_impl = | 208 base::debug::TraceEventSyntheticDelay* delay_impl = |
237 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>( | 209 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>( |
238 base::subtle::NoBarrier_Load(impl_ptr)); | 210 base::subtle::NoBarrier_Load(impl_ptr)); |
239 if (!delay_impl) { | 211 if (!delay_impl) { |
240 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance() | 212 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance() |
241 ->GetOrCreateDelay(name); | 213 ->GetOrCreateDelay(name); |
242 base::subtle::NoBarrier_Store( | 214 base::subtle::NoBarrier_Store( |
243 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl)); | 215 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl)); |
244 } | 216 } |
245 return delay_impl; | 217 return delay_impl; |
246 } | 218 } |
247 | 219 |
248 } // namespace trace_event_internal | 220 } // namespace trace_event_internal |
OLD | NEW |