Chromium Code Reviews| Index: base/debug/synthetic_delay.h |
| diff --git a/base/debug/synthetic_delay.h b/base/debug/synthetic_delay.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4639bb0d4bc4698a4ee5a180e3de1370c2229944 |
| --- /dev/null |
| +++ b/base/debug/synthetic_delay.h |
| @@ -0,0 +1,130 @@ |
| +// Copyright (c) 2013 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. |
|
Dominik Grewe
2013/11/07 16:45:53
Would it be better to busy wait rather than to sle
brianderson
2013/11/18 21:04:06
A sleep should work well if we are just testing th
|
| +// |
| +// Code can be instrumented for delays with two sets of macros. First, for |
| +// delays that should apply within a scope, use the following macro: |
| +// |
| +// SYNTHETIC_DELAY("cc.LayerTreeHost.DrawAndSwap"); |
| +// |
| +// For delaying operations that span multiple scopes, use: |
| +// |
| +// SYNTHETIC_DELAY_BEGIN("cc.Scheduler.BeginMainFrame"); |
| +// SYNTHETIC_DELAY_END("cc.Scheduler.BeginMainFrame"); |
| +// |
| +// Note that while the same delay can be applied in several threads |
| +// simultaneously, a single delay operation cannot begin on one thread and end |
| +// on another. |
| + |
| +#ifndef BASE_DEBUG_SYNTHETIC_DELAY_H_ |
| +#define BASE_DEBUG_SYNTHETIC_DELAY_H_ |
| + |
| +#include "base/atomicops.h" |
| +#include "base/synchronization/lock.h" |
| +#include "base/threading/thread_local.h" |
| +#include "base/time/time.h" |
| + |
| +#define INTERNAL_SYNTHETIC_DELAY_UID3(a, b) synthetic_delay_unique_##a##b |
| +#define INTERNAL_SYNTHETIC_DELAY_UID2(a, b) INTERNAL_SYNTHETIC_DELAY_UID3(a, b) |
| +#define INTERNAL_SYNTHETIC_DELAY_UID(name_prefix) \ |
| + INTERNAL_SYNTHETIC_DELAY_UID2(name_prefix, __LINE__) |
| + |
| +#define SYNTHETIC_DELAY(name) \ |
| + static base::subtle::AtomicWord INTERNAL_SYNTHETIC_DELAY_UID(impl_ptr) = 0; \ |
| + base::debug::ScopedSyntheticDelay INTERNAL_SYNTHETIC_DELAY_UID(delay)( \ |
| + name, &INTERNAL_SYNTHETIC_DELAY_UID(impl_ptr)); |
| + |
| +#define SYNTHETIC_DELAY_BEGIN(name) \ |
| + do { \ |
| + static base::subtle::AtomicWord impl_ptr = 0; \ |
| + base::debug::synthetic_delay_internal::GetOrCreateDelay(name, &impl_ptr) \ |
| + ->Begin(); \ |
| + } while (false) |
| + |
| +#define SYNTHETIC_DELAY_END(name) \ |
| + do { \ |
| + static base::subtle::AtomicWord impl_ptr = 0; \ |
| + base::debug::synthetic_delay_internal::GetOrCreateDelay(name, &impl_ptr) \ |
| + ->End(); \ |
| + } while (false) |
| + |
| +template <typename Type> |
| +struct DefaultSingletonTraits; |
| + |
| +namespace base { |
| +namespace debug { |
| + |
| +class SyntheticDelay { |
| + public: |
| + void SetTargetDuration(TimeDelta target_duration); |
| + void Begin(); |
| + void End(); |
| + |
| + private: |
| + SyntheticDelay(); |
| + friend class SyntheticDelayController; |
| + |
| + void Initialize(const char* name); |
| + |
| + struct ThreadState { |
| + base::TimeTicks start_time; |
| + }; |
| + |
| + Lock lock_; |
| + const char* name_; |
| + base::TimeDelta target_duration_; |
| + ThreadLocalPointer<ThreadState> thread_state_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(SyntheticDelay); |
| +}; |
| + |
| +class ScopedSyntheticDelay { |
| + public: |
| + explicit ScopedSyntheticDelay(const char* name, subtle::AtomicWord* impl_ptr); |
| + ~ScopedSyntheticDelay(); |
| + |
| + private: |
| + SyntheticDelay* delay_impl_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ScopedSyntheticDelay); |
| +}; |
| + |
| +const int kMaxSyntheticDelays = 32; |
| + |
| +class SyntheticDelayController { |
|
brianderson
2013/11/05 03:12:05
Seems like you could move this class into the impl
Sami
2013/11/22 18:29:13
I'll need access to GetOrCreateDelay() later confi
|
| + public: |
| + static SyntheticDelayController* GetInstance(); |
| + |
| + SyntheticDelay* GetOrCreateDelay(const char* name); |
| + |
| + private: |
| + SyntheticDelayController(); |
| + |
| + friend struct DefaultSingletonTraits<SyntheticDelayController>; |
| + |
| + Lock lock_; |
| + SyntheticDelay delays_[kMaxSyntheticDelays]; |
| + SyntheticDelay dummy_delay_; |
| + int delay_count_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(SyntheticDelayController); |
| +}; |
| + |
| +namespace synthetic_delay_internal { |
| + |
| +SyntheticDelay* GetOrCreateDelay(const char* name, |
| + subtle::AtomicWord* impl_ptr); |
| + |
| +} // namespace synthetic_delay_internal |
| +} // namespace debug |
| +} // namespace base |
| + |
| +#endif /* BASE_DEBUG_SYNTHETIC_DELAY_H_ */ |