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

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

Issue 104613003: Use Begin/End semantics for synthetic delays (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add parallel Begin/End and reset. 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/debug/trace_event_synthetic_delay.h" 5 #include "base/debug/trace_event_synthetic_delay.h"
6 #include "base/memory/singleton.h" 6 #include "base/memory/singleton.h"
7 #include "base/threading/platform_thread.h"
8 #include "base/threading/thread_local.h"
9 7
10 namespace { 8 namespace {
11 const int kMaxSyntheticDelays = 32; 9 const int kMaxSyntheticDelays = 32;
12 } // namespace 10 } // namespace
13 11
14 namespace base { 12 namespace base {
15 namespace debug { 13 namespace debug {
16 14
17 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {} 15 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
18 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {} 16 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
19 17
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 {
brianderson 2013/12/19 00:16:59 Since you are removing the thread-local state, doe
Sami 2013/12/19 11:14:59 Yes, now the only way to apply a specific delay in
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 { 18 class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
33 public: 19 public:
34 static TraceEventSyntheticDelayRegistry* GetInstance(); 20 static TraceEventSyntheticDelayRegistry* GetInstance();
35 21
36 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name); 22 TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
37 ThreadState* GetThreadState(int index); 23 void ResetAllDelays();
38 24
39 // TraceEventSyntheticDelayClock implementation. 25 // TraceEventSyntheticDelayClock implementation.
40 virtual base::TimeTicks Now() OVERRIDE; 26 virtual base::TimeTicks Now() OVERRIDE;
41 27
42 private: 28 private:
43 TraceEventSyntheticDelayRegistry(); 29 TraceEventSyntheticDelayRegistry();
44 30
45 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>; 31 friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
46 32
47 Lock lock_; 33 Lock lock_;
48 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays]; 34 TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
49 TraceEventSyntheticDelay dummy_delay_; 35 TraceEventSyntheticDelay dummy_delay_;
50 base::subtle::Atomic32 delay_count_; 36 base::subtle::Atomic32 delay_count_;
51 37
52 ThreadLocalPointer<ThreadState> thread_states_;
53
54 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry); 38 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
55 }; 39 };
56 40
57 TraceEventSyntheticDelay::TraceEventSyntheticDelay() 41 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
58 : mode_(STATIC), generation_(0), thread_state_index_(0), clock_(NULL) {} 42 : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
59 43
60 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {} 44 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
61 45
62 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup( 46 TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
63 const std::string& name) { 47 const std::string& name) {
64 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay( 48 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
65 name.c_str()); 49 name.c_str());
66 } 50 }
67 51
68 void TraceEventSyntheticDelay::Initialize( 52 void TraceEventSyntheticDelay::Initialize(
69 const std::string& name, 53 const std::string& name,
70 TraceEventSyntheticDelayClock* clock, 54 TraceEventSyntheticDelayClock* clock) {
71 int thread_state_index) {
72 name_ = name; 55 name_ = name;
73 clock_ = clock; 56 clock_ = clock;
74 thread_state_index_ = thread_state_index;
75 } 57 }
76 58
77 void TraceEventSyntheticDelay::SetTargetDuration( 59 void TraceEventSyntheticDelay::SetTargetDuration(
78 base::TimeDelta target_duration) { 60 base::TimeDelta target_duration) {
79 AutoLock lock(lock_); 61 AutoLock lock(lock_);
80 target_duration_ = target_duration; 62 target_duration_ = target_duration;
81 generation_++; 63 trigger_count_ = 0;
64 begin_count_ = 0;
82 } 65 }
83 66
84 void TraceEventSyntheticDelay::SetMode(Mode mode) { 67 void TraceEventSyntheticDelay::SetMode(Mode mode) {
85 AutoLock lock(lock_); 68 AutoLock lock(lock_);
86 mode_ = mode; 69 mode_ = mode;
87 generation_++;
88 } 70 }
89 71
90 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { 72 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
91 AutoLock lock(lock_); 73 AutoLock lock(lock_);
92 clock_ = clock; 74 clock_ = clock;
93 generation_++;
94 } 75 }
95 76
96 void TraceEventSyntheticDelay::Activate() { 77 void TraceEventSyntheticDelay::Begin() {
97 // Note that we check for a non-zero target duration without locking to keep 78 // 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 79 // 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 80 // 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 81 // downside of this is that we may fail to apply some delays when the target
101 // duration changes. 82 // duration changes.
102 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); 83 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
103 if (!target_duration_.ToInternalValue()) 84 if (!target_duration_.ToInternalValue())
104 return; 85 return;
105 86
106 ThreadState* thread_state = 87 base::TimeTicks start_time = clock_->Now();
107 TraceEventSyntheticDelayRegistry::GetInstance()-> 88 {
108 GetThreadState(thread_state_index_); 89 AutoLock lock(lock_);
109 if (!thread_state->start_time.ToInternalValue()) 90 if (++begin_count_ != 1)
110 thread_state->start_time = clock_->Now(); 91 return;
92 end_time_ = CalculateEndTimeLocked(start_time);
93 }
111 } 94 }
112 95
113 void TraceEventSyntheticDelay::Apply() { 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
111 void TraceEventSyntheticDelay::End() {
112 // See note in Begin().
114 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); 113 ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
115 if (!target_duration_.ToInternalValue()) 114 if (!target_duration_.ToInternalValue())
116 return; 115 return;
117 116
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; 117 base::TimeTicks end_time;
126 thread_state->start_time = base::TimeTicks();
127
128 { 118 {
129 AutoLock lock(lock_); 119 AutoLock lock(lock_);
130 if (thread_state->generation != generation_) { 120 if (!begin_count_ || --begin_count_ != 0)
131 thread_state->trigger_count = 0; 121 return;
132 thread_state->generation = generation_; 122 end_time = end_time_;
133 } 123 }
124 if (!end_time.is_null())
125 ApplyDelay(end_time);
126 }
134 127
135 if (mode_ == ONE_SHOT && thread_state->trigger_count++) 128 void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
136 return; 129 if (!end_time.is_null())
137 else if (mode_ == ALTERNATING && thread_state->trigger_count++ % 2) 130 ApplyDelay(end_time);
brianderson 2013/12/19 00:16:59 I like how you make the client worry about about t
Sami 2013/12/19 11:14:59 Thanks. It took a few tries to get here but I thin
138 return; 131 }
139 132
140 end_time = start_time + target_duration_; 133 base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
141 if (now >= end_time) 134 base::TimeTicks start_time) {
142 return; 135 if (mode_ == ONE_SHOT && trigger_count_++)
143 } 136 return base::TimeTicks();
144 ApplyDelay(end_time); 137 else if (mode_ == ALTERNATING && trigger_count_++ % 2)
138 return base::TimeTicks();
139 return start_time + target_duration_;
145 } 140 }
146 141
147 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) { 142 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
148 TRACE_EVENT0("synthetic_delay", name_.c_str()); 143 TRACE_EVENT0("synthetic_delay", name_.c_str());
149 while (clock_->Now() < end_time) { 144 while (clock_->Now() < end_time) {
150 // Busy loop. 145 // Busy loop.
151 } 146 }
152 } 147 }
153 148
154 TraceEventSyntheticDelayRegistry* 149 TraceEventSyntheticDelayRegistry*
(...skipping 21 matching lines...) Expand all
176 for (int i = 0; i < delay_count; ++i) { 171 for (int i = 0; i < delay_count; ++i) {
177 if (!strcmp(name, delays_[i].name_.c_str())) 172 if (!strcmp(name, delays_[i].name_.c_str()))
178 return &delays_[i]; 173 return &delays_[i];
179 } 174 }
180 175
181 DCHECK(delay_count < kMaxSyntheticDelays) 176 DCHECK(delay_count < kMaxSyntheticDelays)
182 << "must increase kMaxSyntheticDelays"; 177 << "must increase kMaxSyntheticDelays";
183 if (delay_count >= kMaxSyntheticDelays) 178 if (delay_count >= kMaxSyntheticDelays)
184 return &dummy_delay_; 179 return &dummy_delay_;
185 180
186 delays_[delay_count].Initialize(std::string(name), this, delay_count); 181 delays_[delay_count].Initialize(std::string(name), this);
187 base::subtle::Release_Store(&delay_count_, delay_count + 1); 182 base::subtle::Release_Store(&delay_count_, delay_count + 1);
188 return &delays_[delay_count]; 183 return &delays_[delay_count];
189 } 184 }
190 185
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() { 186 base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
205 return base::TimeTicks::HighResNow(); 187 return base::TimeTicks::HighResNow();
206 } 188 }
207 189
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 }
196
197 void ResetTraceEventSyntheticDelays() {
198 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
199 }
200
208 } // namespace debug 201 } // namespace debug
209 } // namespace base 202 } // namespace base
210 203
211 namespace trace_event_internal { 204 namespace trace_event_internal {
212 205
213 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, 206 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name,
214 base::subtle::AtomicWord* impl_ptr) 207 base::subtle::AtomicWord* impl_ptr)
215 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) { 208 : delay_impl_(GetOrCreateDelay(name, impl_ptr)) {
216 delay_impl_->Activate(); 209 delay_impl_->Begin();
217 } 210 }
218 211
219 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->Apply(); } 212 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->End(); }
220 213
221 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay( 214 base::debug::TraceEventSyntheticDelay* GetOrCreateDelay(
222 const char* name, 215 const char* name,
223 base::subtle::AtomicWord* impl_ptr) { 216 base::subtle::AtomicWord* impl_ptr) {
224 base::debug::TraceEventSyntheticDelay* delay_impl = 217 base::debug::TraceEventSyntheticDelay* delay_impl =
225 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>( 218 reinterpret_cast<base::debug::TraceEventSyntheticDelay*>(
226 base::subtle::NoBarrier_Load(impl_ptr)); 219 base::subtle::NoBarrier_Load(impl_ptr));
227 if (!delay_impl) { 220 if (!delay_impl) {
228 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance() 221 delay_impl = base::debug::TraceEventSyntheticDelayRegistry::GetInstance()
229 ->GetOrCreateDelay(name); 222 ->GetOrCreateDelay(name);
230 base::subtle::NoBarrier_Store( 223 base::subtle::NoBarrier_Store(
231 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl)); 224 impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
232 } 225 }
233 return delay_impl; 226 return delay_impl;
234 } 227 }
235 228
236 } // namespace trace_event_internal 229 } // 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