Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1054)

Side by Side Diff: base/debug/trace_event_synthetic_delay.cc

Issue 53923005: Add synthetic delay testing framework (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Renaming and cleanup. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 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 #include "base/synchronization/lock.h"
8 #include "base/threading/platform_thread.h"
9
10 namespace {
11 const int kMaxSyntheticDelays = 32;
12 } // namespace
13
14 namespace base {
15 namespace debug {
16
17 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
18 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
19
20 class TraceEventSyntheticDelayRegistry
21 : public TraceEventSyntheticDelayClock {
22 public:
23 static TraceEventSyntheticDelayRegistry* GetInstance();
24
25 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
26
27 // TraceEventSyntheticDelayClock implementation.
28 virtual base::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 base::subtle::Atomic32 delay_count_;
39
40 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
41 };
42
43 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
44 : mode_(STATIC), generation_(0), clock_(NULL) {}
45
46 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
47 const std::string& name) {
48 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
49 name.c_str());
50 }
51
52 void TraceEventSyntheticDelay::Initialize(
53 const std::string& name,
54 TraceEventSyntheticDelayClock* clock) {
55 DCHECK(!thread_state_.Get());
56 name_ = name;
57 clock_ = clock;
58 }
59
60 void TraceEventSyntheticDelay::SetTargetDuration(
61 base::TimeDelta target_duration) {
62 AutoLock lock(lock_);
63 target_duration_ = target_duration;
64 generation_++;
65 }
66
67 void TraceEventSyntheticDelay::SetMode(Mode mode) {
68 AutoLock lock(lock_);
69 mode_ = mode;
70 generation_++;
71 }
72
73 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
74 AutoLock lock(lock_);
75 clock_ = clock;
76 generation_++;
77 }
78
79 TraceEventSyntheticDelay::ThreadState::ThreadState()
80 : trigger_count(0u), generation(0) {}
81
82 void TraceEventSyntheticDelay::Activate() {
83 // Note that we check for a non-zero target duration without locking to keep
84 // things quick for the common case when delays are disabled. Since the delay
85 // calculation is done with a lock held, it will always be correct. The only
86 // downside of this is that we may fail to apply some delays when the target
87 // duration changes.
88 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
89 if (!target_duration_.ToInternalValue())
90 return;
91
92 // Store the start time in a thread local struct so the same delay can be
93 // applied to multiple threads simultaneously. Note that the structs are
94 // leaked at program exit.
95 ThreadState* thread_state = EnsureThreadState();
96 if (!thread_state->start_time.ToInternalValue())
97 thread_state->start_time = clock_->Now();
98 }
99
100 TraceEventSyntheticDelay::ThreadState*
101 TraceEventSyntheticDelay::EnsureThreadState() {
102 ThreadState* thread_state = thread_state_.Get();
103 if (!thread_state)
104 thread_state_.Set((thread_state = new ThreadState()));
105 return thread_state;
106 }
107
108 void TraceEventSyntheticDelay::Apply() {
109 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
110 if (!target_duration_.ToInternalValue())
111 return;
112
113 ThreadState* thread_state = EnsureThreadState();
114 if (!thread_state->start_time.ToInternalValue())
115 return;
116 base::TimeTicks now = clock_->Now();
117 base::TimeTicks start_time = thread_state->start_time;
118 base::TimeTicks end_time;
119 thread_state->start_time = base::TimeTicks();
120
121 {
122 AutoLock lock(lock_);
123 if (thread_state->generation != generation_) {
124 thread_state->trigger_count = 0;
125 thread_state->generation = generation_;
126 }
127
128 if (mode_ == ONE_SHOT && thread_state->trigger_count++)
129 return;
130 else if (mode_ == ALTERNATING && thread_state->trigger_count++ % 2)
131 return;
132
133 end_time = start_time + target_duration_;
134 if (now >= end_time)
135 return;
136 }
137 ApplyDelay(end_time);
138 }
139
140 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
141 TRACE_EVENT0("synthetic_delay", name_.c_str());
142 while (clock_->Now() < end_time) {
143 // Busy loop.
144 }
145 }
146
147 TraceEventSyntheticDelayRegistry*
148 TraceEventSyntheticDelayRegistry::GetInstance() {
149 return Singleton<
150 TraceEventSyntheticDelayRegistry,
151 LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
152 }
153
154 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
155 : delay_count_(0) {}
156
157 TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
158 const char* name) {
159 // Try to find an existing delay first without locking to make the common case
160 // fast.
161 int delay_count = base::subtle::Acquire_Load(&delay_count_);
162 for (int i = 0; i < delay_count; ++i) {
163 if (!strcmp(name, delays_[i].name_.c_str()))
164 return &delays_[i];
165 }
166
167 AutoLock lock(lock_);
168 delay_count = base::subtle::Acquire_Load(&delay_count_);
169 for (int i = 0; i < delay_count; ++i) {
170 if (!strcmp(name, delays_[i].name_.c_str()))
171 return &delays_[i];
172 }
173
174 DCHECK(delay_count < kMaxSyntheticDelays)
175 << "must increase kMaxSyntheticDelays";
176 if (delay_count >= kMaxSyntheticDelays)
177 return &dummy_delay_;
178
179 delays_[delay_count].Initialize(std::string(name), this);
180 base::subtle::Release_Store(&delay_count_, delay_count + 1);
181 return &delays_[delay_count];
182 }
183
184 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
185 return base::TimeTicks::HighResNow();
186 }
187
188 } // namespace debug
189 } // namespace base
190
191 namespace trace_event_internal {
192
193 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name,
194 base::subtle::AtomicWord* impl_ptr)
195 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) {
196 delay_impl_->Activate();
197 }
198
199 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->Apply(); }
200
201 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay(
202 const char* name,
203 base::subtle::AtomicWord* impl_ptr) {
204 base::debug::TraceEventSyntheticDelay* delay_impl =
205 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>(
206 base::subtle::NoBarrier_Load(impl_ptr));
207 if (!delay_impl) {
208 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance()
209 ->GetOrCreateDelay(name);
210 base::subtle::NoBarrier_Store(
211 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
212 }
213 return delay_impl;
214 }
215
216 } // namespace trace_event_internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698