Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/debug/synthetic_delay.h" | |
| 6 #include "base/debug/trace_event.h" | |
| 7 #include "base/memory/singleton.h" | |
| 8 #include "base/synchronization/lock.h" | |
| 9 #include "base/threading/platform_thread.h" | |
| 10 | |
| 11 namespace base { | |
| 12 namespace debug { | |
| 13 namespace synthetic_delay_internal { | |
| 14 | |
| 15 SyntheticDelay* GetOrCreateDelay(const char* name, | |
| 16 subtle::AtomicWord* impl_ptr) { | |
| 17 SyntheticDelay* delay_impl = | |
| 18 reinterpret_cast<SyntheticDelay*>(base::subtle::NoBarrier_Load(impl_ptr)); | |
| 19 if (!delay_impl) { | |
| 20 delay_impl = | |
| 21 SyntheticDelayController::GetInstance()->GetOrCreateDelay(name); | |
| 22 subtle::NoBarrier_Store(impl_ptr, | |
| 23 reinterpret_cast<subtle::AtomicWord>(delay_impl)); | |
| 24 } | |
| 25 return delay_impl; | |
| 26 } | |
| 27 | |
| 28 } // namespace synthetic_delay_internal | |
| 29 | |
| 30 ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, | |
| 31 subtle::AtomicWord* impl_ptr) | |
| 32 : delay_impl_(synthetic_delay_internal::GetOrCreateDelay(name, impl_ptr)) { | |
| 33 delay_impl_->Begin(); | |
| 34 } | |
| 35 | |
| 36 ScopedSyntheticDelay::~ScopedSyntheticDelay() { delay_impl_->End(); } | |
| 37 | |
| 38 SyntheticDelay::SyntheticDelay() : name_(NULL) {} | |
| 39 | |
| 40 void SyntheticDelay::Initialize(const char* name) { | |
| 41 AutoLock lock(lock_); | |
|
brianderson
2013/11/05 03:12:05
I don't think this lock is necessary, since it is
Sami
2013/11/22 18:29:13
True, removed.
| |
| 42 DCHECK(!thread_state_.Get()); | |
| 43 name_ = name; | |
| 44 } | |
| 45 | |
| 46 void SyntheticDelay::SetTargetDuration(base::TimeDelta target_duration) { | |
| 47 AutoLock lock(lock_); | |
| 48 target_duration_ = target_duration; | |
| 49 } | |
| 50 | |
| 51 void SyntheticDelay::Begin() { | |
| 52 // Note that we check for a non-zero target duration without locking to keep | |
| 53 // things quick for the common case when delays are disabled. Since the delay | |
| 54 // calculation is done with a lock held, it will always be correct. The only | |
| 55 // downside of this is that we may fail to apply some delays when the target | |
| 56 // duration changes. | |
| 57 if (!target_duration_.ToInternalValue()) | |
| 58 return; | |
| 59 | |
| 60 // Store the start time in a thread local struct so the same delay can be | |
| 61 // applied to multiple threads simultaneously. | |
| 62 DCHECK(!thread_state_.Get()); | |
| 63 scoped_ptr<ThreadState> thread_state(new ThreadState()); | |
|
brianderson
2013/11/05 03:12:05
Can you avoid allocating a new ThreadState for eve
Sami
2013/11/22 18:29:13
Right, the choice is between avoiding the repeated
| |
| 64 thread_state->start_time = base::TimeTicks::Now(); | |
| 65 thread_state_.Set(thread_state.release()); | |
| 66 } | |
| 67 | |
| 68 void SyntheticDelay::End() { | |
| 69 if (!target_duration_.ToInternalValue()) | |
| 70 return; | |
| 71 | |
| 72 DCHECK(thread_state_.Get()); | |
| 73 scoped_ptr<ThreadState> thread_state(thread_state_.Get()); | |
| 74 thread_state_.Set(NULL); | |
| 75 | |
| 76 AutoLock lock(lock_); | |
| 77 base::TimeTicks now = base::TimeTicks::Now(); | |
|
brianderson
2013/11/05 03:12:05
Can you use HighResNow? For the scheduling tests,
Sami
2013/11/22 18:29:13
Great point, changed.
| |
| 78 base::TimeDelta delay = target_duration_ - (now - thread_state->start_time); | |
|
brianderson
2013/11/05 03:12:05
I think you should be able to AutoLock just the li
Sami
2013/11/22 18:29:13
Done.
| |
| 79 if (delay.ToInternalValue() <= 0) | |
| 80 return; | |
| 81 | |
| 82 TRACE_EVENT0("synthetic_delay", name_); | |
| 83 { | |
| 84 AutoUnlock unlock(lock_); | |
| 85 PlatformThread::Sleep(delay); | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 SyntheticDelayController* SyntheticDelayController::GetInstance() { | |
| 90 return Singleton<SyntheticDelayController, | |
| 91 LeakySingletonTraits<SyntheticDelayController> >::get(); | |
|
brianderson
2013/11/05 03:12:05
What does LeakySingletonTraits do?
Sami
2013/11/22 18:29:13
It's for allocating a singleton class that gets le
| |
| 92 } | |
| 93 | |
| 94 SyntheticDelayController::SyntheticDelayController() : delay_count_(0) { | |
| 95 for (int i = 0; i < kMaxSyntheticDelays; ++i) { | |
| 96 ANNOTATE_BENIGN_RACE(&delays_[i].target_duration_, | |
|
brianderson
2013/11/05 03:12:05
What does ANNOTATE_BENIGN_RACE do?
Sami
2013/11/22 18:29:13
It's another hint for dynamic code analyzers -- mo
| |
| 97 "synthetic delay duration"); | |
| 98 } | |
| 99 } | |
| 100 | |
| 101 SyntheticDelay* SyntheticDelayController::GetOrCreateDelay(const char* name) { | |
| 102 AutoLock lock(lock_); | |
|
brianderson
2013/11/05 03:12:05
I think you can avoid taking this lock in the comm
Sami
2013/11/22 18:29:13
Great idea, done.
| |
| 103 for (int i = 0; i < delay_count_; ++i) { | |
| 104 if (!strcmp(name, delays_[i].name_)) | |
| 105 return &delays_[i]; | |
| 106 } | |
| 107 | |
| 108 DCHECK(delay_count_ < kMaxSyntheticDelays) | |
| 109 << "must increase kMaxSyntheticDelays"; | |
| 110 if (delay_count_ >= kMaxSyntheticDelays) | |
| 111 return &dummy_delay_; | |
| 112 | |
| 113 delays_[delay_count_].Initialize(name); | |
| 114 return &delays_[delay_count_++]; | |
| 115 } | |
| 116 | |
| 117 } // namespace debug | |
| 118 } // namespace base | |
| OLD | NEW |