test_simple_seg_storage.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /* Copyright (C) 2011 Kwan Ting Chan
  2. *
  3. * Use, modification and distribution is subject to the
  4. * Boost Software License, Version 1.0. (See accompanying
  5. * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. #include "test_simple_seg_storage.hpp"
  8. #include "track_allocator.hpp"
  9. #include "random_shuffle.hpp"
  10. #include <boost/pool/simple_segregated_storage.hpp>
  11. #include <boost/assert.hpp>
  12. #include <boost/integer/common_factor_ct.hpp>
  13. #if defined(BOOST_MSVC) && (BOOST_MSVC <= 1600)
  14. #pragma warning(push)
  15. #pragma warning(disable: 4244)
  16. // ..\..\boost/random/uniform_int_distribution.hpp(171) :
  17. // warning C4127: conditional expression is constant
  18. #pragma warning(disable: 4127)
  19. #endif
  20. #include <boost/random/mersenne_twister.hpp>
  21. #include <boost/random/uniform_int.hpp>
  22. #include <boost/random/variate_generator.hpp>
  23. #if defined(BOOST_MSVC) && (BOOST_MSVC <= 1600)
  24. #pragma warning(pop)
  25. #endif
  26. #include <boost/core/lightweight_test.hpp>
  27. #include <algorithm>
  28. #include <functional>
  29. #include <set>
  30. #include <vector>
  31. #include <cstddef>
  32. #include <cstdlib>
  33. #include <ctime>
  34. #ifdef BOOST_MSVC
  35. #pragma warning(disable:4267)
  36. #endif
  37. // "A free list is ordered if repeated calls to malloc() will result in a
  38. // constantly-increasing sequence of values, as determined by std::less<void*>"
  39. // Return: true if in constantly-increasing order, false otherwise
  40. bool check_is_order(const std::vector<void*>& vs)
  41. {
  42. if(vs.size() < 2) { return true; }
  43. void *lower, *higher;
  44. std::vector<void*>::const_iterator ci = vs.begin();
  45. lower = *(ci++);
  46. while(ci != vs.end())
  47. {
  48. higher = *(ci++);
  49. if(!std::less<void*>()(lower, higher)) { return false; }
  50. }
  51. return true;
  52. }
  53. // Return: number of chunks malloc'd from store
  54. std::size_t test_is_order(test_simp_seg_store& store)
  55. {
  56. std::vector<void*> vpv;
  57. std::size_t nchunk = 0;
  58. // Pre: !empty()
  59. while(!store.empty())
  60. {
  61. void* const first = store.get_first();
  62. void* const pv = store.malloc();
  63. // "Takes the first available chunk from the free list
  64. // and returns it"
  65. BOOST_TEST(first == pv);
  66. vpv.push_back(pv);
  67. ++nchunk;
  68. }
  69. BOOST_TEST(check_is_order(vpv));
  70. return nchunk;
  71. }
  72. boost::mt19937 gen;
  73. int main()
  74. {
  75. std::srand(static_cast<unsigned>(std::time(0)));
  76. gen.seed(static_cast<boost::uint32_t>(std::time(0)));
  77. /* Store::segregate(block, sz, partition_sz, end) */
  78. std::size_t partition_sz
  79. = boost::integer::static_lcm<sizeof(void*), sizeof(int)>::value;
  80. boost::uniform_int<> dist(partition_sz, 10000);
  81. boost::variate_generator<boost::mt19937&,
  82. boost::uniform_int<> > die(gen, dist);
  83. std::size_t block_size = die();
  84. // Pre: npartition_sz >= sizeof(void*)
  85. // npartition_sz = sizeof(void*) * i, for some integer i
  86. // nsz >= npartition_sz
  87. // block is properly aligned for an array of object of
  88. // size npartition_sz and array of void *
  89. BOOST_ASSERT(partition_sz >= sizeof(void*));
  90. BOOST_ASSERT(partition_sz % sizeof(void*) == 0);
  91. BOOST_ASSERT(block_size >= partition_sz);
  92. {
  93. char* const pc = track_allocator::malloc(block_size);
  94. // (Test) Pre: block of memory is valid
  95. BOOST_ASSERT(pc);
  96. int endadd = 0;
  97. void* const pvret = test_simp_seg_store::segregate(pc, block_size,
  98. partition_sz, &endadd);
  99. // The first chunk "is always equal to block"
  100. BOOST_TEST(pvret == pc);
  101. void* cur = test_simp_seg_store::get_nextof(static_cast<int*>(pvret));
  102. void* last = pvret;
  103. std::size_t nchunk = 1;
  104. while(cur != &endadd)
  105. {
  106. ++nchunk;
  107. // Memory of each chunk does not overlap
  108. // The free list constructed is actually from the given block
  109. // The "interleaved free list is ordered"
  110. BOOST_TEST(std::less_equal<void*>()(static_cast<char*>(last)
  111. + partition_sz, cur));
  112. BOOST_TEST(std::less_equal<void*>()(static_cast<char*>(cur)
  113. + partition_sz, pc + block_size));
  114. last = cur;
  115. cur = test_simp_seg_store::get_nextof(static_cast<int*>(cur));
  116. }
  117. // "The last chunk is set to point to end"
  118. // "Partitioning into as many partition_sz-sized chunks as possible"
  119. BOOST_TEST(nchunk == block_size/partition_sz);
  120. }
  121. /* t.add_block(block, sz, partition_sz), t.malloc() */
  122. {
  123. // Default constructor of simple_segregated_storage do nothing
  124. test_simp_seg_store tstore;
  125. // Post: empty()
  126. BOOST_TEST(tstore.empty());
  127. char* const pc = track_allocator::malloc(block_size);
  128. tstore.add_block(pc, block_size, partition_sz);
  129. // The first chunk "is always equal to block"
  130. BOOST_TEST(tstore.get_first() == pc);
  131. // Empty before add_block() => "is ordered after"
  132. std::size_t nchunk = test_is_order(tstore);
  133. // "Partitioning into as many partition_sz-sized chunks as possible"
  134. BOOST_TEST(nchunk == block_size/partition_sz);
  135. BOOST_ASSERT(partition_sz <= 23);
  136. test_simp_seg_store tstore2;
  137. char* const pc2 = track_allocator::malloc(88);
  138. tstore2.add_block(pc2, 24, partition_sz);
  139. tstore2.add_block(pc2 + 64, 24, partition_sz);
  140. tstore2.add_block(pc2 + 32, 24, partition_sz);
  141. tstore2.add_block(track_allocator::malloc(23), 23, partition_sz);
  142. std::size_t nchunk_ref = (3*(24/partition_sz)) + (23/partition_sz);
  143. for(nchunk = 0; !tstore2.empty(); tstore2.malloc(), ++nchunk) {}
  144. // add_block() merges new free list to existing
  145. BOOST_TEST(nchunk == nchunk_ref);
  146. }
  147. /* t.free(chunk) */
  148. {
  149. test_simp_seg_store tstore;
  150. char* const pc = track_allocator::malloc(partition_sz);
  151. tstore.add_block(pc, partition_sz, partition_sz);
  152. void* pv = tstore.malloc();
  153. BOOST_TEST(tstore.empty());
  154. tstore.free(pv);
  155. }
  156. /* t.add_ordered_block(block, sz, partition_sz) */
  157. {
  158. {
  159. char* const pc = track_allocator::malloc(6 * partition_sz);
  160. std::vector<void*> vpv;
  161. vpv.push_back(pc);
  162. vpv.push_back(pc + (2 * partition_sz));
  163. vpv.push_back(pc + (4 * partition_sz));
  164. do
  165. {
  166. test_simp_seg_store tstore;
  167. tstore.add_ordered_block(vpv[0], 2*partition_sz, partition_sz);
  168. tstore.add_ordered_block(vpv[1], 2*partition_sz, partition_sz);
  169. tstore.add_ordered_block(vpv[2], 2*partition_sz, partition_sz);
  170. // "Order-preserving"
  171. test_is_order(tstore);
  172. } while(std::next_permutation(vpv.begin(), vpv.end()));
  173. }
  174. {
  175. test_simp_seg_store tstore;
  176. char* const pc = track_allocator::malloc(6 * partition_sz);
  177. tstore.add_ordered_block(pc, 2 * partition_sz, partition_sz);
  178. tstore.add_ordered_block(pc + (4 * partition_sz),
  179. (2 * partition_sz), partition_sz);
  180. // "Order-preserving"
  181. test_is_order(tstore);
  182. }
  183. {
  184. test_simp_seg_store tstore;
  185. char* const pc = track_allocator::malloc(6 * partition_sz);
  186. tstore.add_ordered_block(pc + (4 * partition_sz),
  187. (2 * partition_sz), partition_sz);
  188. tstore.add_ordered_block(pc, 2 * partition_sz, partition_sz);
  189. // "Order-preserving"
  190. test_is_order(tstore);
  191. }
  192. }
  193. /* t.ordered_free(chunk) */
  194. {
  195. char* const pc = track_allocator::malloc(6 * partition_sz);
  196. test_simp_seg_store tstore;
  197. tstore.add_block(pc, 6 * partition_sz, partition_sz);
  198. std::vector<void*> vpv;
  199. for(std::size_t i=0; i < 6; ++i) { vpv.push_back(tstore.malloc()); }
  200. BOOST_ASSERT(tstore.empty());
  201. pool_test_random_shuffle(vpv.begin(), vpv.end());
  202. for(std::size_t i=0; i < 6; ++i)
  203. {
  204. tstore.ordered_free(vpv[i]);
  205. }
  206. // "Order-preserving"
  207. test_is_order(tstore);
  208. }
  209. /* t.malloc_n(n, partition_sz) */
  210. {
  211. {
  212. char* const pc = track_allocator::malloc(12 * partition_sz);
  213. test_simp_seg_store tstore;
  214. tstore.add_ordered_block(pc, 2 * partition_sz, partition_sz);
  215. tstore.add_ordered_block(pc + (3 * partition_sz),
  216. 3 * partition_sz, partition_sz);
  217. tstore.add_ordered_block(pc + (7 * partition_sz),
  218. 5 * partition_sz, partition_sz);
  219. void* pvret = tstore.malloc_n(6, partition_sz);
  220. BOOST_TEST(pvret == 0);
  221. pvret = tstore.malloc_n(0, partition_sz);
  222. // There's no prohibition against asking for zero elements
  223. BOOST_TEST(pvret == 0);
  224. pvret = tstore.malloc_n(3, partition_sz);
  225. // Implicit assumption that contiguous sequence found is the first
  226. // available while traversing from the start of the free list
  227. BOOST_TEST(pvret == pc + (3 * partition_sz));
  228. pvret = tstore.malloc_n(4, partition_sz);
  229. BOOST_TEST(pvret == pc + (7 * partition_sz));
  230. // There should still be two contiguous
  231. // and one non-contiguous chunk left
  232. std::size_t nchunks = 0;
  233. while(!tstore.empty())
  234. {
  235. tstore.malloc();
  236. ++nchunks;
  237. }
  238. BOOST_TEST(nchunks == 3);
  239. }
  240. {
  241. char* const pc = track_allocator::malloc(12 * partition_sz);
  242. test_simp_seg_store tstore;
  243. tstore.add_ordered_block(pc, 2 * partition_sz, partition_sz);
  244. tstore.add_ordered_block(pc + (3 * partition_sz),
  245. 3 * partition_sz, partition_sz);
  246. tstore.add_ordered_block(pc + (7 * partition_sz),
  247. 5 * partition_sz, partition_sz);
  248. tstore.malloc_n(3, partition_sz);
  249. // "Order-preserving"
  250. test_is_order(tstore);
  251. }
  252. }
  253. for(std::set<char*>::iterator itr
  254. = track_allocator::allocated_blocks.begin();
  255. itr != track_allocator::allocated_blocks.end();
  256. ++itr)
  257. {
  258. delete [] *itr;
  259. }
  260. track_allocator::allocated_blocks.clear();
  261. return boost::report_errors();
  262. }