1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The synthetic delay framework makes it possible to dynamically inject
// arbitrary delays into into different parts of the codebase. This can be used,
// for instance, for testing various task scheduling algorithms.
//
// The delays are specified in terms of a target duration for a given block of
// code. If the code executes faster than the duration, the thread is made to
// sleep until the deadline is met.
//
// Code can be instrumented for delays with two sets of macros. First, for
// delays that should apply within a scope, use the following macro:
//
// TRACE_EVENT_SYNTHETIC_DELAY("cc.LayerTreeHost.DrawAndSwap");
//
// For delaying operations that span multiple scopes, use:
//
// TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.Scheduler.BeginMainFrame");
// ...
// TRACE_EVENT_SYNTHETIC_DELAY_END("cc.Scheduler.BeginMainFrame");
//
// Here BEGIN establishes the start time for the delay and END executes the
// delay based on the remaining time. If BEGIN is called multiple times in a
// row, END should be called a corresponding number of times. Only the last
// call to END will have an effect.
//
// Note that a single delay may begin on one thread and end on another. This
// implies that a single delay cannot not be applied in several threads at once.
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
#include "base/atomicops.h"
#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
// Apply a named delay in the current scope.
#define TRACE_EVENT_SYNTHETIC_DELAY(name) \
static base::subtle::AtomicWord INTERNAL_TRACE_EVENT_UID(impl_ptr) = 0; \
trace_event_internal::ScopedSyntheticDelay INTERNAL_TRACE_EVENT_UID(delay)( \
name, &INTERNAL_TRACE_EVENT_UID(impl_ptr));
// Begin a named delay, establishing its timing start point. May be called
// multiple times as long as the calls to TRACE_EVENT_SYNTHETIC_DELAY_END are
// balanced. Only the first call records the timing start point.
#define TRACE_EVENT_SYNTHETIC_DELAY_BEGIN(name) \
do { \
static base::subtle::AtomicWord impl_ptr = 0; \
trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->Begin(); \
} while (false)
// End a named delay. The delay is applied only if this call matches the
// first corresponding call to TRACE_EVENT_SYNTHETIC_DELAY_BEGIN with the
// same delay.
#define TRACE_EVENT_SYNTHETIC_DELAY_END(name) \
do { \
static base::subtle::AtomicWord impl_ptr = 0; \
trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->End(); \
} while (false)
namespace base {
namespace trace_event {
// Time source for computing delay durations. Used for testing.
class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelayClock {
public:
TraceEventSyntheticDelayClock();
virtual ~TraceEventSyntheticDelayClock();
virtual base::TimeTicks Now() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayClock);
};
// Single delay point instance.
class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelay {
public:
enum Mode {
STATIC, // Apply the configured delay every time.
ONE_SHOT, // Apply the configured delay just once.
ALTERNATING // Apply the configured delay every other time.
};
// Returns an existing named delay instance or creates a new one with |name|.
static TraceEventSyntheticDelay* Lookup(const std::string& name);
void SetTargetDuration(TimeDelta target_duration);
void SetMode(Mode mode);
void SetClock(TraceEventSyntheticDelayClock* clock);
// Begin the delay, establishing its timing start point. May be called
// multiple times as long as the calls to End() are balanced. Only the first
// call records the timing start point.
void Begin();
// End the delay. The delay is applied only if this call matches the first
// corresponding call to Begin() with the same delay.
void End();
// Begin a parallel instance of the delay. Several parallel instances may be
// active simultaneously and will complete independently. The computed end
// time for the delay is stored in |out_end_time|, which should later be
// passed to EndParallel().
void BeginParallel(base::TimeTicks* out_end_time);
// End a previously started parallel delay. |end_time| is the delay end point
// computed by BeginParallel().
void EndParallel(base::TimeTicks end_time);
private:
TraceEventSyntheticDelay();
~TraceEventSyntheticDelay();
friend class TraceEventSyntheticDelayRegistry;
void Initialize(const std::string& name,
TraceEventSyntheticDelayClock* clock);
base::TimeTicks CalculateEndTimeLocked(base::TimeTicks start_time);
void ApplyDelay(base::TimeTicks end_time);
Lock lock_;
Mode mode_;
std::string name_;
int begin_count_;
int trigger_count_;
base::TimeTicks end_time_;
base::TimeDelta target_duration_;
TraceEventSyntheticDelayClock* clock_;
DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelay);
};
// Set the target durations of all registered synthetic delay points to zero.
TRACE_EVENT_API_CLASS_EXPORT void ResetTraceEventSyntheticDelays();
} // namespace trace_event
} // namespace base
namespace trace_event_internal {
// Helper class for scoped delays. Do not use directly.
class TRACE_EVENT_API_CLASS_EXPORT ScopedSyntheticDelay {
public:
explicit ScopedSyntheticDelay(const char* name,
base::subtle::AtomicWord* impl_ptr);
~ScopedSyntheticDelay();
private:
base::trace_event::TraceEventSyntheticDelay* delay_impl_;
base::TimeTicks end_time_;
DISALLOW_COPY_AND_ASSIGN(ScopedSyntheticDelay);
};
// Helper for registering delays. Do not use directly.
TRACE_EVENT_API_CLASS_EXPORT base::trace_event::TraceEventSyntheticDelay*
GetOrCreateDelay(const char* name, base::subtle::AtomicWord* impl_ptr);
} // namespace trace_event_internal
#endif // BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
|