]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/util/timer_test.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / util / timer_test.cc
CommitLineData
20effc67
TL
1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2// This source code is licensed under both the GPLv2 (found in the
3// COPYING file in the root directory) and Apache 2.0 License
4// (found in the LICENSE.Apache file in the root directory).
5
6#include "util/timer.h"
7
8#include "db/db_test_util.h"
9
10namespace ROCKSDB_NAMESPACE {
11
12class TimerTest : public testing::Test {
13 public:
14 TimerTest() : mock_env_(new MockTimeEnv(Env::Default())) {}
15
16 protected:
17 std::unique_ptr<MockTimeEnv> mock_env_;
18
19 void SetUp() override { mock_env_->InstallTimedWaitFixCallback(); }
20
21 const int kUsPerSec = 1000000;
22};
23
24TEST_F(TimerTest, SingleScheduleOnce) {
25 const int kInitDelayUs = 1 * kUsPerSec;
26 Timer timer(mock_env_.get());
27
28 int count = 0;
29 timer.Add([&] { count++; }, "fn_sch_test", kInitDelayUs, 0);
30
31 ASSERT_TRUE(timer.Start());
32
33 ASSERT_EQ(0, count);
34 // Wait for execution to finish
35 timer.TEST_WaitForRun(
36 [&] { mock_env_->MockSleepForMicroseconds(kInitDelayUs); });
37 ASSERT_EQ(1, count);
38
39 ASSERT_TRUE(timer.Shutdown());
40}
41
42TEST_F(TimerTest, MultipleScheduleOnce) {
43 const int kInitDelay1Us = 1 * kUsPerSec;
44 const int kInitDelay2Us = 3 * kUsPerSec;
45 Timer timer(mock_env_.get());
46
47 int count1 = 0;
48 timer.Add([&] { count1++; }, "fn_sch_test1", kInitDelay1Us, 0);
49
50 int count2 = 0;
51 timer.Add([&] { count2++; }, "fn_sch_test2", kInitDelay2Us, 0);
52
53 ASSERT_TRUE(timer.Start());
54 ASSERT_EQ(0, count1);
55 ASSERT_EQ(0, count2);
56
57 timer.TEST_WaitForRun(
58 [&] { mock_env_->MockSleepForMicroseconds(kInitDelay1Us); });
59
60 ASSERT_EQ(1, count1);
61 ASSERT_EQ(0, count2);
62
63 timer.TEST_WaitForRun([&] {
64 mock_env_->MockSleepForMicroseconds(kInitDelay2Us - kInitDelay1Us);
65 });
66
67 ASSERT_EQ(1, count1);
68 ASSERT_EQ(1, count2);
69
70 ASSERT_TRUE(timer.Shutdown());
71}
72
73TEST_F(TimerTest, SingleScheduleRepeatedly) {
74 const int kIterations = 5;
75 const int kInitDelayUs = 1 * kUsPerSec;
76 const int kRepeatUs = 1 * kUsPerSec;
77
78 Timer timer(mock_env_.get());
79 int count = 0;
80 timer.Add([&] { count++; }, "fn_sch_test", kInitDelayUs, kRepeatUs);
81
82 ASSERT_TRUE(timer.Start());
83 ASSERT_EQ(0, count);
84
85 timer.TEST_WaitForRun(
86 [&] { mock_env_->MockSleepForMicroseconds(kInitDelayUs); });
87
88 ASSERT_EQ(1, count);
89
90 // Wait for execution to finish
91 for (int i = 1; i < kIterations; i++) {
92 timer.TEST_WaitForRun(
93 [&] { mock_env_->MockSleepForMicroseconds(kRepeatUs); });
94 }
95 ASSERT_EQ(kIterations, count);
96
97 ASSERT_TRUE(timer.Shutdown());
98}
99
100TEST_F(TimerTest, MultipleScheduleRepeatedly) {
101 const int kIterations = 5;
102 const int kInitDelay1Us = 0 * kUsPerSec;
103 const int kInitDelay2Us = 1 * kUsPerSec;
104 const int kInitDelay3Us = 0 * kUsPerSec;
105 const int kRepeatUs = 2 * kUsPerSec;
106 const int kLargeRepeatUs = 100 * kUsPerSec;
107
108 Timer timer(mock_env_.get());
109
110 int count1 = 0;
111 timer.Add([&] { count1++; }, "fn_sch_test1", kInitDelay1Us, kRepeatUs);
112
113 int count2 = 0;
114 timer.Add([&] { count2++; }, "fn_sch_test2", kInitDelay2Us, kRepeatUs);
115
116 // Add a function with relatively large repeat interval
117 int count3 = 0;
118 timer.Add([&] { count3++; }, "fn_sch_test3", kInitDelay3Us, kLargeRepeatUs);
119
120 ASSERT_TRUE(timer.Start());
121
122 ASSERT_EQ(0, count2);
123 // Wait for execution to finish
124 for (int i = 1; i < kIterations * (kRepeatUs / kUsPerSec); i++) {
125 timer.TEST_WaitForRun(
126 [&] { mock_env_->MockSleepForMicroseconds(1 * kUsPerSec); });
127 ASSERT_EQ((i + 2) / (kRepeatUs / kUsPerSec), count1);
128 ASSERT_EQ((i + 1) / (kRepeatUs / kUsPerSec), count2);
129
130 // large interval function should only run once (the first one).
131 ASSERT_EQ(1, count3);
132 }
133
134 timer.Cancel("fn_sch_test1");
135
136 // Wait for execution to finish
137 timer.TEST_WaitForRun(
138 [&] { mock_env_->MockSleepForMicroseconds(1 * kUsPerSec); });
139 ASSERT_EQ(kIterations, count1);
140 ASSERT_EQ(kIterations, count2);
141 ASSERT_EQ(1, count3);
142
143 timer.Cancel("fn_sch_test2");
144
145 ASSERT_EQ(kIterations, count1);
146 ASSERT_EQ(kIterations, count2);
147
148 // execute the long interval one
149 timer.TEST_WaitForRun([&] {
150 mock_env_->MockSleepForMicroseconds(
151 kLargeRepeatUs - static_cast<int>(mock_env_->NowMicros()));
152 });
153 ASSERT_EQ(2, count3);
154
155 ASSERT_TRUE(timer.Shutdown());
156}
157
158TEST_F(TimerTest, AddAfterStartTest) {
159 const int kIterations = 5;
160 const int kInitDelayUs = 1 * kUsPerSec;
161 const int kRepeatUs = 1 * kUsPerSec;
162
163 // wait timer to run and then add a new job
164 SyncPoint::GetInstance()->LoadDependency(
165 {{"Timer::Run::Waiting", "TimerTest:AddAfterStartTest:1"}});
166 SyncPoint::GetInstance()->EnableProcessing();
167
168 Timer timer(mock_env_.get());
169
170 ASSERT_TRUE(timer.Start());
171
172 TEST_SYNC_POINT("TimerTest:AddAfterStartTest:1");
173 int count = 0;
174 timer.Add([&] { count++; }, "fn_sch_test", kInitDelayUs, kRepeatUs);
175 ASSERT_EQ(0, count);
176 // Wait for execution to finish
177 timer.TEST_WaitForRun(
178 [&] { mock_env_->MockSleepForMicroseconds(kInitDelayUs); });
179 ASSERT_EQ(1, count);
180
181 for (int i = 1; i < kIterations; i++) {
182 timer.TEST_WaitForRun(
183 [&] { mock_env_->MockSleepForMicroseconds(kRepeatUs); });
184 }
185 ASSERT_EQ(kIterations, count);
186
187 ASSERT_TRUE(timer.Shutdown());
188}
189
190TEST_F(TimerTest, CancelRunningTask) {
191 static constexpr char kTestFuncName[] = "test_func";
192 const int kRepeatUs = 1 * kUsPerSec;
193 Timer timer(mock_env_.get());
194 ASSERT_TRUE(timer.Start());
195 int* value = new int;
196 *value = 0;
197 SyncPoint::GetInstance()->DisableProcessing();
198 SyncPoint::GetInstance()->LoadDependency({
199 {"TimerTest::CancelRunningTask:test_func:0",
200 "TimerTest::CancelRunningTask:BeforeCancel"},
201 {"Timer::WaitForTaskCompleteIfNecessary:TaskExecuting",
202 "TimerTest::CancelRunningTask:test_func:1"},
203 });
204 SyncPoint::GetInstance()->EnableProcessing();
205 timer.Add(
206 [&]() {
207 *value = 1;
208 TEST_SYNC_POINT("TimerTest::CancelRunningTask:test_func:0");
209 TEST_SYNC_POINT("TimerTest::CancelRunningTask:test_func:1");
210 },
211 kTestFuncName, 0, kRepeatUs);
212 port::Thread control_thr([&]() {
213 TEST_SYNC_POINT("TimerTest::CancelRunningTask:BeforeCancel");
214 timer.Cancel(kTestFuncName);
215 // Verify that *value has been set to 1.
216 ASSERT_EQ(1, *value);
217 delete value;
218 value = nullptr;
219 });
220 mock_env_->MockSleepForMicroseconds(kRepeatUs);
221 control_thr.join();
222 ASSERT_TRUE(timer.Shutdown());
223}
224
225TEST_F(TimerTest, ShutdownRunningTask) {
226 const int kRepeatUs = 1 * kUsPerSec;
227 constexpr char kTestFunc1Name[] = "test_func1";
228 constexpr char kTestFunc2Name[] = "test_func2";
229 Timer timer(mock_env_.get());
230
231 SyncPoint::GetInstance()->DisableProcessing();
232 SyncPoint::GetInstance()->LoadDependency({
233 {"TimerTest::ShutdownRunningTest:test_func:0",
234 "TimerTest::ShutdownRunningTest:BeforeShutdown"},
235 {"Timer::WaitForTaskCompleteIfNecessary:TaskExecuting",
236 "TimerTest::ShutdownRunningTest:test_func:1"},
237 });
238 SyncPoint::GetInstance()->EnableProcessing();
239
240 ASSERT_TRUE(timer.Start());
241
242 int* value = new int;
243 *value = 0;
244 timer.Add(
245 [&]() {
246 TEST_SYNC_POINT("TimerTest::ShutdownRunningTest:test_func:0");
247 *value = 1;
248 TEST_SYNC_POINT("TimerTest::ShutdownRunningTest:test_func:1");
249 },
250 kTestFunc1Name, 0, kRepeatUs);
251
252 timer.Add([&]() { ++(*value); }, kTestFunc2Name, 0, kRepeatUs);
253
254 port::Thread control_thr([&]() {
255 TEST_SYNC_POINT("TimerTest::ShutdownRunningTest:BeforeShutdown");
256 timer.Shutdown();
257 });
258 mock_env_->MockSleepForMicroseconds(kRepeatUs);
259 control_thr.join();
260 delete value;
261}
262
263TEST_F(TimerTest, AddSameFuncName) {
264 const int kInitDelayUs = 1 * kUsPerSec;
265 const int kRepeat1Us = 5 * kUsPerSec;
266 const int kRepeat2Us = 4 * kUsPerSec;
267
268 Timer timer(mock_env_.get());
269 ASSERT_TRUE(timer.Start());
270
271 int func_counter1 = 0;
272 timer.Add([&] { func_counter1++; }, "duplicated_func", kInitDelayUs,
273 kRepeat1Us);
274
275 int func2_counter = 0;
276 timer.Add([&] { func2_counter++; }, "func2", kInitDelayUs, kRepeat2Us);
277
278 // New function with the same name should override the existing one
279 int func_counter2 = 0;
280 timer.Add([&] { func_counter2++; }, "duplicated_func", kInitDelayUs,
281 kRepeat1Us);
282
283 ASSERT_EQ(0, func_counter1);
284 ASSERT_EQ(0, func2_counter);
285 ASSERT_EQ(0, func_counter2);
286
287 timer.TEST_WaitForRun(
288 [&] { mock_env_->MockSleepForMicroseconds(kInitDelayUs); });
289
290 ASSERT_EQ(0, func_counter1);
291 ASSERT_EQ(1, func2_counter);
292 ASSERT_EQ(1, func_counter2);
293
294 timer.TEST_WaitForRun(
295 [&] { mock_env_->MockSleepForMicroseconds(kRepeat1Us); });
296
297 ASSERT_EQ(0, func_counter1);
298 ASSERT_EQ(2, func2_counter);
299 ASSERT_EQ(2, func_counter2);
300
301 ASSERT_TRUE(timer.Shutdown());
302}
303
304TEST_F(TimerTest, RepeatIntervalWithFuncRunningTime) {
305 const int kInitDelayUs = 1 * kUsPerSec;
306 const int kRepeatUs = 5 * kUsPerSec;
307 const int kFuncRunningTimeUs = 1 * kUsPerSec;
308
309 Timer timer(mock_env_.get());
310 ASSERT_TRUE(timer.Start());
311
312 int func_counter = 0;
313 timer.Add(
314 [&] {
315 mock_env_->MockSleepForMicroseconds(kFuncRunningTimeUs);
316 func_counter++;
317 },
318 "func", kInitDelayUs, kRepeatUs);
319
320 ASSERT_EQ(0, func_counter);
321 timer.TEST_WaitForRun(
322 [&] { mock_env_->MockSleepForMicroseconds(kInitDelayUs); });
323 ASSERT_EQ(1, func_counter);
324 ASSERT_EQ(kInitDelayUs + kFuncRunningTimeUs, mock_env_->NowMicros());
325
326 // After repeat interval time, the function is not executed, as running
327 // the function takes some time (`kFuncRunningTimeSec`). The repeat interval
328 // is the time between ending time of the last call and starting time of the
329 // next call.
330 uint64_t next_abs_interval_time_us = kInitDelayUs + kRepeatUs;
331 timer.TEST_WaitForRun([&] {
332 mock_env_->set_current_time(next_abs_interval_time_us / kUsPerSec);
333 });
334 ASSERT_EQ(1, func_counter);
335
336 // After the function running time, it's executed again
337 timer.TEST_WaitForRun(
338 [&] { mock_env_->MockSleepForMicroseconds(kFuncRunningTimeUs); });
339 ASSERT_EQ(2, func_counter);
340
341 ASSERT_TRUE(timer.Shutdown());
342}
343
344TEST_F(TimerTest, DestroyRunningTimer) {
345 const int kInitDelayUs = 1 * kUsPerSec;
346 const int kRepeatUs = 1 * kUsPerSec;
347
348 auto timer_ptr = new Timer(mock_env_.get());
349
350 int count = 0;
351 timer_ptr->Add([&] { count++; }, "fn_sch_test", kInitDelayUs, kRepeatUs);
352 ASSERT_TRUE(timer_ptr->Start());
353
354 timer_ptr->TEST_WaitForRun(
355 [&] { mock_env_->MockSleepForMicroseconds(kInitDelayUs); });
356
357 // delete a running timer should not cause any exception
358 delete timer_ptr;
359}
360
361TEST_F(TimerTest, DestroyTimerWithRunningFunc) {
362 const int kRepeatUs = 1 * kUsPerSec;
363 auto timer_ptr = new Timer(mock_env_.get());
364
365 SyncPoint::GetInstance()->DisableProcessing();
366 SyncPoint::GetInstance()->LoadDependency({
367 {"TimerTest::DestroyTimerWithRunningFunc:test_func:0",
368 "TimerTest::DestroyTimerWithRunningFunc:BeforeDelete"},
369 {"Timer::WaitForTaskCompleteIfNecessary:TaskExecuting",
370 "TimerTest::DestroyTimerWithRunningFunc:test_func:1"},
371 });
372 SyncPoint::GetInstance()->EnableProcessing();
373
374 ASSERT_TRUE(timer_ptr->Start());
375
376 int count = 0;
377 timer_ptr->Add(
378 [&]() {
379 TEST_SYNC_POINT("TimerTest::DestroyTimerWithRunningFunc:test_func:0");
380 count++;
381 TEST_SYNC_POINT("TimerTest::DestroyTimerWithRunningFunc:test_func:1");
382 },
383 "fn_running_test", 0, kRepeatUs);
384
385 port::Thread control_thr([&] {
386 TEST_SYNC_POINT("TimerTest::DestroyTimerWithRunningFunc:BeforeDelete");
387 delete timer_ptr;
388 });
389 mock_env_->MockSleepForMicroseconds(kRepeatUs);
390 control_thr.join();
391}
392
393} // namespace ROCKSDB_NAMESPACE
394
395int main(int argc, char** argv) {
396 ::testing::InitGoogleTest(&argc, argv);
397
398 return RUN_ALL_TESTS();
399}