• 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/macros.h"
6 #include "base/memory/singleton.h"
7 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
8 #include "base/trace_event/trace_event_synthetic_delay.h"
9 
10 namespace {
11 const int kMaxSyntheticDelays = 32;
12 }  // namespace
13 
14 namespace base {
15 namespace trace_event {
16 
TraceEventSyntheticDelayClock()17 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
~TraceEventSyntheticDelayClock()18 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
19 
20 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
21  public:
22   static TraceEventSyntheticDelayRegistry* GetInstance();
23 
24   TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
25   void ResetAllDelays();
26 
27   // TraceEventSyntheticDelayClock implementation.
28   TimeTicks Now() override;
29 
30  private:
31   TraceEventSyntheticDelayRegistry();
32 
33   friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
34 
35   Lock lock_;
36   TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
37   TraceEventSyntheticDelay dummy_delay_;
38   subtle::Atomic32 delay_count_;
39 
40   DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
41 };
42 
TraceEventSyntheticDelay()43 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
44     : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
45 
~TraceEventSyntheticDelay()46 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
47 
Lookup(const std::string & name)48 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
49     const std::string& name) {
50   return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
51       name.c_str());
52 }
53 
Initialize(const std::string & name,TraceEventSyntheticDelayClock * clock)54 void TraceEventSyntheticDelay::Initialize(
55     const std::string& name,
56     TraceEventSyntheticDelayClock* clock) {
57   name_ = name;
58   clock_ = clock;
59 }
60 
SetTargetDuration(TimeDelta target_duration)61 void TraceEventSyntheticDelay::SetTargetDuration(TimeDelta target_duration) {
62   AutoLock lock(lock_);
63   target_duration_ = target_duration;
64   trigger_count_ = 0;
65   begin_count_ = 0;
66 }
67 
SetMode(Mode mode)68 void TraceEventSyntheticDelay::SetMode(Mode mode) {
69   AutoLock lock(lock_);
70   mode_ = mode;
71 }
72 
SetClock(TraceEventSyntheticDelayClock * clock)73 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
74   AutoLock lock(lock_);
75   clock_ = clock;
76 }
77 
Begin()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;
87 
88   TimeTicks start_time = clock_->Now();
89   {
90     AutoLock lock(lock_);
91     if (++begin_count_ != 1)
92       return;
93     end_time_ = CalculateEndTimeLocked(start_time);
94   }
95 }
96 
BeginParallel(TimeTicks * out_end_time)97 void TraceEventSyntheticDelay::BeginParallel(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 = TimeTicks();
102     return;
103   }
104 
105   TimeTicks start_time = clock_->Now();
106   {
107     AutoLock lock(lock_);
108     *out_end_time = CalculateEndTimeLocked(start_time);
109   }
110 }
111 
End()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;
117 
118   TimeTicks end_time;
119   {
120     AutoLock lock(lock_);
121     if (!begin_count_ || --begin_count_ != 0)
122       return;
123     end_time = end_time_;
124   }
125   if (!end_time.is_null())
126     ApplyDelay(end_time);
127 }
128 
EndParallel(TimeTicks end_time)129 void TraceEventSyntheticDelay::EndParallel(TimeTicks end_time) {
130   if (!end_time.is_null())
131     ApplyDelay(end_time);
132 }
133 
CalculateEndTimeLocked(TimeTicks start_time)134 TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
135     TimeTicks start_time) {
136   if (mode_ == ONE_SHOT && trigger_count_++)
137     return TimeTicks();
138   else if (mode_ == ALTERNATING && trigger_count_++ % 2)
139     return TimeTicks();
140   return start_time + target_duration_;
141 }
142 
ApplyDelay(TimeTicks end_time)143 void TraceEventSyntheticDelay::ApplyDelay(TimeTicks end_time) {
144   TRACE_EVENT0("synthetic_delay", name_.c_str());
145   while (clock_->Now() < end_time) {
146     // Busy loop.
147   }
148 }
149 
150 TraceEventSyntheticDelayRegistry*
GetInstance()151 TraceEventSyntheticDelayRegistry::GetInstance() {
152   return Singleton<
153       TraceEventSyntheticDelayRegistry,
154       LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
155 }
156 
TraceEventSyntheticDelayRegistry()157 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
158     : delay_count_(0) {}
159 
GetOrCreateDelay(const char * name)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 = 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];
168   }
169 
170   AutoLock lock(lock_);
171   delay_count = 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];
175   }
176 
177   DCHECK(delay_count < kMaxSyntheticDelays)
178       << "must increase kMaxSyntheticDelays";
179   if (delay_count >= kMaxSyntheticDelays)
180     return &dummy_delay_;
181 
182   delays_[delay_count].Initialize(std::string(name), this);
183   subtle::Release_Store(&delay_count_, delay_count + 1);
184   return &delays_[delay_count];
185 }
186 
Now()187 TimeTicks TraceEventSyntheticDelayRegistry::Now() {
188   return TimeTicks::Now();
189 }
190 
ResetAllDelays()191 void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
192   AutoLock lock(lock_);
193   int delay_count = subtle::Acquire_Load(&delay_count_);
194   for (int i = 0; i < delay_count; ++i) {
195     delays_[i].SetTargetDuration(TimeDelta());
196     delays_[i].SetClock(this);
197   }
198 }
199 
ResetTraceEventSyntheticDelays()200 void ResetTraceEventSyntheticDelays() {
201   TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
202 }
203 
204 }  // namespace trace_event
205 }  // namespace base
206 
207 namespace trace_event_internal {
208 
ScopedSyntheticDelay(const char * name,base::subtle::AtomicWord * impl_ptr)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_);
213 }
214 
~ScopedSyntheticDelay()215 ScopedSyntheticDelay::~ScopedSyntheticDelay() {
216   delay_impl_->EndParallel(end_time_);
217 }
218 
GetOrCreateDelay(const char * name,base::subtle::AtomicWord * impl_ptr)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));
231   }
232   return delay_impl;
233 }
234 
235 }  // namespace trace_event_internal
236