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.
5 #include "base/memory/singleton.h"
6 #include "base/trace_event/trace_event_synthetic_delay.h"
9 const int kMaxSyntheticDelays
= 32;
13 namespace trace_event
{
15 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
16 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
18 class TraceEventSyntheticDelayRegistry
: public TraceEventSyntheticDelayClock
{
20 static TraceEventSyntheticDelayRegistry
* GetInstance();
22 TraceEventSyntheticDelay
* GetOrCreateDelay(const char* name
);
23 void ResetAllDelays();
25 // TraceEventSyntheticDelayClock implementation.
26 base::TimeTicks
Now() override
;
29 TraceEventSyntheticDelayRegistry();
31 friend struct DefaultSingletonTraits
<TraceEventSyntheticDelayRegistry
>;
34 TraceEventSyntheticDelay delays_
[kMaxSyntheticDelays
];
35 TraceEventSyntheticDelay dummy_delay_
;
36 base::subtle::Atomic32 delay_count_
;
38 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry
);
41 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
42 : mode_(STATIC
), begin_count_(0), trigger_count_(0), clock_(NULL
) {}
44 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
46 TraceEventSyntheticDelay
* TraceEventSyntheticDelay::Lookup(
47 const std::string
& name
) {
48 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
52 void TraceEventSyntheticDelay::Initialize(
53 const std::string
& name
,
54 TraceEventSyntheticDelayClock
* clock
) {
59 void TraceEventSyntheticDelay::SetTargetDuration(
60 base::TimeDelta target_duration
) {
62 target_duration_
= target_duration
;
67 void TraceEventSyntheticDelay::SetMode(Mode mode
) {
72 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock
* clock
) {
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
83 ANNOTATE_BENIGN_RACE(&target_duration_
, "Synthetic delay duration");
84 if (!target_duration_
.ToInternalValue())
87 base::TimeTicks start_time
= clock_
->Now();
90 if (++begin_count_
!= 1)
92 end_time_
= CalculateEndTimeLocked(start_time
);
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();
104 base::TimeTicks start_time
= clock_
->Now();
106 AutoLock
lock(lock_
);
107 *out_end_time
= CalculateEndTimeLocked(start_time
);
111 void TraceEventSyntheticDelay::End() {
112 // See note in Begin().
113 ANNOTATE_BENIGN_RACE(&target_duration_
, "Synthetic delay duration");
114 if (!target_duration_
.ToInternalValue())
117 base::TimeTicks end_time
;
119 AutoLock
lock(lock_
);
120 if (!begin_count_
|| --begin_count_
!= 0)
122 end_time
= end_time_
;
124 if (!end_time
.is_null())
125 ApplyDelay(end_time
);
128 void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time
) {
129 if (!end_time
.is_null())
130 ApplyDelay(end_time
);
133 base::TimeTicks
TraceEventSyntheticDelay::CalculateEndTimeLocked(
134 base::TimeTicks start_time
) {
135 if (mode_
== ONE_SHOT
&& trigger_count_
++)
136 return base::TimeTicks();
137 else if (mode_
== ALTERNATING
&& trigger_count_
++ % 2)
138 return base::TimeTicks();
139 return start_time
+ target_duration_
;
142 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time
) {
143 TRACE_EVENT0("synthetic_delay", name_
.c_str());
144 while (clock_
->Now() < end_time
) {
149 TraceEventSyntheticDelayRegistry
*
150 TraceEventSyntheticDelayRegistry::GetInstance() {
152 TraceEventSyntheticDelayRegistry
,
153 LeakySingletonTraits
<TraceEventSyntheticDelayRegistry
> >::get();
156 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
159 TraceEventSyntheticDelay
* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
161 // Try to find an existing delay first without locking to make the common case
163 int delay_count
= base::subtle::Acquire_Load(&delay_count_
);
164 for (int i
= 0; i
< delay_count
; ++i
) {
165 if (!strcmp(name
, delays_
[i
].name_
.c_str()))
169 AutoLock
lock(lock_
);
170 delay_count
= base::subtle::Acquire_Load(&delay_count_
);
171 for (int i
= 0; i
< delay_count
; ++i
) {
172 if (!strcmp(name
, delays_
[i
].name_
.c_str()))
176 DCHECK(delay_count
< kMaxSyntheticDelays
)
177 << "must increase kMaxSyntheticDelays";
178 if (delay_count
>= kMaxSyntheticDelays
)
179 return &dummy_delay_
;
181 delays_
[delay_count
].Initialize(std::string(name
), this);
182 base::subtle::Release_Store(&delay_count_
, delay_count
+ 1);
183 return &delays_
[delay_count
];
186 base::TimeTicks
TraceEventSyntheticDelayRegistry::Now() {
187 return base::TimeTicks::Now();
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 delays_
[i
].SetClock(this);
199 void ResetTraceEventSyntheticDelays() {
200 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
203 } // namespace trace_event
206 namespace trace_event_internal
{
208 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name
,
209 base::subtle::AtomicWord
* impl_ptr
)
210 : delay_impl_(GetOrCreateDelay(name
, impl_ptr
)) {
211 delay_impl_
->BeginParallel(&end_time_
);
214 ScopedSyntheticDelay::~ScopedSyntheticDelay() {
215 delay_impl_
->EndParallel(end_time_
);
218 base::trace_event::TraceEventSyntheticDelay
* GetOrCreateDelay(
220 base::subtle::AtomicWord
* impl_ptr
) {
221 base::trace_event::TraceEventSyntheticDelay
* delay_impl
=
222 reinterpret_cast<base::trace_event::TraceEventSyntheticDelay
*>(
223 base::subtle::Acquire_Load(impl_ptr
));
226 base::trace_event::TraceEventSyntheticDelayRegistry::GetInstance()
227 ->GetOrCreateDelay(name
);
228 base::subtle::Release_Store(
229 impl_ptr
, reinterpret_cast<base::subtle::AtomicWord
>(delay_impl
));
234 } // namespace trace_event_internal