SupervisedUser SafeSites: Switch to the new SafeSearch API
[chromium-blink-merge.git] / base / trace_event / trace_event_synthetic_delay.cc
blobbad79ccbc8c27a826a951051b77bfc2ef0ed6e4c
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/memory/singleton.h"
6 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
7 #include "base/trace_event/trace_event_synthetic_delay.h"
9 namespace {
10 const int kMaxSyntheticDelays = 32;
11 } // namespace
13 namespace base {
14 namespace trace_event {
16 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
17 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
19 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
20 public:
21 static TraceEventSyntheticDelayRegistry* GetInstance();
23 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
24 void ResetAllDelays();
26 // TraceEventSyntheticDelayClock implementation.
27 base::TimeTicks Now() override;
29 private:
30 TraceEventSyntheticDelayRegistry();
32 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
34 Lock lock_;
35 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
36 TraceEventSyntheticDelay dummy_delay_;
37 base::subtle::Atomic32 delay_count_;
39 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
42 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
43 : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
45 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
47 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
48 const std::string& name) {
49 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
50 name.c_str());
53 void TraceEventSyntheticDelay::Initialize(
54 const std::string& name,
55 TraceEventSyntheticDelayClock* clock) {
56 name_ = name;
57 clock_ = clock;
60 void TraceEventSyntheticDelay::SetTargetDuration(
61 base::TimeDelta target_duration) {
62 AutoLock lock(lock_);
63 target_duration_ = target_duration;
64 trigger_count_ = 0;
65 begin_count_ = 0;
68 void TraceEventSyntheticDelay::SetMode(Mode mode) {
69 AutoLock lock(lock_);
70 mode_ = mode;
73 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
74 AutoLock lock(lock_);
75 clock_ = clock;
78 void TraceEventSyntheticDelay::Begin() {
79 // Note that we check for a non-zero target duration without locking to keep
80 // things quick for the common case when delays are disabled. Since the delay
81 // calculation is done with a lock held, it will always be correct. The only
82 // downside of this is that we may fail to apply some delays when the target
83 // duration changes.
84 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
85 if (!target_duration_.ToInternalValue())
86 return;
88 base::TimeTicks start_time = clock_->Now();
90 AutoLock lock(lock_);
91 if (++begin_count_ != 1)
92 return;
93 end_time_ = CalculateEndTimeLocked(start_time);
97 void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) {
98 // See note in Begin().
99 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
100 if (!target_duration_.ToInternalValue()) {
101 *out_end_time = base::TimeTicks();
102 return;
105 base::TimeTicks start_time = clock_->Now();
107 AutoLock lock(lock_);
108 *out_end_time = CalculateEndTimeLocked(start_time);
112 void TraceEventSyntheticDelay::End() {
113 // See note in Begin().
114 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
115 if (!target_duration_.ToInternalValue())
116 return;
118 base::TimeTicks end_time;
120 AutoLock lock(lock_);
121 if (!begin_count_ || --begin_count_ != 0)
122 return;
123 end_time = end_time_;
125 if (!end_time.is_null())
126 ApplyDelay(end_time);
129 void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
130 if (!end_time.is_null())
131 ApplyDelay(end_time);
134 base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
135 base::TimeTicks start_time) {
136 if (mode_ == ONE_SHOT && trigger_count_++)
137 return base::TimeTicks();
138 else if (mode_ == ALTERNATING && trigger_count_++ % 2)
139 return base::TimeTicks();
140 return start_time + target_duration_;
143 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
144 TRACE_EVENT0("synthetic_delay", name_.c_str());
145 while (clock_->Now() < end_time) {
146 // Busy loop.
150 TraceEventSyntheticDelayRegistry*
151 TraceEventSyntheticDelayRegistry::GetInstance() {
152 return Singleton<
153 TraceEventSyntheticDelayRegistry,
154 LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
157 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
158 : delay_count_(0) {}
160 TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
161 const char* name) {
162 // Try to find an existing delay first without locking to make the common case
163 // fast.
164 int delay_count = base::subtle::Acquire_Load(&delay_count_);
165 for (int i = 0; i < delay_count; ++i) {
166 if (!strcmp(name, delays_[i].name_.c_str()))
167 return &delays_[i];
170 AutoLock lock(lock_);
171 delay_count = base::subtle::Acquire_Load(&delay_count_);
172 for (int i = 0; i < delay_count; ++i) {
173 if (!strcmp(name, delays_[i].name_.c_str()))
174 return &delays_[i];
177 DCHECK(delay_count < kMaxSyntheticDelays)
178 << "must increase kMaxSyntheticDelays";
179 if (delay_count >= kMaxSyntheticDelays)
180 return &dummy_delay_;
182 delays_[delay_count].Initialize(std::string(name), this);
183 base::subtle::Release_Store(&delay_count_, delay_count + 1);
184 return &delays_[delay_count];
187 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
188 return base::TimeTicks::Now();
191 void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
192 AutoLock lock(lock_);
193 int delay_count = base::subtle::Acquire_Load(&delay_count_);
194 for (int i = 0; i < delay_count; ++i) {
195 delays_[i].SetTargetDuration(base::TimeDelta());
196 delays_[i].SetClock(this);
200 void ResetTraceEventSyntheticDelays() {
201 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
204 } // namespace trace_event
205 } // namespace base
207 namespace trace_event_internal {
209 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name,
210 base::subtle::AtomicWord* impl_ptr)
211 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) {
212 delay_impl_->BeginParallel(&end_time_);
215 ScopedSyntheticDelay::~ScopedSyntheticDelay() {
216 delay_impl_->EndParallel(end_time_);
219 base::trace_event::TraceEventSyntheticDelay* GetOrCreateDelay(
220 const char* name,
221 base::subtle::AtomicWord* impl_ptr) {
222 base::trace_event::TraceEventSyntheticDelay* delay_impl =
223 reinterpret_cast<base::trace_event::TraceEventSyntheticDelay*>(
224 base::subtle::Acquire_Load(impl_ptr));
225 if (!delay_impl) {
226 delay_impl =
227 base::trace_event::TraceEventSyntheticDelayRegistry::GetInstance()
228 ->GetOrCreateDelay(name);
229 base::subtle::Release_Store(
230 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
232 return delay_impl;
235 } // namespace trace_event_internal