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 |