bvar_lock_timer_unittest.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Licensed to the Apache Software Foundation (ASF) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. // Date: 2015/03/06 18:34:03
  18. #include <iostream>
  19. #if __cplusplus >= 201103L
  20. #include <condition_variable>
  21. #endif
  22. #include <gtest/gtest.h>
  23. #include "butil/gperftools_profiler.h"
  24. #include "bvar/utils/lock_timer.h"
  25. namespace {
  26. struct DummyMutex {};
  27. }
  28. namespace std {
  29. template <>
  30. class lock_guard<DummyMutex> {
  31. public:
  32. lock_guard(DummyMutex&) {}
  33. };
  34. template <>
  35. class unique_lock<DummyMutex> {
  36. public:
  37. unique_lock() {}
  38. unique_lock(DummyMutex&) {}
  39. template <typename T>
  40. unique_lock(DummyMutex&, T) {}
  41. bool try_lock() { return true; }
  42. void lock() {}
  43. void unlock() {}
  44. };
  45. } // namespace std
  46. namespace {
  47. using bvar::IntRecorder;
  48. using bvar::LatencyRecorder;
  49. using bvar::utils::MutexWithRecorder;
  50. using bvar::utils::MutexWithLatencyRecorder;
  51. class LockTimerTest : public testing::Test {
  52. };
  53. #if __cplusplus >= 201103L
  54. TEST_F(LockTimerTest, MutexWithRecorder) {
  55. IntRecorder recorder;
  56. MutexWithRecorder<std::mutex> mutex(recorder);
  57. {
  58. BAIDU_SCOPED_LOCK(mutex);
  59. }
  60. ASSERT_EQ(1u, recorder.get_value().num);
  61. LOG(INFO) << recorder;
  62. {
  63. std::unique_lock<decltype(mutex) > lck(mutex);
  64. lck.unlock();
  65. lck.lock();
  66. ASSERT_EQ(2u, recorder.get_value().num);
  67. LOG(INFO) << recorder;
  68. std::condition_variable cond;
  69. cond.wait_for(lck, std::chrono::milliseconds(10));
  70. }
  71. ASSERT_EQ(3u, recorder.get_value().num);
  72. }
  73. TEST_F(LockTimerTest, MutexWithLatencyRecorder) {
  74. LatencyRecorder recorder(10);
  75. MutexWithLatencyRecorder<std::mutex> mutex(recorder);
  76. {
  77. BAIDU_SCOPED_LOCK(mutex);
  78. }
  79. ASSERT_EQ(1u, recorder.count());
  80. {
  81. std::unique_lock<decltype(mutex) > lck(mutex);
  82. lck.unlock();
  83. lck.lock();
  84. ASSERT_EQ(2u, recorder.count());
  85. LOG(INFO) << recorder;
  86. std::condition_variable cond;
  87. cond.wait_for(lck, std::chrono::milliseconds(10));
  88. }
  89. ASSERT_EQ(3u, recorder.count());
  90. }
  91. #endif
  92. TEST_F(LockTimerTest, pthread_mutex_and_cond) {
  93. LatencyRecorder recorder(10);
  94. MutexWithLatencyRecorder<pthread_mutex_t> mutex(recorder);
  95. {
  96. BAIDU_SCOPED_LOCK(mutex);
  97. }
  98. ASSERT_EQ(1u, recorder.count());
  99. {
  100. std::unique_lock<MutexWithLatencyRecorder<pthread_mutex_t> > lck(mutex);
  101. ASSERT_EQ(1u, recorder.count());
  102. timespec due_time = butil::milliseconds_from_now(10);
  103. pthread_cond_t cond;
  104. ASSERT_EQ(0, pthread_cond_init(&cond, NULL));
  105. pthread_cond_timedwait(&cond, &(pthread_mutex_t&)mutex, &due_time);
  106. pthread_cond_timedwait(&cond, &mutex.mutex(), &due_time);
  107. ASSERT_EQ(0, pthread_cond_destroy(&cond));
  108. }
  109. ASSERT_EQ(2u, recorder.count());
  110. }
  111. const static size_t OPS_PER_THREAD = 1000;
  112. template <typename M>
  113. void *signal_lock_thread(void *arg) {
  114. M *m = (M*)arg;
  115. for (size_t i = 0; i < OPS_PER_THREAD; ++i) {
  116. {
  117. std::unique_lock<M> lck(*m);
  118. usleep(10);
  119. }
  120. }
  121. return NULL;
  122. }
  123. TEST_F(LockTimerTest, signal_lock_time) {
  124. IntRecorder r0;
  125. MutexWithRecorder<pthread_mutex_t> m0(r0);
  126. pthread_t threads[4];
  127. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  128. ASSERT_EQ(0, pthread_create(&threads[i], NULL,
  129. signal_lock_thread<MutexWithRecorder<pthread_mutex_t> >, &m0));
  130. }
  131. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  132. pthread_join(threads[i], NULL);
  133. }
  134. LOG(INFO) << r0;
  135. ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r0.get_value().num);
  136. LatencyRecorder r1;
  137. MutexWithLatencyRecorder<pthread_mutex_t> m1(r1);
  138. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  139. ASSERT_EQ(0, pthread_create(&threads[i], NULL,
  140. signal_lock_thread<MutexWithLatencyRecorder<pthread_mutex_t> >, &m1));
  141. }
  142. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  143. pthread_join(threads[i], NULL);
  144. }
  145. LOG(INFO) << r1._latency;
  146. ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r1.count());
  147. }
  148. template <typename M0, typename M1>
  149. struct DoubleLockArg {
  150. M0 m0;
  151. M1 m1;
  152. };
  153. template <typename M0, typename M1>
  154. void *double_lock_thread(void *arg) {
  155. DoubleLockArg<M0, M1>* dla = (DoubleLockArg<M0, M1>*)arg;
  156. for (size_t i = 0; i < OPS_PER_THREAD; ++i) {
  157. std::unique_lock<M0> lck0(dla->m0, std::defer_lock);
  158. std::unique_lock<M1> lck1(dla->m1, std::defer_lock);
  159. butil::double_lock(lck0, lck1);
  160. usleep(10);
  161. }
  162. return NULL;
  163. }
  164. TEST_F(LockTimerTest, double_lock_time) {
  165. typedef MutexWithRecorder<pthread_mutex_t> M0;
  166. typedef MutexWithLatencyRecorder<pthread_mutex_t> M1;
  167. DoubleLockArg<M0, M1> arg;
  168. IntRecorder r0;
  169. LatencyRecorder r1;
  170. arg.m0.set_recorder(r0);
  171. arg.m1.set_recorder(r1);
  172. pthread_t threads[4];
  173. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  174. ASSERT_EQ(0, pthread_create(&threads[i], NULL,
  175. double_lock_thread<M0, M1>, &arg));
  176. }
  177. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  178. pthread_join(threads[i], NULL);
  179. }
  180. ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r0.get_value().num);
  181. ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r1.count());
  182. LOG(INFO) << r0;
  183. LOG(INFO) << r1._latency;
  184. r0.reset();
  185. r1._latency.reset();
  186. DoubleLockArg<M1, M0> arg1;
  187. arg1.m0.set_recorder(r1);
  188. arg1.m1.set_recorder(r0);
  189. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  190. ASSERT_EQ(0, pthread_create(&threads[i], NULL,
  191. double_lock_thread<M1, M0>, &arg1));
  192. }
  193. for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
  194. pthread_join(threads[i], NULL);
  195. }
  196. ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r0.get_value().num);
  197. ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r1.count());
  198. LOG(INFO) << r0;
  199. LOG(INFO) << r1._latency;
  200. }
  201. TEST_F(LockTimerTest, overhead) {
  202. LatencyRecorder r0;
  203. MutexWithLatencyRecorder<DummyMutex> m0(r0);
  204. butil::Timer timer;
  205. const size_t N = 1000 * 1000 * 10;
  206. ProfilerStart("mutex_with_latency_recorder.prof");
  207. timer.start();
  208. for (size_t i = 0; i < N; ++i) {
  209. BAIDU_SCOPED_LOCK(m0);
  210. }
  211. timer.stop();
  212. ProfilerStop();
  213. LOG(INFO) << "The overhead of MutexWithLatencyRecorder is "
  214. << timer.n_elapsed() / N << "ns";
  215. IntRecorder r1;
  216. MutexWithRecorder<DummyMutex> m1(r1);
  217. ProfilerStart("mutex_with_recorder.prof");
  218. timer.start();
  219. for (size_t i = 0; i < N; ++i) {
  220. BAIDU_SCOPED_LOCK(m1);
  221. }
  222. timer.stop();
  223. ProfilerStop();
  224. LOG(INFO) << "The overhead of MutexWithRecorder is "
  225. << timer.n_elapsed() / N << "ns";
  226. MutexWithRecorder<DummyMutex> m2;
  227. ProfilerStart("mutex_with_timer.prof");
  228. timer.start();
  229. for (size_t i = 0; i < N; ++i) {
  230. BAIDU_SCOPED_LOCK(m2);
  231. }
  232. timer.stop();
  233. ProfilerStop();
  234. LOG(INFO) << "The overhead of timer is "
  235. << timer.n_elapsed() / N << "ns";
  236. }
  237. } // namespace