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

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: Happy new year Created 6 years, 11 months 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) 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 #include "base/threading/platform_thread.h"
8 #include "base/threading/thread_local.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 // Thread-local state for each synthetic delay point. This allows the same delay
21 // to be applied to multiple threads simultaneously.
22 struct ThreadState {
23 ThreadState();
24
25 base::TimeTicks start_time;
26 unsigned trigger_count;
27 int generation;
28 };
29
30 ThreadState::ThreadState() : trigger_count(0u), generation(0) {}
31
32 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
33 public:
34 static TraceEventSyntheticDelayRegistry* GetInstance();
35
36 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
37 ThreadState* GetThreadState(int index);
38
39 // TraceEventSyntheticDelayClock implementation.
40 virtual base::TimeTicks Now() OVERRIDE;
41
42 private:
43 TraceEventSyntheticDelayRegistry();
44
45 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
46
47 Lock lock_;
48 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
49 TraceEventSyntheticDelay dummy_delay_;
50 base::subtle::Atomic32 delay_count_;
51
52 ThreadLocalPointer<ThreadState> thread_states_;
53
54 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
55 };
56
57 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
58 : mode_(STATIC), generation_(0), thread_state_index_(0), clock_(NULL) {}
59
60 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
61
62 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
63 const std::string& name) {
64 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
65 name.c_str());
66 }
67
68 void TraceEventSyntheticDelay::Initialize(
69 const std::string& name,
70 TraceEventSyntheticDelayClock* clock,
71 int thread_state_index) {
72 name_ = name;
73 clock_ = clock;
74 thread_state_index_ = thread_state_index;
75 }
76
77 void TraceEventSyntheticDelay::SetTargetDuration(
78 base::TimeDelta target_duration) {
79 AutoLock lock(lock_);
80 target_duration_ = target_duration;
81 generation_++;
82 }
83
84 void TraceEventSyntheticDelay::SetMode(Mode mode) {
85 AutoLock lock(lock_);
86 mode_ = mode;
87 generation_++;
88 }
89
90 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
91 AutoLock lock(lock_);
92 clock_ = clock;
93 generation_++;
94 }
95
96 void TraceEventSyntheticDelay::Activate() {
97 // Note that we check for a non-zero target duration without locking to keep
98 // things quick for the common case when delays are disabled. Since the delay
99 // calculation is done with a lock held, it will always be correct. The only
100 // downside of this is that we may fail to apply some delays when the target
101 // duration changes.
102 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
103 if (!target_duration_.ToInternalValue())
104 return;
105
106 ThreadState* thread_state =
107 TraceEventSyntheticDelayRegistry::GetInstance()->
108 GetThreadState(thread_state_index_);
109 if (!thread_state->start_time.ToInternalValue())
110 thread_state->start_time = clock_->Now();
111 }
112
113 void TraceEventSyntheticDelay::Apply() {
114 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
115 if (!target_duration_.ToInternalValue())
116 return;
117
118 ThreadState* thread_state =
119 TraceEventSyntheticDelayRegistry::GetInstance()->
120 GetThreadState(thread_state_index_);
121 if (!thread_state->start_time.ToInternalValue())
122 return;
123 base::TimeTicks now = clock_->Now();
124 base::TimeTicks start_time = thread_state->start_time;
125 base::TimeTicks end_time;
126 thread_state->start_time = base::TimeTicks();
127
128 {
129 AutoLock lock(lock_);
130 if (thread_state->generation != generation_) {
131 thread_state->trigger_count = 0;
132 thread_state->generation = generation_;
133 }
134
135 if (mode_ == ONE_SHOT && thread_state->trigger_count++)
136 return;
137 else if (mode_ == ALTERNATING && thread_state->trigger_count++ % 2)
138 return;
139
140 end_time = start_time + target_duration_;
141 if (now >= end_time)
142 return;
143 }
144 ApplyDelay(end_time);
145 }
146
147 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
148 TRACE_EVENT0("synthetic_delay", name_.c_str());
149 while (clock_->Now() < end_time) {
150 // Busy loop.
151 }
152 }
153
154 TraceEventSyntheticDelayRegistry*
155 TraceEventSyntheticDelayRegistry::GetInstance() {
156 return Singleton<
157 TraceEventSyntheticDelayRegistry,
158 LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
159 }
160
161 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
162 : delay_count_(0) {}
163
164 TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
165 const char* name) {
166 // Try to find an existing delay first without locking to make the common case
167 // fast.
168 int 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 AutoLock lock(lock_);
175 delay_count = base::subtle::Acquire_Load(&delay_count_);
176 for (int i = 0; i < delay_count; ++i) {
177 if (!strcmp(name, delays_[i].name_.c_str()))
178 return &delays_[i];
179 }
180
181 DCHECK(delay_count < kMaxSyntheticDelays)
182 << "must increase kMaxSyntheticDelays";
183 if (delay_count >= kMaxSyntheticDelays)
184 return &dummy_delay_;
185
186 delays_[delay_count].Initialize(std::string(name), this, delay_count);
187 base::subtle::Release_Store(&delay_count_, delay_count + 1);
188 return &delays_[delay_count];
189 }
190
191 ThreadState* TraceEventSyntheticDelayRegistry::GetThreadState(int index) {
192 DCHECK(index >= 0 && index < kMaxSyntheticDelays);
193 if (index < 0 || index >= kMaxSyntheticDelays)
194 return NULL;
195
196 // Note that these thread states are leaked at program exit. They will only
197 // get allocated if synthetic delays are actually used.
198 ThreadState* thread_states = thread_states_.Get();
199 if (!thread_states)
200 thread_states_.Set((thread_states = new ThreadState[kMaxSyntheticDelays]));
201 return &thread_states[index];
202 }
203
204 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
205 return base::TimeTicks::HighResNow();
206 }
207
208 } // namespace debug
209 } // namespace base
210
211 namespace trace_event_internal {
212
213 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name,
214 base::subtle::AtomicWord* impl_ptr)
215 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) {
216 delay_impl_->Activate();
217 }
218
219 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->Apply(); }
220
221 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay(
222 const char* name,
223 base::subtle::AtomicWord* impl_ptr) {
224 base::debug::TraceEventSyntheticDelay* delay_impl =
225 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>(
226 base::subtle::NoBarrier_Load(impl_ptr));
227 if (!delay_impl) {
228 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance()
229 ->GetOrCreateDelay(name);
230 base::subtle::NoBarrier_Store(
231 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
232 }
233 return delay_impl;
234 }
235
236 } // namespace trace_event_internal
OLDNEW
« no previous file with comments | « base/debug/trace_event_synthetic_delay.h ('k') | base/debug/trace_event_synthetic_delay_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698