/Users/deen/code/yugabyte-db/src/yb/util/debug/trace_event_synthetic_delay.cc
Line | Count | Source (jump to first uncovered line) |
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. |
4 | | // |
5 | | // The following only applies to changes made to this file as part of YugaByte development. |
6 | | // |
7 | | // Portions Copyright (c) YugaByte, Inc. |
8 | | // |
9 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
10 | | // in compliance with the License. You may obtain a copy of the License at |
11 | | // |
12 | | // http://www.apache.org/licenses/LICENSE-2.0 |
13 | | // |
14 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
15 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
16 | | // or implied. See the License for the specific language governing permissions and limitations |
17 | | // under the License. |
18 | | // |
19 | | |
20 | | #include "yb/util/debug/trace_event_synthetic_delay.h" |
21 | | |
22 | | #include "yb/gutil/singleton.h" |
23 | | |
24 | | namespace { |
25 | | const int kMaxSyntheticDelays = 32; |
26 | | } // namespace |
27 | | |
28 | | namespace yb { |
29 | | namespace debug { |
30 | | |
31 | 35 | TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {} |
32 | 10 | TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {} |
33 | | |
34 | | class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock { |
35 | | public: |
36 | | static TraceEventSyntheticDelayRegistry* GetInstance(); |
37 | | |
38 | | TraceEventSyntheticDelay* GetOrCreateDelay(const char* name); |
39 | | void ResetAllDelays(); |
40 | | |
41 | | // TraceEventSyntheticDelayClock implementation. |
42 | | MonoTime Now() override; |
43 | | |
44 | | private: |
45 | | TraceEventSyntheticDelayRegistry(); |
46 | | |
47 | | friend class Singleton<TraceEventSyntheticDelayRegistry>; |
48 | | |
49 | | Mutex lock_; |
50 | | TraceEventSyntheticDelay delays_[kMaxSyntheticDelays]; |
51 | | TraceEventSyntheticDelay dummy_delay_; |
52 | | base::subtle::Atomic32 delay_count_; |
53 | | |
54 | | DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry); |
55 | | }; |
56 | | |
57 | | TraceEventSyntheticDelay::TraceEventSyntheticDelay() |
58 | 825 | : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(nullptr) {} |
59 | | |
60 | 0 | TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {} |
61 | | |
62 | | TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup( |
63 | 10 | const std::string& name) { |
64 | 10 | return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay( |
65 | 10 | name.c_str()); |
66 | 10 | } |
67 | | |
68 | | void TraceEventSyntheticDelay::Initialize( |
69 | | const std::string& name, |
70 | 10 | TraceEventSyntheticDelayClock* clock) { |
71 | 10 | name_ = name; |
72 | 10 | clock_ = clock; |
73 | 10 | } |
74 | | |
75 | 22 | void TraceEventSyntheticDelay::SetTargetDuration(const MonoDelta& target_duration) { |
76 | 22 | MutexLock lock(lock_); |
77 | 22 | target_duration_ = target_duration; |
78 | 22 | trigger_count_ = 0; |
79 | 22 | begin_count_ = 0; |
80 | 22 | } |
81 | | |
82 | 3 | void TraceEventSyntheticDelay::SetMode(Mode mode) { |
83 | 3 | MutexLock lock(lock_); |
84 | 3 | mode_ = mode; |
85 | 3 | } |
86 | | |
87 | 21 | void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) { |
88 | 21 | MutexLock lock(lock_); |
89 | 21 | clock_ = clock; |
90 | 21 | } |
91 | | |
92 | 6 | void TraceEventSyntheticDelay::Begin() { |
93 | | // Note that we check for a non-zero target duration without locking to keep |
94 | | // things quick for the common case when delays are disabled. Since the delay |
95 | | // calculation is done with a lock held, it will always be correct. The only |
96 | | // downside of this is that we may fail to apply some delays when the target |
97 | | // duration changes. |
98 | 6 | ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
99 | 6 | if (!target_duration_.Initialized()) |
100 | 0 | return; |
101 | | |
102 | 6 | MonoTime start_time = clock_->Now(); |
103 | 6 | { |
104 | 6 | MutexLock lock(lock_); |
105 | 6 | if (++begin_count_ != 1) |
106 | 1 | return; |
107 | 5 | end_time_ = CalculateEndTimeLocked(start_time); |
108 | 5 | } |
109 | 5 | } |
110 | | |
111 | 11 | void TraceEventSyntheticDelay::BeginParallel(MonoTime* out_end_time) { |
112 | | // See note in Begin(). |
113 | 11 | ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
114 | 11 | if (!target_duration_.Initialized()) { |
115 | 1 | *out_end_time = MonoTime(); |
116 | 1 | return; |
117 | 1 | } |
118 | | |
119 | 10 | MonoTime start_time = clock_->Now(); |
120 | 10 | { |
121 | 10 | MutexLock lock(lock_); |
122 | 10 | *out_end_time = CalculateEndTimeLocked(start_time); |
123 | 10 | } |
124 | 10 | } |
125 | | |
126 | 8 | void TraceEventSyntheticDelay::End() { |
127 | | // See note in Begin(). |
128 | 8 | ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration"); |
129 | 8 | if (!target_duration_.Initialized()) |
130 | 0 | return; |
131 | | |
132 | 8 | MonoTime end_time; |
133 | 8 | { |
134 | 8 | MutexLock lock(lock_); |
135 | 8 | if (!begin_count_ || --begin_count_ != 06 ) |
136 | 3 | return; |
137 | 5 | end_time = end_time_; |
138 | 5 | } |
139 | 5 | if (end_time.Initialized()) |
140 | 5 | ApplyDelay(end_time); |
141 | 5 | } |
142 | | |
143 | 11 | void TraceEventSyntheticDelay::EndParallel(const MonoTime& end_time) { |
144 | 11 | if (end_time.Initialized()) |
145 | 7 | ApplyDelay(end_time); |
146 | 11 | } |
147 | | |
148 | | MonoTime TraceEventSyntheticDelay::CalculateEndTimeLocked( |
149 | 15 | const MonoTime& start_time) { |
150 | 15 | if (mode_ == ONE_SHOT && trigger_count_++3 ) |
151 | 1 | return MonoTime(); |
152 | 14 | else if (mode_ == ALTERNATING && trigger_count_++ % 24 ) |
153 | 2 | return MonoTime(); |
154 | 12 | MonoTime end = start_time; |
155 | 12 | end.AddDelta(target_duration_); |
156 | 12 | return end; |
157 | 15 | } |
158 | | |
159 | 12 | void TraceEventSyntheticDelay::ApplyDelay(const MonoTime& end_time) { |
160 | 12 | TRACE_EVENT0("synthetic_delay", name_.c_str()); |
161 | 988 | while (clock_->Now().ComesBefore(end_time)) { |
162 | | // Busy loop. |
163 | 976 | } |
164 | 12 | } |
165 | | |
166 | | TraceEventSyntheticDelayRegistry* |
167 | 52 | TraceEventSyntheticDelayRegistry::GetInstance() { |
168 | 52 | return Singleton<TraceEventSyntheticDelayRegistry>::get(); |
169 | 52 | } |
170 | | |
171 | | TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry() |
172 | 25 | : delay_count_(0) {} |
173 | | |
174 | | TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay( |
175 | 23 | const char* name) { |
176 | | // Try to find an existing delay first without locking to make the common case |
177 | | // fast. |
178 | 23 | int delay_count = base::subtle::Acquire_Load(&delay_count_); |
179 | 23 | for (int i = 0; i < delay_count; ++i0 ) { |
180 | 13 | if (!strcmp(name, delays_[i].name_.c_str())) |
181 | 13 | return &delays_[i]; |
182 | 13 | } |
183 | | |
184 | 10 | MutexLock lock(lock_); |
185 | 10 | delay_count = base::subtle::Acquire_Load(&delay_count_); |
186 | 10 | for (int i = 0; i < delay_count; ++i0 ) { |
187 | 0 | if (!strcmp(name, delays_[i].name_.c_str())) |
188 | 0 | return &delays_[i]; |
189 | 0 | } |
190 | | |
191 | 10 | DCHECK(delay_count < kMaxSyntheticDelays) |
192 | 0 | << "must increase kMaxSyntheticDelays"; |
193 | 10 | if (delay_count >= kMaxSyntheticDelays) |
194 | 0 | return &dummy_delay_; |
195 | | |
196 | 10 | delays_[delay_count].Initialize(std::string(name), this); |
197 | 10 | base::subtle::Release_Store(&delay_count_, delay_count + 1); |
198 | 10 | return &delays_[delay_count]; |
199 | 10 | } |
200 | | |
201 | 0 | MonoTime TraceEventSyntheticDelayRegistry::Now() { |
202 | 0 | return MonoTime::Now(); |
203 | 0 | } |
204 | | |
205 | 29 | void TraceEventSyntheticDelayRegistry::ResetAllDelays() { |
206 | 29 | MutexLock lock(lock_); |
207 | 29 | int delay_count = base::subtle::Acquire_Load(&delay_count_); |
208 | 40 | for (int i = 0; i < delay_count; ++i11 ) { |
209 | 11 | delays_[i].SetTargetDuration(MonoDelta()); |
210 | 11 | delays_[i].SetClock(this); |
211 | 11 | } |
212 | 29 | } |
213 | | |
214 | 29 | void ResetTraceEventSyntheticDelays() { |
215 | 29 | TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays(); |
216 | 29 | } |
217 | | |
218 | | } // namespace debug |
219 | | } // namespace yb |
220 | | |
221 | | namespace trace_event_internal { |
222 | | |
223 | | ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name, |
224 | | AtomicWord* impl_ptr) |
225 | 9 | : delay_impl_(GetOrCreateDelay(name, impl_ptr)) { |
226 | 9 | delay_impl_->BeginParallel(&end_time_); |
227 | 9 | } |
228 | | |
229 | 9 | ScopedSyntheticDelay::~ScopedSyntheticDelay() { |
230 | 9 | delay_impl_->EndParallel(end_time_); |
231 | 9 | } |
232 | | |
233 | | yb::debug::TraceEventSyntheticDelay* GetOrCreateDelay( |
234 | | const char* name, |
235 | 23 | AtomicWord* impl_ptr) { |
236 | 23 | yb::debug::TraceEventSyntheticDelay* delay_impl = |
237 | 23 | reinterpret_cast<yb::debug::TraceEventSyntheticDelay*>( |
238 | 23 | base::subtle::Acquire_Load(impl_ptr)); |
239 | 23 | if (!delay_impl) { |
240 | 13 | delay_impl = yb::debug::TraceEventSyntheticDelayRegistry::GetInstance() |
241 | 13 | ->GetOrCreateDelay(name); |
242 | 13 | base::subtle::Release_Store( |
243 | 13 | impl_ptr, reinterpret_cast<AtomicWord>(delay_impl)); |
244 | 13 | } |
245 | 23 | return delay_impl; |
246 | 23 | } |
247 | | |
248 | | } // namespace trace_event_internal |