OLD | NEW |
| (Empty) |
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/debug/trace_event_synthetic_delay.h" | |
6 #include "base/memory/singleton.h" | |
7 | |
8 namespace { | |
9 const int kMaxSyntheticDelays = 32; | |
10 } // namespace | |
11 | |
12 namespace base { | |
13 namespace debug { | |
14 | |
15 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {} | |
16 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {} | |
17 | |
18 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock { | |
19 public: | |
20 static TraceEventSyntheticDelayRegistry* GetInstance(); | |
21 | |
22 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name); | |
23 void ResetAllDelays(); | |
24 | |
25 // TraceEventSyntheticDelayClock implementation. | |
26 base::TimeTicks Now() override; | |
27 | |
28 private: | |
29 TraceEventSyntheticDelayRegistry(); | |
30 | |
31 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>; | |
32 | |
33 Lock lock_; | |
34 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays]; | |
35 TraceEventSyntheticDelay dummy_delay_; | |
36 base::subtle::Atomic32 delay_count_; | |
37 | |
38 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry); | |
39 }; | |
40 | |
41 TraceEventSyntheticDelay::TraceEventSyntheticDelay() | |
42 : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {} | |
43 | |
44 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {} | |
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 name_ = name; | |
56 clock_ = clock; | |
57 } | |
58 | |
59 void TraceEventSyntheticDelay::SetTargetDuration( | |
60 base::TimeDelta target_duration) { | |
61 AutoLock lock(lock_); | |
62 target_duration_ = target_duration; | |
63 trigger_count_ = 0; | |
64 begin_count_ = 0; | |
65 } | |
66 | |
67 void TraceEventSyntheticDelay::SetMode(Mode mode) { | |
68 AutoLock lock(lock_); | |
69 mode_ = mode; | |
70 } | |
71 | |
72 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { | |
73 AutoLock lock(lock_); | |
74 clock_ = clock; | |
75 } | |
76 | |
77 void 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 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); | |
84 if (!target_duration_.ToInternalValue()) | |
85 return; | |
86 | |
87 base::TimeTicks start_time = clock_->Now(); | |
88 { | |
89 AutoLock lock(lock_); | |
90 if (++begin_count_ != 1) | |
91 return; | |
92 end_time_ = CalculateEndTimeLocked(start_time); | |
93 } | |
94 } | |
95 | |
96 void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) { | |
97 // See note in Begin(). | |
98 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); | |
99 if (!target_duration_.ToInternalValue()) { | |
100 *out_end_time = base::TimeTicks(); | |
101 return; | |
102 } | |
103 | |
104 base::TimeTicks start_time = clock_->Now(); | |
105 { | |
106 AutoLock lock(lock_); | |
107 *out_end_time = CalculateEndTimeLocked(start_time); | |
108 } | |
109 } | |
110 | |
111 void TraceEventSyntheticDelay::End() { | |
112 // See note in Begin(). | |
113 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); | |
114 if (!target_duration_.ToInternalValue()) | |
115 return; | |
116 | |
117 base::TimeTicks end_time; | |
118 { | |
119 AutoLock lock(lock_); | |
120 if (!begin_count_ || --begin_count_ != 0) | |
121 return; | |
122 end_time = end_time_; | |
123 } | |
124 if (!end_time.is_null()) | |
125 ApplyDelay(end_time); | |
126 } | |
127 | |
128 void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) { | |
129 if (!end_time.is_null()) | |
130 ApplyDelay(end_time); | |
131 } | |
132 | |
133 base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked( | |
134 base::TimeTicks start_time) { | |
135 if (mode_ == ONE_SHOT && trigger_count_++) | |
136 return base::TimeTicks(); | |
137 else if (mode_ == ALTERNATING && trigger_count_++ % 2) | |
138 return base::TimeTicks(); | |
139 return start_time + target_duration_; | |
140 } | |
141 | |
142 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) { | |
143 TRACE_EVENT0("synthetic_delay", name_.c_str()); | |
144 while (clock_->Now() < end_time) { | |
145 // Busy loop. | |
146 } | |
147 } | |
148 | |
149 TraceEventSyntheticDelayRegistry* | |
150 TraceEventSyntheticDelayRegistry::GetInstance() { | |
151 return Singleton< | |
152 TraceEventSyntheticDelayRegistry, | |
153 LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get(); | |
154 } | |
155 | |
156 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry() | |
157 : delay_count_(0) {} | |
158 | |
159 TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay( | |
160 const char* name) { | |
161 // Try to find an existing delay first without locking to make the common case | |
162 // fast. | |
163 int delay_count = base::subtle::Acquire_Load(&delay_count_); | |
164 for (int i = 0; i < delay_count; ++i) { | |
165 if (!strcmp(name, delays_[i].name_.c_str())) | |
166 return &delays_[i]; | |
167 } | |
168 | |
169 AutoLock lock(lock_); | |
170 delay_count = base::subtle::Acquire_Load(&delay_count_); | |
171 for (int i = 0; i < delay_count; ++i) { | |
172 if (!strcmp(name, delays_[i].name_.c_str())) | |
173 return &delays_[i]; | |
174 } | |
175 | |
176 DCHECK(delay_count < kMaxSyntheticDelays) | |
177 << "must increase kMaxSyntheticDelays"; | |
178 if (delay_count >= kMaxSyntheticDelays) | |
179 return &dummy_delay_; | |
180 | |
181 delays_[delay_count].Initialize(std::string(name), this); | |
182 base::subtle::Release_Store(&delay_count_, delay_count + 1); | |
183 return &delays_[delay_count]; | |
184 } | |
185 | |
186 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() { | |
187 return base::TimeTicks::HighResNow(); | |
188 } | |
189 | |
190 void TraceEventSyntheticDelayRegistry::ResetAllDelays() { | |
191 AutoLock lock(lock_); | |
192 int delay_count = base::subtle::Acquire_Load(&delay_count_); | |
193 for (int i = 0; i < delay_count; ++i) { | |
194 delays_[i].SetTargetDuration(base::TimeDelta()); | |
195 delays_[i].SetClock(this); | |
196 } | |
197 } | |
198 | |
199 void ResetTraceEventSyntheticDelays() { | |
200 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays(); | |
201 } | |
202 | |
203 } // namespace debug | |
204 } // namespace base | |
205 | |
206 namespace trace_event_internal { | |
207 | |
208 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, | |
209 base::subtle::AtomicWord* impl_ptr) | |
210 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) { | |
211 delay_impl_->BeginParallel(&end_time_); | |
212 } | |
213 | |
214 ScopedSyntheticDelay::~ScopedSyntheticDelay() { | |
215 delay_impl_->EndParallel(end_time_); | |
216 } | |
217 | |
218 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay( | |
219 const char* name, | |
220 base::subtle::AtomicWord* impl_ptr) { | |
221 base::debug::TraceEventSyntheticDelay* delay_impl = | |
222 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>( | |
223 base::subtle::Acquire_Load(impl_ptr)); | |
224 if (!delay_impl) { | |
225 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance() | |
226 ->GetOrCreateDelay(name); | |
227 base::subtle::Release_Store( | |
228 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl)); | |
229 } | |
230 return delay_impl; | |
231 } | |
232 | |
233 } // namespace trace_event_internal | |
OLD | NEW |