• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TraceEventSyntheticDelayClock()15 TraceEventSyntheticDelayClock::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   virtual 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 
TraceEventSyntheticDelay()41 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
42     : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
43 
~TraceEventSyntheticDelay()44 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
45 
Lookup(const std::string & name)46 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
47     const std::string& name) {
48   return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
49       name.c_str());
50 }
51 
Initialize(const std::string & name,TraceEventSyntheticDelayClock * clock)52 void TraceEventSyntheticDelay::Initialize(
53     const std::string& name,
54     TraceEventSyntheticDelayClock* clock) {
55   name_ = name;
56   clock_ = clock;
57 }
58 
SetTargetDuration(base::TimeDelta target_duration)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 
SetMode(Mode mode)67 void TraceEventSyntheticDelay::SetMode(Mode mode) {
68   AutoLock lock(lock_);
69   mode_ = mode;
70 }
71 
SetClock(TraceEventSyntheticDelayClock * clock)72 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
73   AutoLock lock(lock_);
74   clock_ = clock;
75 }
76 
Begin()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 
BeginParallel(base::TimeTicks * out_end_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;
102   }
103 
104   base::TimeTicks start_time = clock_->Now();
105   {
106     AutoLock lock(lock_);
107     *out_end_time = CalculateEndTimeLocked(start_time);
108   }
109 }
110 
End()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 
EndParallel(base::TimeTicks end_time)128 void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
129   if (!end_time.is_null())
130     ApplyDelay(end_time);
131 }
132 
CalculateEndTimeLocked(base::TimeTicks start_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_;
140 }
141 
ApplyDelay(base::TimeTicks end_time)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*
GetInstance()150 TraceEventSyntheticDelayRegistry::GetInstance() {
151   return Singleton<
152       TraceEventSyntheticDelayRegistry,
153       LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
154 }
155 
TraceEventSyntheticDelayRegistry()156 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
157     : delay_count_(0) {}
158 
GetOrCreateDelay(const char * name)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 
Now()186 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
187   return base::TimeTicks::HighResNow();
188 }
189 
ResetAllDelays()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 
ResetTraceEventSyntheticDelays()199 void ResetTraceEventSyntheticDelays() {
200   TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
201 }
202 
203 }  // namespace debug
204 }  // namespace base
205 
206 namespace trace_event_internal {
207 
ScopedSyntheticDelay(const char * name,base::subtle::AtomicWord * impl_ptr)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 
~ScopedSyntheticDelay()214 ScopedSyntheticDelay::~ScopedSyntheticDelay() {
215   delay_impl_->EndParallel(end_time_);
216 }
217 
GetOrCreateDelay(const char * name,base::subtle::AtomicWord * impl_ptr)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::NoBarrier_Load(impl_ptr));
224   if (!delay_impl) {
225     delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance()
226                      ->GetOrCreateDelay(name);
227     base::subtle::NoBarrier_Store(
228         impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
229   }
230   return delay_impl;
231 }
232 
233 }  // namespace trace_event_internal
234