memory_algorithm_test_template.hpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org/libs/interprocess for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #ifndef BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER
  11. #define BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER
  12. #include <boost/interprocess/detail/config_begin.hpp>
  13. #include <boost/interprocess/containers/vector.hpp>
  14. #include <vector>
  15. #include <iostream>
  16. #include <new> //std::nothrow
  17. #include <cstring> //std::memset
  18. namespace boost { namespace interprocess { namespace test {
  19. enum deallocation_type { DirectDeallocation, InverseDeallocation, MixedDeallocation, EndDeallocationType };
  20. //This test allocates until there is no more memory
  21. //and after that deallocates all in the inverse order
  22. template<class Allocator>
  23. bool test_allocation(Allocator &a)
  24. {
  25. for( deallocation_type t = DirectDeallocation
  26. ; t != EndDeallocationType
  27. ; t = (deallocation_type)((int)t + 1)){
  28. std::vector<void*> buffers;
  29. typename Allocator::size_type free_memory = a.get_free_memory();
  30. for(int i = 0; true; ++i){
  31. void *ptr = a.allocate(i, std::nothrow);
  32. if(!ptr)
  33. break;
  34. std::size_t size = a.size(ptr);
  35. std::memset(ptr, 0, size);
  36. buffers.push_back(ptr);
  37. }
  38. switch(t){
  39. case DirectDeallocation:
  40. {
  41. for(int j = 0, max = (int)buffers.size()
  42. ;j < max
  43. ;++j){
  44. a.deallocate(buffers[j]);
  45. }
  46. }
  47. break;
  48. case InverseDeallocation:
  49. {
  50. for(int j = (int)buffers.size()
  51. ;j--
  52. ;){
  53. a.deallocate(buffers[j]);
  54. }
  55. }
  56. break;
  57. case MixedDeallocation:
  58. {
  59. for(int j = 0, max = (int)buffers.size()
  60. ;j < max
  61. ;++j){
  62. int pos = (j%4)*((int)buffers.size())/4;
  63. a.deallocate(buffers[pos]);
  64. buffers.erase(buffers.begin()+pos);
  65. }
  66. }
  67. break;
  68. default:
  69. break;
  70. }
  71. bool ok = free_memory == a.get_free_memory() &&
  72. a.all_memory_deallocated() && a.check_sanity();
  73. if(!ok) return ok;
  74. }
  75. return true;
  76. }
  77. //This test allocates until there is no more memory
  78. //and after that tries to shrink all the buffers to the
  79. //half of the original size
  80. template<class Allocator>
  81. bool test_allocation_shrink(Allocator &a)
  82. {
  83. std::vector<void*> buffers;
  84. //Allocate buffers with extra memory
  85. for(int i = 0; true; ++i){
  86. void *ptr = a.allocate(i*2, std::nothrow);
  87. if(!ptr)
  88. break;
  89. std::size_t size = a.size(ptr);
  90. std::memset(ptr, 0, size);
  91. buffers.push_back(ptr);
  92. }
  93. //Now shrink to half
  94. for(int i = 0, max = (int)buffers.size()
  95. ;i < max
  96. ; ++i){
  97. typename Allocator::size_type received_size;
  98. char *reuse = static_cast<char*>(buffers[i]);
  99. if(a.template allocation_command<char>
  100. ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, i*2
  101. , received_size = i, reuse)){
  102. if(received_size > std::size_t(i*2)){
  103. return false;
  104. }
  105. if(received_size < std::size_t(i)){
  106. return false;
  107. }
  108. std::memset(buffers[i], 0, a.size(buffers[i]));
  109. }
  110. }
  111. //Deallocate it in non sequential order
  112. for(int j = 0, max = (int)buffers.size()
  113. ;j < max
  114. ;++j){
  115. int pos = (j%4)*((int)buffers.size())/4;
  116. a.deallocate(buffers[pos]);
  117. buffers.erase(buffers.begin()+pos);
  118. }
  119. return a.all_memory_deallocated() && a.check_sanity();
  120. }
  121. //This test allocates until there is no more memory
  122. //and after that tries to expand all the buffers to
  123. //avoid the wasted internal fragmentation
  124. template<class Allocator>
  125. bool test_allocation_expand(Allocator &a)
  126. {
  127. std::vector<void*> buffers;
  128. //Allocate buffers with extra memory
  129. for(int i = 0; true; ++i){
  130. void *ptr = a.allocate(i, std::nothrow);
  131. if(!ptr)
  132. break;
  133. std::size_t size = a.size(ptr);
  134. std::memset(ptr, 0, size);
  135. buffers.push_back(ptr);
  136. }
  137. //Now try to expand to the double of the size
  138. for(int i = 0, max = (int)buffers.size()
  139. ;i < max
  140. ;++i){
  141. typename Allocator::size_type received_size;
  142. std::size_t min_size = i+1;
  143. std::size_t preferred_size = i*2;
  144. preferred_size = min_size > preferred_size ? min_size : preferred_size;
  145. char *reuse = static_cast<char*>(buffers[i]);
  146. while(a.template allocation_command<char>
  147. ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size
  148. , received_size = preferred_size, reuse)){
  149. //Check received size is bigger than minimum
  150. if(received_size < min_size){
  151. return false;
  152. }
  153. //Now, try to expand further
  154. min_size = received_size+1;
  155. preferred_size = min_size*2;
  156. }
  157. }
  158. //Deallocate it in non sequential order
  159. for(int j = 0, max = (int)buffers.size()
  160. ;j < max
  161. ;++j){
  162. int pos = (j%4)*((int)buffers.size())/4;
  163. a.deallocate(buffers[pos]);
  164. buffers.erase(buffers.begin()+pos);
  165. }
  166. return a.all_memory_deallocated() && a.check_sanity();
  167. }
  168. //This test allocates until there is no more memory
  169. //and after that tries to expand all the buffers to
  170. //avoid the wasted internal fragmentation
  171. template<class Allocator>
  172. bool test_allocation_shrink_and_expand(Allocator &a)
  173. {
  174. std::vector<void*> buffers;
  175. std::vector<typename Allocator::size_type> received_sizes;
  176. std::vector<bool> size_reduced;
  177. //Allocate buffers wand store received sizes
  178. for(int i = 0; true; ++i){
  179. typename Allocator::size_type received_size;
  180. char *reuse = 0;
  181. void *ptr = a.template allocation_command<char>
  182. ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, i, received_size = i*2, reuse);
  183. if(!ptr){
  184. ptr = a.template allocation_command<char>
  185. ( boost::interprocess::allocate_new | boost::interprocess::nothrow_allocation, 1, received_size = i*2, reuse);
  186. if(!ptr)
  187. break;
  188. }
  189. buffers.push_back(ptr);
  190. received_sizes.push_back(received_size);
  191. }
  192. //Now shrink to half
  193. for(int i = 0, max = (int)buffers.size()
  194. ; i < max
  195. ; ++i){
  196. typename Allocator::size_type received_size;
  197. char *reuse = static_cast<char*>(buffers[i]);
  198. if(a.template allocation_command<char>
  199. ( boost::interprocess::shrink_in_place | boost::interprocess::nothrow_allocation, received_sizes[i]
  200. , received_size = i, reuse)){
  201. if(received_size > std::size_t(received_sizes[i])){
  202. return false;
  203. }
  204. if(received_size < std::size_t(i)){
  205. return false;
  206. }
  207. size_reduced.push_back(received_size != received_sizes[i]);
  208. }
  209. }
  210. //Now try to expand to the original size
  211. for(int i = 0, max = (int)buffers.size()
  212. ;i < max
  213. ;++i){
  214. typename Allocator::size_type received_size;
  215. std::size_t request_size = received_sizes[i];
  216. char *reuse = static_cast<char*>(buffers[i]);
  217. if(a.template allocation_command<char>
  218. ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, request_size
  219. , received_size = request_size, reuse)){
  220. if(received_size != received_sizes[i]){
  221. return false;
  222. }
  223. }
  224. else{
  225. return false;
  226. }
  227. }
  228. //Deallocate it in non sequential order
  229. for(int j = 0, max = (int)buffers.size()
  230. ;j < max
  231. ;++j){
  232. int pos = (j%4)*((int)buffers.size())/4;
  233. a.deallocate(buffers[pos]);
  234. buffers.erase(buffers.begin()+pos);
  235. }
  236. return a.all_memory_deallocated() && a.check_sanity();
  237. }
  238. //This test allocates until there is no more memory
  239. //and after that deallocates the odd buffers to
  240. //make room for expansions. The expansion will probably
  241. //success since the deallocation left room for that.
  242. template<class Allocator>
  243. bool test_allocation_deallocation_expand(Allocator &a)
  244. {
  245. std::vector<void*> buffers;
  246. //Allocate buffers with extra memory
  247. for(int i = 0; true; ++i){
  248. void *ptr = a.allocate(i, std::nothrow);
  249. if(!ptr)
  250. break;
  251. std::size_t size = a.size(ptr);
  252. std::memset(ptr, 0, size);
  253. buffers.push_back(ptr);
  254. }
  255. //Now deallocate the half of the blocks
  256. //so expand maybe can merge new free blocks
  257. for(int i = 0, max = (int)buffers.size()
  258. ;i < max
  259. ;++i){
  260. if(i%2){
  261. a.deallocate(buffers[i]);
  262. buffers[i] = 0;
  263. }
  264. }
  265. //Now try to expand to the double of the size
  266. for(int i = 0, max = (int)buffers.size()
  267. ;i < max
  268. ;++i){
  269. //
  270. if(buffers[i]){
  271. typename Allocator::size_type received_size;
  272. std::size_t min_size = i+1;
  273. std::size_t preferred_size = i*2;
  274. preferred_size = min_size > preferred_size ? min_size : preferred_size;
  275. char *reuse = static_cast<char*>(buffers[i]);
  276. while(a.template allocation_command<char>
  277. ( boost::interprocess::expand_fwd | boost::interprocess::nothrow_allocation, min_size
  278. , received_size = preferred_size, reuse)){
  279. //Check received size is bigger than minimum
  280. if(received_size < min_size){
  281. return false;
  282. }
  283. //Now, try to expand further
  284. min_size = received_size+1;
  285. preferred_size = min_size*2;
  286. }
  287. }
  288. }
  289. //Now erase null values from the vector
  290. buffers.erase( std::remove(buffers.begin(), buffers.end(), static_cast<void*>(0))
  291. , buffers.end());
  292. //Deallocate it in non sequential order
  293. for(int j = 0, max = (int)buffers.size()
  294. ;j < max
  295. ;++j){
  296. int pos = (j%4)*((int)buffers.size())/4;
  297. a.deallocate(buffers[pos]);
  298. buffers.erase(buffers.begin()+pos);
  299. }
  300. return a.all_memory_deallocated() && a.check_sanity();
  301. }
  302. //This test allocates until there is no more memory
  303. //and after that deallocates all except the last.
  304. //If the allocation algorithm is a bottom-up algorithm
  305. //the last buffer will be in the end of the segment.
  306. //Then the test will start expanding backwards, until
  307. //the buffer fills all the memory
  308. template<class Allocator>
  309. bool test_allocation_with_reuse(Allocator &a)
  310. {
  311. //We will repeat this test for different sized elements
  312. for(int sizeof_object = 1; sizeof_object < 20; ++sizeof_object){
  313. std::vector<void*> buffers;
  314. //Allocate buffers with extra memory
  315. for(int i = 0; true; ++i){
  316. void *ptr = a.allocate(i*sizeof_object, std::nothrow);
  317. if(!ptr)
  318. break;
  319. std::size_t size = a.size(ptr);
  320. std::memset(ptr, 0, size);
  321. buffers.push_back(ptr);
  322. }
  323. //Now deallocate all except the latest
  324. //Now try to expand to the double of the sizeof_object
  325. for(int i = 0, max = (int)buffers.size() - 1
  326. ;i < max
  327. ;++i){
  328. a.deallocate(buffers[i]);
  329. }
  330. //Save the unique buffer and clear vector
  331. void *ptr = buffers.back();
  332. buffers.clear();
  333. //Now allocate with reuse
  334. typename Allocator::size_type received_size = 0;
  335. for(int i = 0; true; ++i){
  336. std::size_t min_size = (received_size + 1);
  337. std::size_t prf_size = (received_size + (i+1)*2);
  338. void *reuse = ptr;
  339. void *ret = a.raw_allocation_command
  340. ( boost::interprocess::expand_bwd | boost::interprocess::nothrow_allocation, min_size
  341. , received_size = prf_size, reuse, sizeof_object);
  342. if(!ret)
  343. break;
  344. //If we have memory, this must be a buffer reuse
  345. if(!reuse)
  346. return 1;
  347. if(received_size < min_size)
  348. return 1;
  349. ptr = ret;
  350. }
  351. //There is only a single block so deallocate it
  352. a.deallocate(ptr);
  353. if(!a.all_memory_deallocated() || !a.check_sanity())
  354. return false;
  355. }
  356. return true;
  357. }
  358. //This test allocates memory with different alignments
  359. //and checks returned memory is aligned.
  360. template<class Allocator>
  361. bool test_aligned_allocation(Allocator &a)
  362. {
  363. //Allocate aligned buffers in a loop
  364. //and then deallocate it
  365. bool continue_loop = true;
  366. for(unsigned int i = 1; continue_loop; i <<= 1){
  367. for(unsigned int j = 1; true; j <<= 1){
  368. void *ptr = a.allocate_aligned(i-1, j, std::nothrow);
  369. if(!ptr){
  370. if(j == 1)
  371. continue_loop = false;
  372. break;
  373. }
  374. if(((std::size_t)ptr & (j - 1)) != 0)
  375. return false;
  376. a.deallocate(ptr);
  377. if(!a.all_memory_deallocated() || !a.check_sanity()){
  378. return false;
  379. }
  380. }
  381. }
  382. return a.all_memory_deallocated() && a.check_sanity();
  383. }
  384. //This test allocates memory with different alignments
  385. //and checks returned memory is aligned.
  386. template<class Allocator>
  387. bool test_continuous_aligned_allocation(Allocator &a)
  388. {
  389. std::vector<void*> buffers;
  390. //Allocate aligned buffers in a loop
  391. //and then deallocate it
  392. bool continue_loop = true;
  393. for(unsigned i = 1; continue_loop && i; i <<= 1){
  394. for(unsigned int j = 1; j; j <<= 1){
  395. for(bool any_allocated = false; 1;){
  396. void *ptr = a.allocate_aligned(i-1, j, std::nothrow);
  397. buffers.push_back(ptr);
  398. if(!ptr){
  399. if(j == 1 && !any_allocated){
  400. continue_loop = false;
  401. }
  402. break;
  403. }
  404. else{
  405. any_allocated = true;
  406. }
  407. if(((std::size_t)ptr & (j - 1)) != 0)
  408. return false;
  409. }
  410. //Deallocate all
  411. for(unsigned int k = (int)buffers.size(); k--;){
  412. a.deallocate(buffers[k]);
  413. }
  414. buffers.clear();
  415. if(!a.all_memory_deallocated() && a.check_sanity())
  416. return false;
  417. if(!continue_loop)
  418. break;
  419. }
  420. }
  421. return a.all_memory_deallocated() && a.check_sanity();
  422. }
  423. //This test allocates memory, writes it with a non-zero value and
  424. //tests zero_free_memory initializes to zero for the next allocation
  425. template<class Allocator>
  426. bool test_clear_free_memory(Allocator &a)
  427. {
  428. std::vector<void*> buffers;
  429. //Allocate memory
  430. for(int i = 0; true; ++i){
  431. void *ptr = a.allocate(i, std::nothrow);
  432. if(!ptr)
  433. break;
  434. std::size_t size = a.size(ptr);
  435. std::memset(ptr, 1, size);
  436. buffers.push_back(ptr);
  437. }
  438. //Mark it
  439. for(int i = 0, max = buffers.size(); i < max; ++i){
  440. std::memset(buffers[i], 1, i);
  441. }
  442. //Deallocate all
  443. for(int j = (int)buffers.size()
  444. ;j--
  445. ;){
  446. a.deallocate(buffers[j]);
  447. }
  448. buffers.clear();
  449. if(!a.all_memory_deallocated() && a.check_sanity())
  450. return false;
  451. //Now clear all free memory
  452. a.zero_free_memory();
  453. if(!a.all_memory_deallocated() && a.check_sanity())
  454. return false;
  455. //Now test all allocated memory is zero
  456. //Allocate memory
  457. const char *first_addr = 0;
  458. for(int i = 0; true; ++i){
  459. void *ptr = a.allocate(i, std::nothrow);
  460. if(!ptr)
  461. break;
  462. if(i == 0){
  463. first_addr = (char*)ptr;
  464. }
  465. std::size_t memsize = a.size(ptr);
  466. buffers.push_back(ptr);
  467. for(int j = 0; j < (int)memsize; ++j){
  468. if(static_cast<char*>((char*)ptr)[j]){
  469. std::cout << "Zero memory test failed. in buffer " << i
  470. << " byte " << j << " first address " << (void*) first_addr << " offset " << ((char*)ptr+j) - (char*)first_addr << " memsize: " << memsize << std::endl;
  471. return false;
  472. }
  473. }
  474. }
  475. //Deallocate all
  476. for(int j = (int)buffers.size()
  477. ;j--
  478. ;){
  479. a.deallocate(buffers[j]);
  480. }
  481. if(!a.all_memory_deallocated() && a.check_sanity())
  482. return false;
  483. return true;
  484. }
  485. //This test uses tests grow and shrink_to_fit functions
  486. template<class Allocator>
  487. bool test_grow_shrink_to_fit(Allocator &a)
  488. {
  489. std::vector<void*> buffers;
  490. typename Allocator::size_type original_size = a.get_size();
  491. typename Allocator::size_type original_free = a.get_free_memory();
  492. a.shrink_to_fit();
  493. if(!a.all_memory_deallocated() && a.check_sanity())
  494. return false;
  495. typename Allocator::size_type shrunk_size = a.get_size();
  496. typename Allocator::size_type shrunk_free_memory = a.get_free_memory();
  497. if(shrunk_size != a.get_min_size())
  498. return 1;
  499. a.grow(original_size - shrunk_size);
  500. if(!a.all_memory_deallocated() && a.check_sanity())
  501. return false;
  502. if(original_size != a.get_size())
  503. return false;
  504. if(original_free != a.get_free_memory())
  505. return false;
  506. //Allocate memory
  507. for(int i = 0; true; ++i){
  508. void *ptr = a.allocate(i, std::nothrow);
  509. if(!ptr)
  510. break;
  511. std::size_t size = a.size(ptr);
  512. std::memset(ptr, 0, size);
  513. buffers.push_back(ptr);
  514. }
  515. //Now deallocate the half of the blocks
  516. //so expand maybe can merge new free blocks
  517. for(int i = 0, max = (int)buffers.size()
  518. ;i < max
  519. ;++i){
  520. if(i%2){
  521. a.deallocate(buffers[i]);
  522. buffers[i] = 0;
  523. }
  524. }
  525. //Deallocate the rest of the blocks
  526. //Deallocate it in non sequential order
  527. for(int j = 0, max = (int)buffers.size()
  528. ;j < max
  529. ;++j){
  530. int pos = (j%5)*((int)buffers.size())/4;
  531. if(pos == int(buffers.size()))
  532. --pos;
  533. a.deallocate(buffers[pos]);
  534. buffers.erase(buffers.begin()+pos);
  535. typename Allocator::size_type old_free = a.get_free_memory();
  536. a.shrink_to_fit();
  537. if(!a.check_sanity()) return false;
  538. if(original_size < a.get_size()) return false;
  539. if(old_free < a.get_free_memory()) return false;
  540. a.grow(original_size - a.get_size());
  541. if(!a.check_sanity()) return false;
  542. if(original_size != a.get_size()) return false;
  543. if(old_free != a.get_free_memory()) return false;
  544. }
  545. //Now shrink it to the maximum
  546. a.shrink_to_fit();
  547. if(a.get_size() != a.get_min_size())
  548. return 1;
  549. if(shrunk_free_memory != a.get_free_memory())
  550. return 1;
  551. if(!a.all_memory_deallocated() && a.check_sanity())
  552. return false;
  553. a.grow(original_size - shrunk_size);
  554. if(original_size != a.get_size())
  555. return false;
  556. if(original_free != a.get_free_memory())
  557. return false;
  558. if(!a.all_memory_deallocated() && a.check_sanity())
  559. return false;
  560. return true;
  561. }
  562. //This test allocates multiple values until there is no more memory
  563. //and after that deallocates all in the inverse order
  564. template<class Allocator>
  565. bool test_many_equal_allocation(Allocator &a)
  566. {
  567. for( deallocation_type t = DirectDeallocation
  568. ; t != EndDeallocationType
  569. ; t = (deallocation_type)((int)t + 1)){
  570. typename Allocator::size_type free_memory = a.get_free_memory();
  571. std::vector<void*> buffers2;
  572. //Allocate buffers with extra memory
  573. for(int i = 0; true; ++i){
  574. void *ptr = a.allocate(i, std::nothrow);
  575. if(!ptr)
  576. break;
  577. std::size_t size = a.size(ptr);
  578. std::memset(ptr, 0, size);
  579. if(!a.check_sanity())
  580. return false;
  581. buffers2.push_back(ptr);
  582. }
  583. //Now deallocate the half of the blocks
  584. //so expand maybe can merge new free blocks
  585. for(int i = 0, max = (int)buffers2.size()
  586. ;i < max
  587. ;++i){
  588. if(i%2){
  589. a.deallocate(buffers2[i]);
  590. buffers2[i] = 0;
  591. }
  592. }
  593. if(!a.check_sanity())
  594. return false;
  595. typedef typename Allocator::multiallocation_chain multiallocation_chain;
  596. std::vector<void*> buffers;
  597. for(int i = 0; true; ++i){
  598. multiallocation_chain chain;
  599. a.allocate_many(std::nothrow, i+1, (i+1)*2, chain);
  600. if(chain.empty())
  601. break;
  602. typename multiallocation_chain::size_type n = chain.size();
  603. while(!chain.empty()){
  604. buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front()));
  605. }
  606. if(n != std::size_t((i+1)*2))
  607. return false;
  608. }
  609. if(!a.check_sanity())
  610. return false;
  611. switch(t){
  612. case DirectDeallocation:
  613. {
  614. for(int j = 0, max = (int)buffers.size()
  615. ;j < max
  616. ;++j){
  617. a.deallocate(buffers[j]);
  618. }
  619. }
  620. break;
  621. case InverseDeallocation:
  622. {
  623. for(int j = (int)buffers.size()
  624. ;j--
  625. ;){
  626. a.deallocate(buffers[j]);
  627. }
  628. }
  629. break;
  630. case MixedDeallocation:
  631. {
  632. for(int j = 0, max = (int)buffers.size()
  633. ;j < max
  634. ;++j){
  635. int pos = (j%4)*((int)buffers.size())/4;
  636. a.deallocate(buffers[pos]);
  637. buffers.erase(buffers.begin()+pos);
  638. }
  639. }
  640. break;
  641. default:
  642. break;
  643. }
  644. //Deallocate the rest of the blocks
  645. //Deallocate it in non sequential order
  646. for(int j = 0, max = (int)buffers2.size()
  647. ;j < max
  648. ;++j){
  649. int pos = (j%4)*((int)buffers2.size())/4;
  650. a.deallocate(buffers2[pos]);
  651. buffers2.erase(buffers2.begin()+pos);
  652. }
  653. bool ok = free_memory == a.get_free_memory() &&
  654. a.all_memory_deallocated() && a.check_sanity();
  655. if(!ok) return ok;
  656. }
  657. return true;
  658. }
  659. //This test allocates multiple values until there is no more memory
  660. //and after that deallocates all in the inverse order
  661. template<class Allocator>
  662. bool test_many_different_allocation(Allocator &a)
  663. {
  664. typedef typename Allocator::multiallocation_chain multiallocation_chain;
  665. const std::size_t ArraySize = 11;
  666. typename Allocator::size_type requested_sizes[ArraySize];
  667. for(std::size_t i = 0; i < ArraySize; ++i){
  668. requested_sizes[i] = 4*i;
  669. }
  670. for( deallocation_type t = DirectDeallocation
  671. ; t != EndDeallocationType
  672. ; t = (deallocation_type)((int)t + 1)){
  673. typename Allocator::size_type free_memory = a.get_free_memory();
  674. std::vector<void*> buffers2;
  675. //Allocate buffers with extra memory
  676. for(int i = 0; true; ++i){
  677. void *ptr = a.allocate(i, std::nothrow);
  678. if(!ptr)
  679. break;
  680. std::size_t size = a.size(ptr);
  681. std::memset(ptr, 0, size);
  682. buffers2.push_back(ptr);
  683. }
  684. //Now deallocate the half of the blocks
  685. //so expand maybe can merge new free blocks
  686. for(int i = 0, max = (int)buffers2.size()
  687. ;i < max
  688. ;++i){
  689. if(i%2){
  690. a.deallocate(buffers2[i]);
  691. buffers2[i] = 0;
  692. }
  693. }
  694. std::vector<void*> buffers;
  695. for(int i = 0; true; ++i){
  696. multiallocation_chain chain;
  697. a.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain);
  698. if(chain.empty())
  699. break;
  700. typename multiallocation_chain::size_type n = chain.size();
  701. while(!chain.empty()){
  702. buffers.push_back(ipcdetail::to_raw_pointer(chain.pop_front()));
  703. }
  704. if(n != ArraySize)
  705. return false;
  706. }
  707. switch(t){
  708. case DirectDeallocation:
  709. {
  710. for(int j = 0, max = (int)buffers.size()
  711. ;j < max
  712. ;++j){
  713. a.deallocate(buffers[j]);
  714. }
  715. }
  716. break;
  717. case InverseDeallocation:
  718. {
  719. for(int j = (int)buffers.size()
  720. ;j--
  721. ;){
  722. a.deallocate(buffers[j]);
  723. }
  724. }
  725. break;
  726. case MixedDeallocation:
  727. {
  728. for(int j = 0, max = (int)buffers.size()
  729. ;j < max
  730. ;++j){
  731. int pos = (j%4)*((int)buffers.size())/4;
  732. a.deallocate(buffers[pos]);
  733. buffers.erase(buffers.begin()+pos);
  734. }
  735. }
  736. break;
  737. default:
  738. break;
  739. }
  740. //Deallocate the rest of the blocks
  741. //Deallocate it in non sequential order
  742. for(int j = 0, max = (int)buffers2.size()
  743. ;j < max
  744. ;++j){
  745. int pos = (j%4)*((int)buffers2.size())/4;
  746. a.deallocate(buffers2[pos]);
  747. buffers2.erase(buffers2.begin()+pos);
  748. }
  749. bool ok = free_memory == a.get_free_memory() &&
  750. a.all_memory_deallocated() && a.check_sanity();
  751. if(!ok) return ok;
  752. }
  753. return true;
  754. }
  755. //This test allocates multiple values until there is no more memory
  756. //and after that deallocates all in the inverse order
  757. template<class Allocator>
  758. bool test_many_deallocation(Allocator &a)
  759. {
  760. typedef typename Allocator::multiallocation_chain multiallocation_chain;
  761. typedef typename Allocator::multiallocation_chain multiallocation_chain;
  762. const std::size_t ArraySize = 11;
  763. vector<multiallocation_chain> buffers;
  764. typename Allocator::size_type requested_sizes[ArraySize];
  765. for(std::size_t i = 0; i < ArraySize; ++i){
  766. requested_sizes[i] = 4*i;
  767. }
  768. typename Allocator::size_type free_memory = a.get_free_memory();
  769. {
  770. for(int i = 0; true; ++i){
  771. multiallocation_chain chain;
  772. a.allocate_many(std::nothrow, requested_sizes, ArraySize, 1, chain);
  773. if(chain.empty())
  774. break;
  775. buffers.push_back(boost::move(chain));
  776. }
  777. for(int i = 0, max = (int)buffers.size(); i != max; ++i){
  778. a.deallocate_many(buffers[i]);
  779. }
  780. buffers.clear();
  781. bool ok = free_memory == a.get_free_memory() &&
  782. a.all_memory_deallocated() && a.check_sanity();
  783. if(!ok) return ok;
  784. }
  785. {
  786. for(int i = 0; true; ++i){
  787. multiallocation_chain chain;
  788. a.allocate_many(std::nothrow, i*4, ArraySize, chain);
  789. if(chain.empty())
  790. break;
  791. buffers.push_back(boost::move(chain));
  792. }
  793. for(int i = 0, max = (int)buffers.size(); i != max; ++i){
  794. a.deallocate_many(buffers[i]);
  795. }
  796. buffers.clear();
  797. bool ok = free_memory == a.get_free_memory() &&
  798. a.all_memory_deallocated() && a.check_sanity();
  799. if(!ok) return ok;
  800. }
  801. return true;
  802. }
  803. //This function calls all tests
  804. template<class Allocator>
  805. bool test_all_allocation(Allocator &a)
  806. {
  807. std::cout << "Starting test_allocation. Class: "
  808. << typeid(a).name() << std::endl;
  809. if(!test_allocation(a)){
  810. std::cout << "test_allocation_direct_deallocation failed. Class: "
  811. << typeid(a).name() << std::endl;
  812. return false;
  813. }
  814. std::cout << "Starting test_many_equal_allocation. Class: "
  815. << typeid(a).name() << std::endl;
  816. if(!test_many_equal_allocation(a)){
  817. std::cout << "test_many_equal_allocation failed. Class: "
  818. << typeid(a).name() << std::endl;
  819. return false;
  820. }
  821. std::cout << "Starting test_many_different_allocation. Class: "
  822. << typeid(a).name() << std::endl;
  823. if(!test_many_different_allocation(a)){
  824. std::cout << "test_many_different_allocation failed. Class: "
  825. << typeid(a).name() << std::endl;
  826. return false;
  827. }
  828. if(!test_many_deallocation(a)){
  829. std::cout << "test_many_deallocation failed. Class: "
  830. << typeid(a).name() << std::endl;
  831. return false;
  832. }
  833. std::cout << "Starting test_allocation_shrink. Class: "
  834. << typeid(a).name() << std::endl;
  835. if(!test_allocation_shrink(a)){
  836. std::cout << "test_allocation_shrink failed. Class: "
  837. << typeid(a).name() << std::endl;
  838. return false;
  839. }
  840. if(!test_allocation_shrink_and_expand(a)){
  841. std::cout << "test_allocation_shrink_and_expand failed. Class: "
  842. << typeid(a).name() << std::endl;
  843. return false;
  844. }
  845. std::cout << "Starting test_allocation_expand. Class: "
  846. << typeid(a).name() << std::endl;
  847. if(!test_allocation_expand(a)){
  848. std::cout << "test_allocation_expand failed. Class: "
  849. << typeid(a).name() << std::endl;
  850. return false;
  851. }
  852. std::cout << "Starting test_allocation_deallocation_expand. Class: "
  853. << typeid(a).name() << std::endl;
  854. if(!test_allocation_deallocation_expand(a)){
  855. std::cout << "test_allocation_deallocation_expand failed. Class: "
  856. << typeid(a).name() << std::endl;
  857. return false;
  858. }
  859. std::cout << "Starting test_allocation_with_reuse. Class: "
  860. << typeid(a).name() << std::endl;
  861. if(!test_allocation_with_reuse(a)){
  862. std::cout << "test_allocation_with_reuse failed. Class: "
  863. << typeid(a).name() << std::endl;
  864. return false;
  865. }
  866. std::cout << "Starting test_aligned_allocation. Class: "
  867. << typeid(a).name() << std::endl;
  868. if(!test_aligned_allocation(a)){
  869. std::cout << "test_aligned_allocation failed. Class: "
  870. << typeid(a).name() << std::endl;
  871. return false;
  872. }
  873. std::cout << "Starting test_continuous_aligned_allocation. Class: "
  874. << typeid(a).name() << std::endl;
  875. if(!test_continuous_aligned_allocation(a)){
  876. std::cout << "test_continuous_aligned_allocation failed. Class: "
  877. << typeid(a).name() << std::endl;
  878. return false;
  879. }
  880. std::cout << "Starting test_clear_free_memory. Class: "
  881. << typeid(a).name() << std::endl;
  882. if(!test_clear_free_memory(a)){
  883. std::cout << "test_clear_free_memory failed. Class: "
  884. << typeid(a).name() << std::endl;
  885. return false;
  886. }
  887. std::cout << "Starting test_grow_shrink_to_fit. Class: "
  888. << typeid(a).name() << std::endl;
  889. if(!test_grow_shrink_to_fit(a)){
  890. std::cout << "test_grow_shrink_to_fit failed. Class: "
  891. << typeid(a).name() << std::endl;
  892. return false;
  893. }
  894. return true;
  895. }
  896. }}} //namespace boost { namespace interprocess { namespace test {
  897. #include <boost/interprocess/detail/config_end.hpp>
  898. #endif //BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER