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/third_party/dynamic_annotations/dynamic_annotations.h"
7 #include "base/trace_event/trace_event_synthetic_delay.h"
10 const int kMaxSyntheticDelays
= 32;
14 namespace trace_event
{
16 TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
17 TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
19 class TraceEventSyntheticDelayRegistry
: public TraceEventSyntheticDelayClock
{
21 static TraceEventSyntheticDelayRegistry
* GetInstance();
23 TraceEventSyntheticDelay
* GetOrCreateDelay(const char* name
);
24 void ResetAllDelays();
26 // TraceEventSyntheticDelayClock implementation.
27 base::TimeTicks
Now() override
;
30 TraceEventSyntheticDelayRegistry();
32 friend struct DefaultSingletonTraits
<TraceEventSyntheticDelayRegistry
>;
35 TraceEventSyntheticDelay delays_
[kMaxSyntheticDelays
];
36 TraceEventSyntheticDelay dummy_delay_
;
37 base::subtle::Atomic32 delay_count_
;
39 DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry
);
42 TraceEventSyntheticDelay::TraceEventSyntheticDelay()
43 : mode_(STATIC
), begin_count_(0), trigger_count_(0), clock_(NULL
) {}
45 TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
47 TraceEventSyntheticDelay
* TraceEventSyntheticDelay::Lookup(
48 const std::string
& name
) {
49 return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
53 void TraceEventSyntheticDelay::Initialize(
54 const std::string
& name
,
55 TraceEventSyntheticDelayClock
* clock
) {
60 void TraceEventSyntheticDelay::SetTargetDuration(
61 base::TimeDelta target_duration
) {
63 target_duration_
= target_duration
;
68 void TraceEventSyntheticDelay::SetMode(Mode mode
) {
73 void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock
* clock
) {
78 void TraceEventSyntheticDelay::Begin() {
79 // Note that we check for a non-zero target duration without locking to keep
80 // things quick for the common case when delays are disabled. Since the delay
81 // calculation is done with a lock held, it will always be correct. The only
82 // downside of this is that we may fail to apply some delays when the target
84 ANNOTATE_BENIGN_RACE(&target_duration_
, "Synthetic delay duration");
85 if (!target_duration_
.ToInternalValue())
88 base::TimeTicks start_time
= clock_
->Now();
91 if (++begin_count_
!= 1)
93 end_time_
= CalculateEndTimeLocked(start_time
);
97 void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks
* out_end_time
) {
98 // See note in Begin().
99 ANNOTATE_BENIGN_RACE(&target_duration_
, "Synthetic delay duration");
100 if (!target_duration_
.ToInternalValue()) {
101 *out_end_time
= base::TimeTicks();
105 base::TimeTicks start_time
= clock_
->Now();
107 AutoLock
lock(lock_
);
108 *out_end_time
= CalculateEndTimeLocked(start_time
);
112 void TraceEventSyntheticDelay::End() {
113 // See note in Begin().
114 ANNOTATE_BENIGN_RACE(&target_duration_
, "Synthetic delay duration");
115 if (!target_duration_
.ToInternalValue())
118 base::TimeTicks end_time
;
120 AutoLock
lock(lock_
);
121 if (!begin_count_
|| --begin_count_
!= 0)
123 end_time
= end_time_
;
125 if (!end_time
.is_null())
126 ApplyDelay(end_time
);
129 void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time
) {
130 if (!end_time
.is_null())
131 ApplyDelay(end_time
);
134 base::TimeTicks
TraceEventSyntheticDelay::CalculateEndTimeLocked(
135 base::TimeTicks start_time
) {
136 if (mode_
== ONE_SHOT
&& trigger_count_
++)
137 return base::TimeTicks();
138 else if (mode_
== ALTERNATING
&& trigger_count_
++ % 2)
139 return base::TimeTicks();
140 return start_time
+ target_duration_
;
143 void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time
) {
144 TRACE_EVENT0("synthetic_delay", name_
.c_str());
145 while (clock_
->Now() < end_time
) {
150 TraceEventSyntheticDelayRegistry
*
151 TraceEventSyntheticDelayRegistry::GetInstance() {
153 TraceEventSyntheticDelayRegistry
,
154 LeakySingletonTraits
<TraceEventSyntheticDelayRegistry
> >::get();
157 TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
160 TraceEventSyntheticDelay
* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
162 // Try to find an existing delay first without locking to make the common case
164 int delay_count
= base::subtle::Acquire_Load(&delay_count_
);
165 for (int i
= 0; i
< delay_count
; ++i
) {
166 if (!strcmp(name
, delays_
[i
].name_
.c_str()))
170 AutoLock
lock(lock_
);
171 delay_count
= base::subtle::Acquire_Load(&delay_count_
);
172 for (int i
= 0; i
< delay_count
; ++i
) {
173 if (!strcmp(name
, delays_
[i
].name_
.c_str()))
177 DCHECK(delay_count
< kMaxSyntheticDelays
)
178 << "must increase kMaxSyntheticDelays";
179 if (delay_count
>= kMaxSyntheticDelays
)
180 return &dummy_delay_
;
182 delays_
[delay_count
].Initialize(std::string(name
), this);
183 base::subtle::Release_Store(&delay_count_
, delay_count
+ 1);
184 return &delays_
[delay_count
];
187 base::TimeTicks
TraceEventSyntheticDelayRegistry::Now() {
188 return base::TimeTicks::Now();
191 void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
192 AutoLock
lock(lock_
);
193 int delay_count
= base::subtle::Acquire_Load(&delay_count_
);
194 for (int i
= 0; i
< delay_count
; ++i
) {
195 delays_
[i
].SetTargetDuration(base::TimeDelta());
196 delays_
[i
].SetClock(this);
200 void ResetTraceEventSyntheticDelays() {
201 TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
204 } // namespace trace_event
207 namespace trace_event_internal
{
209 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name
,
210 base::subtle::AtomicWord
* impl_ptr
)
211 : delay_impl_(GetOrCreateDelay(name
, impl_ptr
)) {
212 delay_impl_
->BeginParallel(&end_time_
);
215 ScopedSyntheticDelay::~ScopedSyntheticDelay() {
216 delay_impl_
->EndParallel(end_time_
);
219 base::trace_event::TraceEventSyntheticDelay
* GetOrCreateDelay(
221 base::subtle::AtomicWord
* impl_ptr
) {
222 base::trace_event::TraceEventSyntheticDelay
* delay_impl
=
223 reinterpret_cast<base::trace_event::TraceEventSyntheticDelay
*>(
224 base::subtle::Acquire_Load(impl_ptr
));
227 base::trace_event::TraceEventSyntheticDelayRegistry::GetInstance()
228 ->GetOrCreateDelay(name
);
229 base::subtle::Release_Store(
230 impl_ptr
, reinterpret_cast<base::subtle::AtomicWord
>(delay_impl
));
235 } // namespace trace_event_internal