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