timer_test.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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. #include "util/timer.h"
  6. #include "db/db_test_util.h"
  7. #include "rocksdb/file_system.h"
  8. #include "test_util/mock_time_env.h"
  9. namespace ROCKSDB_NAMESPACE {
  10. class TimerTest : public testing::Test {
  11. public:
  12. TimerTest()
  13. : mock_clock_(std::make_shared<MockSystemClock>(SystemClock::Default())) {
  14. }
  15. protected:
  16. std::shared_ptr<MockSystemClock> mock_clock_;
  17. void SetUp() override { mock_clock_->InstallTimedWaitFixCallback(); }
  18. const int kUsPerSec = 1000000;
  19. };
  20. TEST_F(TimerTest, SingleScheduleOnce) {
  21. const int kInitDelayUs = 1 * kUsPerSec;
  22. Timer timer(mock_clock_.get());
  23. int count = 0;
  24. timer.Add([&] { count++; }, "fn_sch_test", kInitDelayUs, 0);
  25. ASSERT_TRUE(timer.Start());
  26. ASSERT_EQ(0, count);
  27. // Wait for execution to finish
  28. timer.TEST_WaitForRun(
  29. [&] { mock_clock_->SleepForMicroseconds(kInitDelayUs); });
  30. ASSERT_EQ(1, count);
  31. ASSERT_TRUE(timer.Shutdown());
  32. }
  33. TEST_F(TimerTest, MultipleScheduleOnce) {
  34. const int kInitDelay1Us = 1 * kUsPerSec;
  35. const int kInitDelay2Us = 3 * kUsPerSec;
  36. Timer timer(mock_clock_.get());
  37. int count1 = 0;
  38. timer.Add([&] { count1++; }, "fn_sch_test1", kInitDelay1Us, 0);
  39. int count2 = 0;
  40. timer.Add([&] { count2++; }, "fn_sch_test2", kInitDelay2Us, 0);
  41. ASSERT_TRUE(timer.Start());
  42. ASSERT_EQ(0, count1);
  43. ASSERT_EQ(0, count2);
  44. timer.TEST_WaitForRun(
  45. [&] { mock_clock_->SleepForMicroseconds(kInitDelay1Us); });
  46. ASSERT_EQ(1, count1);
  47. ASSERT_EQ(0, count2);
  48. timer.TEST_WaitForRun([&] {
  49. mock_clock_->SleepForMicroseconds(kInitDelay2Us - kInitDelay1Us);
  50. });
  51. ASSERT_EQ(1, count1);
  52. ASSERT_EQ(1, count2);
  53. ASSERT_TRUE(timer.Shutdown());
  54. }
  55. TEST_F(TimerTest, SingleScheduleRepeatedly) {
  56. const int kIterations = 5;
  57. const int kInitDelayUs = 1 * kUsPerSec;
  58. const int kRepeatUs = 1 * kUsPerSec;
  59. Timer timer(mock_clock_.get());
  60. int count = 0;
  61. timer.Add([&] { count++; }, "fn_sch_test", kInitDelayUs, kRepeatUs);
  62. ASSERT_TRUE(timer.Start());
  63. ASSERT_EQ(0, count);
  64. timer.TEST_WaitForRun(
  65. [&] { mock_clock_->SleepForMicroseconds(kInitDelayUs); });
  66. ASSERT_EQ(1, count);
  67. // Wait for execution to finish
  68. for (int i = 1; i < kIterations; i++) {
  69. timer.TEST_WaitForRun(
  70. [&] { mock_clock_->SleepForMicroseconds(kRepeatUs); });
  71. }
  72. ASSERT_EQ(kIterations, count);
  73. ASSERT_TRUE(timer.Shutdown());
  74. }
  75. TEST_F(TimerTest, MultipleScheduleRepeatedly) {
  76. const int kIterations = 5;
  77. const int kInitDelay1Us = 0 * kUsPerSec;
  78. const int kInitDelay2Us = 1 * kUsPerSec;
  79. const int kInitDelay3Us = 0 * kUsPerSec;
  80. const int kRepeatUs = 2 * kUsPerSec;
  81. const int kLargeRepeatUs = 100 * kUsPerSec;
  82. Timer timer(mock_clock_.get());
  83. int count1 = 0;
  84. timer.Add([&] { count1++; }, "fn_sch_test1", kInitDelay1Us, kRepeatUs);
  85. int count2 = 0;
  86. timer.Add([&] { count2++; }, "fn_sch_test2", kInitDelay2Us, kRepeatUs);
  87. // Add a function with relatively large repeat interval
  88. int count3 = 0;
  89. timer.Add([&] { count3++; }, "fn_sch_test3", kInitDelay3Us, kLargeRepeatUs);
  90. ASSERT_TRUE(timer.Start());
  91. ASSERT_EQ(0, count2);
  92. // Wait for execution to finish
  93. for (int i = 1; i < kIterations * (kRepeatUs / kUsPerSec); i++) {
  94. timer.TEST_WaitForRun(
  95. [&] { mock_clock_->SleepForMicroseconds(1 * kUsPerSec); });
  96. ASSERT_EQ((i + 2) / (kRepeatUs / kUsPerSec), count1);
  97. ASSERT_EQ((i + 1) / (kRepeatUs / kUsPerSec), count2);
  98. // large interval function should only run once (the first one).
  99. ASSERT_EQ(1, count3);
  100. }
  101. timer.Cancel("fn_sch_test1");
  102. // Wait for execution to finish
  103. timer.TEST_WaitForRun(
  104. [&] { mock_clock_->SleepForMicroseconds(1 * kUsPerSec); });
  105. ASSERT_EQ(kIterations, count1);
  106. ASSERT_EQ(kIterations, count2);
  107. ASSERT_EQ(1, count3);
  108. timer.Cancel("fn_sch_test2");
  109. ASSERT_EQ(kIterations, count1);
  110. ASSERT_EQ(kIterations, count2);
  111. // execute the long interval one
  112. timer.TEST_WaitForRun([&] {
  113. mock_clock_->SleepForMicroseconds(
  114. kLargeRepeatUs - static_cast<int>(mock_clock_->NowMicros()));
  115. });
  116. ASSERT_EQ(2, count3);
  117. ASSERT_TRUE(timer.Shutdown());
  118. }
  119. TEST_F(TimerTest, AddAfterStartTest) {
  120. const int kIterations = 5;
  121. const int kInitDelayUs = 1 * kUsPerSec;
  122. const int kRepeatUs = 1 * kUsPerSec;
  123. // wait timer to run and then add a new job
  124. SyncPoint::GetInstance()->LoadDependency(
  125. {{"Timer::Run::Waiting", "TimerTest:AddAfterStartTest:1"}});
  126. SyncPoint::GetInstance()->EnableProcessing();
  127. Timer timer(mock_clock_.get());
  128. ASSERT_TRUE(timer.Start());
  129. TEST_SYNC_POINT("TimerTest:AddAfterStartTest:1");
  130. int count = 0;
  131. timer.Add([&] { count++; }, "fn_sch_test", kInitDelayUs, kRepeatUs);
  132. ASSERT_EQ(0, count);
  133. // Wait for execution to finish
  134. timer.TEST_WaitForRun(
  135. [&] { mock_clock_->SleepForMicroseconds(kInitDelayUs); });
  136. ASSERT_EQ(1, count);
  137. for (int i = 1; i < kIterations; i++) {
  138. timer.TEST_WaitForRun(
  139. [&] { mock_clock_->SleepForMicroseconds(kRepeatUs); });
  140. }
  141. ASSERT_EQ(kIterations, count);
  142. ASSERT_TRUE(timer.Shutdown());
  143. }
  144. TEST_F(TimerTest, CancelRunningTask) {
  145. static constexpr char kTestFuncName[] = "test_func";
  146. const int kRepeatUs = 1 * kUsPerSec;
  147. Timer timer(mock_clock_.get());
  148. ASSERT_TRUE(timer.Start());
  149. int* value = new int;
  150. *value = 0;
  151. SyncPoint::GetInstance()->DisableProcessing();
  152. SyncPoint::GetInstance()->LoadDependency({
  153. {"TimerTest::CancelRunningTask:test_func:0",
  154. "TimerTest::CancelRunningTask:BeforeCancel"},
  155. {"Timer::WaitForTaskCompleteIfNecessary:TaskExecuting",
  156. "TimerTest::CancelRunningTask:test_func:1"},
  157. });
  158. SyncPoint::GetInstance()->EnableProcessing();
  159. timer.Add(
  160. [&]() {
  161. *value = 1;
  162. TEST_SYNC_POINT("TimerTest::CancelRunningTask:test_func:0");
  163. TEST_SYNC_POINT("TimerTest::CancelRunningTask:test_func:1");
  164. },
  165. kTestFuncName, 0, kRepeatUs);
  166. port::Thread control_thr([&]() {
  167. TEST_SYNC_POINT("TimerTest::CancelRunningTask:BeforeCancel");
  168. timer.Cancel(kTestFuncName);
  169. // Verify that *value has been set to 1.
  170. ASSERT_EQ(1, *value);
  171. delete value;
  172. value = nullptr;
  173. });
  174. mock_clock_->SleepForMicroseconds(kRepeatUs);
  175. control_thr.join();
  176. ASSERT_TRUE(timer.Shutdown());
  177. }
  178. TEST_F(TimerTest, ShutdownRunningTask) {
  179. const int kRepeatUs = 1 * kUsPerSec;
  180. constexpr char kTestFunc1Name[] = "test_func1";
  181. constexpr char kTestFunc2Name[] = "test_func2";
  182. Timer timer(mock_clock_.get());
  183. SyncPoint::GetInstance()->DisableProcessing();
  184. SyncPoint::GetInstance()->LoadDependency({
  185. {"TimerTest::ShutdownRunningTest:test_func:0",
  186. "TimerTest::ShutdownRunningTest:BeforeShutdown"},
  187. {"Timer::WaitForTaskCompleteIfNecessary:TaskExecuting",
  188. "TimerTest::ShutdownRunningTest:test_func:1"},
  189. });
  190. SyncPoint::GetInstance()->EnableProcessing();
  191. ASSERT_TRUE(timer.Start());
  192. int* value = new int;
  193. *value = 0;
  194. timer.Add(
  195. [&]() {
  196. TEST_SYNC_POINT("TimerTest::ShutdownRunningTest:test_func:0");
  197. *value = 1;
  198. TEST_SYNC_POINT("TimerTest::ShutdownRunningTest:test_func:1");
  199. },
  200. kTestFunc1Name, 0, kRepeatUs);
  201. timer.Add([&]() { ++(*value); }, kTestFunc2Name, 0, kRepeatUs);
  202. port::Thread control_thr([&]() {
  203. TEST_SYNC_POINT("TimerTest::ShutdownRunningTest:BeforeShutdown");
  204. timer.Shutdown();
  205. });
  206. mock_clock_->SleepForMicroseconds(kRepeatUs);
  207. control_thr.join();
  208. delete value;
  209. }
  210. TEST_F(TimerTest, AddSameFuncName) {
  211. const int kInitDelayUs = 1 * kUsPerSec;
  212. const int kRepeat1Us = 5 * kUsPerSec;
  213. const int kRepeat2Us = 4 * kUsPerSec;
  214. Timer timer(mock_clock_.get());
  215. ASSERT_TRUE(timer.Start());
  216. int func_counter1 = 0;
  217. ASSERT_TRUE(timer.Add([&] { func_counter1++; }, "duplicated_func",
  218. kInitDelayUs, kRepeat1Us));
  219. int func2_counter = 0;
  220. ASSERT_TRUE(
  221. timer.Add([&] { func2_counter++; }, "func2", kInitDelayUs, kRepeat2Us));
  222. // New function with the same name should fail to add
  223. int func_counter2 = 0;
  224. ASSERT_FALSE(timer.Add([&] { func_counter2++; }, "duplicated_func",
  225. kInitDelayUs, kRepeat1Us));
  226. ASSERT_EQ(0, func_counter1);
  227. ASSERT_EQ(0, func2_counter);
  228. timer.TEST_WaitForRun(
  229. [&] { mock_clock_->SleepForMicroseconds(kInitDelayUs); });
  230. ASSERT_EQ(1, func_counter1);
  231. ASSERT_EQ(1, func2_counter);
  232. timer.TEST_WaitForRun([&] { mock_clock_->SleepForMicroseconds(kRepeat1Us); });
  233. ASSERT_EQ(2, func_counter1);
  234. ASSERT_EQ(2, func2_counter);
  235. ASSERT_EQ(0, func_counter2);
  236. ASSERT_TRUE(timer.Shutdown());
  237. }
  238. TEST_F(TimerTest, RepeatIntervalWithFuncRunningTime) {
  239. const int kInitDelayUs = 1 * kUsPerSec;
  240. const int kRepeatUs = 5 * kUsPerSec;
  241. const int kFuncRunningTimeUs = 1 * kUsPerSec;
  242. Timer timer(mock_clock_.get());
  243. ASSERT_TRUE(timer.Start());
  244. int func_counter = 0;
  245. timer.Add(
  246. [&] {
  247. mock_clock_->SleepForMicroseconds(kFuncRunningTimeUs);
  248. func_counter++;
  249. },
  250. "func", kInitDelayUs, kRepeatUs);
  251. ASSERT_EQ(0, func_counter);
  252. timer.TEST_WaitForRun(
  253. [&] { mock_clock_->SleepForMicroseconds(kInitDelayUs); });
  254. ASSERT_EQ(1, func_counter);
  255. ASSERT_EQ(kInitDelayUs + kFuncRunningTimeUs, mock_clock_->NowMicros());
  256. // After repeat interval time, the function is not executed, as running
  257. // the function takes some time (`kFuncRunningTimeSec`). The repeat interval
  258. // is the time between ending time of the last call and starting time of the
  259. // next call.
  260. uint64_t next_abs_interval_time_us = kInitDelayUs + kRepeatUs;
  261. timer.TEST_WaitForRun([&] {
  262. mock_clock_->SetCurrentTime(next_abs_interval_time_us / kUsPerSec);
  263. });
  264. ASSERT_EQ(1, func_counter);
  265. // After the function running time, it's executed again
  266. timer.TEST_WaitForRun(
  267. [&] { mock_clock_->SleepForMicroseconds(kFuncRunningTimeUs); });
  268. ASSERT_EQ(2, func_counter);
  269. ASSERT_TRUE(timer.Shutdown());
  270. }
  271. TEST_F(TimerTest, DestroyRunningTimer) {
  272. const int kInitDelayUs = 1 * kUsPerSec;
  273. const int kRepeatUs = 1 * kUsPerSec;
  274. auto timer_ptr = new Timer(mock_clock_.get());
  275. int count = 0;
  276. timer_ptr->Add([&] { count++; }, "fn_sch_test", kInitDelayUs, kRepeatUs);
  277. ASSERT_TRUE(timer_ptr->Start());
  278. timer_ptr->TEST_WaitForRun(
  279. [&] { mock_clock_->SleepForMicroseconds(kInitDelayUs); });
  280. // delete a running timer should not cause any exception
  281. delete timer_ptr;
  282. }
  283. TEST_F(TimerTest, DestroyTimerWithRunningFunc) {
  284. const int kRepeatUs = 1 * kUsPerSec;
  285. auto timer_ptr = new Timer(mock_clock_.get());
  286. SyncPoint::GetInstance()->DisableProcessing();
  287. SyncPoint::GetInstance()->LoadDependency({
  288. {"TimerTest::DestroyTimerWithRunningFunc:test_func:0",
  289. "TimerTest::DestroyTimerWithRunningFunc:BeforeDelete"},
  290. {"Timer::WaitForTaskCompleteIfNecessary:TaskExecuting",
  291. "TimerTest::DestroyTimerWithRunningFunc:test_func:1"},
  292. });
  293. SyncPoint::GetInstance()->EnableProcessing();
  294. ASSERT_TRUE(timer_ptr->Start());
  295. int count = 0;
  296. timer_ptr->Add(
  297. [&]() {
  298. TEST_SYNC_POINT("TimerTest::DestroyTimerWithRunningFunc:test_func:0");
  299. count++;
  300. TEST_SYNC_POINT("TimerTest::DestroyTimerWithRunningFunc:test_func:1");
  301. },
  302. "fn_running_test", 0, kRepeatUs);
  303. port::Thread control_thr([&] {
  304. TEST_SYNC_POINT("TimerTest::DestroyTimerWithRunningFunc:BeforeDelete");
  305. delete timer_ptr;
  306. });
  307. mock_clock_->SleepForMicroseconds(kRepeatUs);
  308. control_thr.join();
  309. }
  310. } // namespace ROCKSDB_NAMESPACE
  311. int main(int argc, char** argv) {
  312. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  313. ::testing::InitGoogleTest(&argc, argv);
  314. return RUN_ALL_TESTS();
  315. }