freelist_test.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright (C) 2011 Tim Blechmann
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // enables error checks via dummy::~dtor
  7. #define BOOST_LOCKFREE_FREELIST_INIT_RUNS_DTOR
  8. #include <boost/lockfree/detail/freelist.hpp>
  9. #include <boost/lockfree/queue.hpp>
  10. #include <boost/foreach.hpp>
  11. #include <boost/thread.hpp>
  12. #include <boost/scoped_ptr.hpp>
  13. #define BOOST_TEST_MAIN
  14. #ifdef BOOST_LOCKFREE_INCLUDE_TESTS
  15. #include <boost/test/included/unit_test.hpp>
  16. #else
  17. #include <boost/test/unit_test.hpp>
  18. #endif
  19. #include <set>
  20. #include "test_helpers.hpp"
  21. using boost::lockfree::detail::atomic;
  22. atomic<bool> test_running(false);
  23. struct dummy
  24. {
  25. dummy(void)
  26. {
  27. if (test_running.load(boost::lockfree::detail::memory_order_relaxed))
  28. assert(allocated == 0);
  29. allocated = 1;
  30. }
  31. ~dummy(void)
  32. {
  33. if (test_running.load(boost::lockfree::detail::memory_order_relaxed))
  34. assert(allocated == 1);
  35. allocated = 0;
  36. }
  37. size_t padding[2]; // for used for the freelist node
  38. int allocated;
  39. };
  40. template <typename freelist_type,
  41. bool threadsafe,
  42. bool bounded>
  43. void run_test(void)
  44. {
  45. freelist_type fl(std::allocator<int>(), 8);
  46. std::set<dummy*> nodes;
  47. dummy d;
  48. if (bounded)
  49. test_running.store(true);
  50. for (int i = 0; i != 4; ++i) {
  51. dummy * allocated = fl.template construct<threadsafe, bounded>();
  52. BOOST_REQUIRE(nodes.find(allocated) == nodes.end());
  53. nodes.insert(allocated);
  54. }
  55. BOOST_FOREACH(dummy * d, nodes)
  56. fl.template destruct<threadsafe>(d);
  57. nodes.clear();
  58. for (int i = 0; i != 4; ++i)
  59. nodes.insert(fl.template construct<threadsafe, bounded>());
  60. BOOST_FOREACH(dummy * d, nodes)
  61. fl.template destruct<threadsafe>(d);
  62. for (int i = 0; i != 4; ++i)
  63. nodes.insert(fl.template construct<threadsafe, bounded>());
  64. if (bounded)
  65. test_running.store(false);
  66. }
  67. template <bool bounded>
  68. void run_tests(void)
  69. {
  70. run_test<boost::lockfree::detail::freelist_stack<dummy>, true, bounded>();
  71. run_test<boost::lockfree::detail::freelist_stack<dummy>, false, bounded>();
  72. run_test<boost::lockfree::detail::fixed_size_freelist<dummy>, true, bounded>();
  73. }
  74. BOOST_AUTO_TEST_CASE( freelist_tests )
  75. {
  76. run_tests<false>();
  77. run_tests<true>();
  78. }
  79. template <typename freelist_type, bool threadsafe>
  80. void oom_test(void)
  81. {
  82. const bool bounded = true;
  83. freelist_type fl(std::allocator<int>(), 8);
  84. for (int i = 0; i != 8; ++i)
  85. fl.template construct<threadsafe, bounded>();
  86. dummy * allocated = fl.template construct<threadsafe, bounded>();
  87. BOOST_REQUIRE(allocated == NULL);
  88. }
  89. BOOST_AUTO_TEST_CASE( oom_tests )
  90. {
  91. oom_test<boost::lockfree::detail::freelist_stack<dummy>, true >();
  92. oom_test<boost::lockfree::detail::freelist_stack<dummy>, false >();
  93. oom_test<boost::lockfree::detail::fixed_size_freelist<dummy>, true >();
  94. oom_test<boost::lockfree::detail::fixed_size_freelist<dummy>, false >();
  95. }
  96. template <typename freelist_type, bool bounded>
  97. struct freelist_tester
  98. {
  99. static const int size = 128;
  100. static const int thread_count = 4;
  101. #ifndef BOOST_LOCKFREE_STRESS_TEST
  102. static const int operations_per_thread = 1000;
  103. #else
  104. static const int operations_per_thread = 100000;
  105. #endif
  106. freelist_type fl;
  107. boost::lockfree::queue<dummy*> allocated_nodes;
  108. atomic<bool> running;
  109. static_hashed_set<dummy*, 1<<16 > working_set;
  110. freelist_tester(void):
  111. fl(std::allocator<int>(), size), allocated_nodes(256)
  112. {}
  113. void run()
  114. {
  115. running = true;
  116. if (bounded)
  117. test_running.store(true);
  118. boost::thread_group alloc_threads;
  119. boost::thread_group dealloc_threads;
  120. for (int i = 0; i != thread_count; ++i)
  121. dealloc_threads.create_thread(boost::bind(&freelist_tester::deallocate, this));
  122. for (int i = 0; i != thread_count; ++i)
  123. alloc_threads.create_thread(boost::bind(&freelist_tester::allocate, this));
  124. alloc_threads.join_all();
  125. test_running.store(false);
  126. running = false;
  127. dealloc_threads.join_all();
  128. }
  129. void allocate(void)
  130. {
  131. for (long i = 0; i != operations_per_thread; ++i) {
  132. for (;;) {
  133. dummy * node = fl.template construct<true, bounded>();
  134. if (node) {
  135. bool success = working_set.insert(node);
  136. assert(success);
  137. allocated_nodes.push(node);
  138. break;
  139. }
  140. }
  141. }
  142. }
  143. void deallocate(void)
  144. {
  145. for (;;) {
  146. dummy * node;
  147. if (allocated_nodes.pop(node)) {
  148. bool success = working_set.erase(node);
  149. assert(success);
  150. fl.template destruct<true>(node);
  151. }
  152. if (running.load() == false)
  153. break;
  154. #ifdef __VXWORKS__
  155. boost::thread::yield();
  156. #endif
  157. }
  158. dummy * node;
  159. while (allocated_nodes.pop(node)) {
  160. bool success = working_set.erase(node);
  161. assert(success);
  162. fl.template destruct<true>(node);
  163. }
  164. }
  165. };
  166. template <typename Tester>
  167. void run_tester()
  168. {
  169. boost::scoped_ptr<Tester> tester (new Tester);
  170. tester->run();
  171. }
  172. BOOST_AUTO_TEST_CASE( unbounded_freelist_test )
  173. {
  174. typedef freelist_tester<boost::lockfree::detail::freelist_stack<dummy>, false > test_type;
  175. run_tester<test_type>();
  176. }
  177. BOOST_AUTO_TEST_CASE( bounded_freelist_test )
  178. {
  179. typedef freelist_tester<boost::lockfree::detail::freelist_stack<dummy>, true > test_type;
  180. run_tester<test_type>();
  181. }
  182. BOOST_AUTO_TEST_CASE( fixed_size_freelist_test )
  183. {
  184. typedef freelist_tester<boost::lockfree::detail::fixed_size_freelist<dummy>, true > test_type;
  185. run_tester<test_type>();
  186. }