Ensure that on Windows 7, relaunching the browser via chrome://restart or changing...
[chromium-blink-merge.git] / base / debug / trace_event_synthetic_delay.cc
blob868a77737645d4693bd8313db3972ba45091bc55
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.
5 #include "base/debug/trace_event_synthetic_delay.h"
6 #include "base/memory/singleton.h"
8 namespace {
9 const int kMaxSyntheticDelays = 32;
10 } // namespace
12 namespace base {
13 namespace debug {
15 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
16 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
18 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
19 public:
20 static TraceEventSyntheticDelayRegistry* GetInstance();
22 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
23 void ResetAllDelays();
25 // TraceEventSyntheticDelayClock implementation.
26 virtual base::TimeTicks Now() OVERRIDE;
28 private:
29 TraceEventSyntheticDelayRegistry();
31 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
33 Lock lock_;
34 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
35 TraceEventSyntheticDelay dummy_delay_;
36 base::subtle::Atomic32 delay_count_;
38 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
41 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
42 : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
44 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
46 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
47 const std::string& name) {
48 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
49 name.c_str());
52 void TraceEventSyntheticDelay::Initialize(
53 const std::string& name,
54 TraceEventSyntheticDelayClock* clock) {
55 name_ = name;
56 clock_ = clock;
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;
67 void TraceEventSyntheticDelay::SetMode(Mode mode) {
68 AutoLock lock(lock_);
69 mode_ = mode;
72 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
73 AutoLock lock(lock_);
74 clock_ = clock;
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;
87 base::TimeTicks start_time = clock_->Now();
89 AutoLock lock(lock_);
90 if (++begin_count_ != 1)
91 return;
92 end_time_ = CalculateEndTimeLocked(start_time);
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;
104 base::TimeTicks start_time = clock_->Now();
106 AutoLock lock(lock_);
107 *out_end_time = CalculateEndTimeLocked(start_time);
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;
117 base::TimeTicks end_time;
119 AutoLock lock(lock_);
120 if (!begin_count_ || --begin_count_ != 0)
121 return;
122 end_time = end_time_;
124 if (!end_time.is_null())
125 ApplyDelay(end_time);
128 void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
129 if (!end_time.is_null())
130 ApplyDelay(end_time);
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_;
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.
149 TraceEventSyntheticDelayRegistry*
150 TraceEventSyntheticDelayRegistry::GetInstance() {
151 return Singleton<
152 TraceEventSyntheticDelayRegistry,
153 LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
156 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
157 : delay_count_(0) {}
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];
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];
176 DCHECK(delay_count < kMaxSyntheticDelays)
177 << "must increase kMaxSyntheticDelays";
178 if (delay_count >= kMaxSyntheticDelays)
179 return &dummy_delay_;
181 delays_[delay_count].Initialize(std::string(name), this);
182 base::subtle::Release_Store(&delay_count_, delay_count + 1);
183 return &delays_[delay_count];
186 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
187 return base::TimeTicks::HighResNow();
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);
199 void ResetTraceEventSyntheticDelays() {
200 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
203 } // namespace debug
204 } // namespace base
206 namespace trace_event_internal {
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_);
214 ScopedSyntheticDelay::~ScopedSyntheticDelay() {
215 delay_impl_->EndParallel(end_time_);
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));
230 return delay_impl;
233 } // namespace trace_event_internal