/sparrowhawk/foundation/unit_tests/ESFBuddyAllocatorTest.cpp

http://github.com/jtblatt/duderino · C++ · 352 lines · 238 code · 73 blank · 41 comment · 53 complexity · b4ba40b49d5d8f889319251621d6384e MD5 · raw file

  1. /** @file ESFBuddyAllocatorTest.cpp
  2. * @brief ESFBuddyAllocatorTest is the unit test for ESFBuddyAllocator.
  3. *
  4. * Copyright 2005 Joshua Blatt, Yahoo! Inc.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * $Author: blattj $
  19. * $Date: 2009/05/25 21:51:14 $
  20. * $Name: $
  21. * $Revision: 1.3 $
  22. */
  23. #ifndef ESF_BUDDY_ALLOCATOR_TEST_H
  24. #include <ESFBuddyAllocatorTest.h>
  25. #endif
  26. #ifndef ESTF_ASSERT_H
  27. #include <ESTFAssert.h>
  28. #endif
  29. #ifndef ESF_SYSTEM_ALLOCATOR_H
  30. #include <ESFSystemAllocator.h>
  31. #endif
  32. static const int Allocations = 160;
  33. static const bool Debug = false;
  34. static const int Iterations = 2000;
  35. ESFBuddyAllocatorTest::ESFBuddyAllocatorTest() :
  36. _rand(), _allocator(17, ESFSystemAllocator::GetInstance()) {
  37. }
  38. ESFBuddyAllocatorTest::~ESFBuddyAllocatorTest() {
  39. }
  40. bool ESFBuddyAllocatorTest::run(ESTFResultCollector *collector) {
  41. //
  42. // This test case follows Knuth's test case for the Buddy System ( and
  43. // other allocators ) in The Art of Computer Programming, Volume 1
  44. // Fundamental Algorithms Third Edition, p. 146.
  45. //
  46. ESFError error;
  47. int bytesAllocated = 0;
  48. char buffer[256];
  49. error = _allocator.initialize();
  50. if (ESF_SUCCESS != error) {
  51. ESFDescribeError(error, buffer, sizeof(buffer));
  52. ESTF_FAILURE( collector, buffer );
  53. ESTF_ERROR( collector, "Failed to initialize allocator" );
  54. return false;
  55. }
  56. struct allocation
  57. {
  58. int size;
  59. int lifetime;
  60. void *data;
  61. }allocations[Allocations];
  62. memset( allocations, 0, sizeof( allocations ) );
  63. for ( int i = 0; i < Iterations; ++i )
  64. {
  65. for ( int j = 0; j < Allocations; ++j )
  66. {
  67. if ( 0 < allocations[j].size && allocations[j].lifetime == i )
  68. {
  69. if ( Debug )
  70. {
  71. cerr << "Freeing block of size " << allocations[j].size
  72. << " at time " << i << endl;
  73. }
  74. char *data = ( char * ) allocations[j].data;
  75. // Make sure no one else overwrote this block.
  76. for ( int k = 0; k < allocations[j].size; ++k )
  77. {
  78. ESTF_ASSERT( collector, ( i % 127 ) == data[k] );
  79. }
  80. error = _allocator.deallocate( allocations[j].data );
  81. allocations[j].data = 0;
  82. if ( ESF_SUCCESS != error )
  83. {
  84. ESFDescribeError( error, buffer, sizeof( buffer ) );
  85. ESTF_FAILURE( collector, buffer );
  86. }
  87. ESTF_ASSERT( collector, ESF_SUCCESS == error );
  88. ESTF_ASSERT( collector, ! allocations[j].data );
  89. bytesAllocated -= allocations[j].size;
  90. allocations[j].size = 0;
  91. allocations[j].lifetime = 0;
  92. allocations[j].data = 0;
  93. }
  94. if ( 0 == allocations[j].size && 1 == _rand.generateRandom( 1, 4 ) )
  95. {
  96. ESTF_ASSERT( collector, 0 == allocations[j].lifetime );
  97. ESTF_ASSERT( collector, 0 == allocations[j].data );
  98. allocations[j].size = generateAllocSize();
  99. allocations[j].lifetime = i + generateAllocLifetime();
  100. if ( Debug )
  101. {
  102. cerr << "Allocating block of size " << allocations[j].size
  103. << " at time " << i << " with lifetime: "
  104. << allocations[j].lifetime << endl;
  105. }
  106. error = _allocator.allocate( &allocations[j].data,
  107. allocations[j].size );
  108. //
  109. // We allow failures after half of the allocators memory
  110. // has been allocated.
  111. //
  112. if ( ( bytesAllocated < ( 1 << 16 ) ) ||
  113. allocations[j].data )
  114. {
  115. if ( ESF_SUCCESS != error )
  116. {
  117. ESFDescribeError( error, buffer, sizeof( buffer ) );
  118. ESTF_FAILURE( collector, buffer );
  119. }
  120. ESTF_ASSERT( collector, ESF_SUCCESS == error );
  121. ESTF_ASSERT( collector, allocations[j].data );
  122. }
  123. else
  124. {
  125. if ( ESF_OUT_OF_MEMORY != error )
  126. {
  127. ESFDescribeError( error, buffer, sizeof( buffer ) );
  128. ESTF_FAILURE( collector, buffer );
  129. }
  130. ESTF_ASSERT( collector, ESF_OUT_OF_MEMORY == error );
  131. }
  132. if ( ! allocations[j].data )
  133. {
  134. if ( Debug )
  135. {
  136. cerr << "Failed to allocate block of size "
  137. << allocations[j].size << " at time " << i
  138. << " with lifetime: "
  139. << allocations[j].lifetime << endl;
  140. }
  141. allocations[j].lifetime = 0;
  142. allocations[j].size = 0;
  143. }
  144. else
  145. {
  146. //
  147. // We will check this value when we free the block to
  148. // make sure no one overwrote it.
  149. //
  150. memset( allocations[j].data,
  151. allocations[j].lifetime % 127,
  152. allocations[j].size );
  153. bytesAllocated += allocations[j].size;
  154. }
  155. if ( Debug )
  156. {
  157. cerr << bytesAllocated << " out of " << ( 1 << 17 )
  158. << " bytes allocated\n";
  159. }
  160. }
  161. if ( Debug )
  162. {
  163. int size =0;
  164. for ( int k = 0; k < Allocations; ++k )
  165. {
  166. size += allocations[k].size;
  167. }
  168. ESTF_ASSERT( collector, size == bytesAllocated );
  169. }
  170. }
  171. }
  172. // Simulation mostly done, return everything to the allocator.
  173. for ( int i = 0; i < Allocations; ++i )
  174. {
  175. if ( 0 < allocations[i].size )
  176. {
  177. if ( Debug )
  178. {
  179. cerr << "Freeing block of size " << allocations[i].size
  180. << " at cleanup stage\n";
  181. }
  182. error = _allocator.deallocate( allocations[i].data );
  183. allocations[i].data = 0;
  184. if ( ESF_SUCCESS != error )
  185. {
  186. ESFDescribeError( error, buffer, sizeof( buffer ) );
  187. ESTF_FAILURE( collector, buffer );
  188. }
  189. ESTF_ASSERT( collector, ESF_SUCCESS == error );
  190. ESTF_ASSERT( collector, ! allocations[i].data );
  191. allocations[i].size = 0;
  192. allocations[i].lifetime = 0;
  193. allocations[i].data = 0;
  194. }
  195. }
  196. //
  197. // The buddy allocator should have coalesced everything back into one
  198. // big block, try a really big allocation.
  199. //
  200. error = _allocator.allocate( &allocations[0].data, 1 << 16 );
  201. if ( ESF_SUCCESS != error )
  202. {
  203. ESFDescribeError( error, buffer, sizeof( buffer ) );
  204. ESTF_FAILURE( collector, buffer );
  205. }
  206. ESTF_ASSERT( collector, ESF_SUCCESS == error );
  207. ESTF_ASSERT( collector, allocations[0].data );
  208. if ( allocations[0].data )
  209. {
  210. memset( allocations[0].data, 'B', 1 << 16 );
  211. error = _allocator.destroy();
  212. ESTF_ASSERT( collector, ESF_IN_USE == error );
  213. if ( Debug )
  214. {
  215. cerr << "Allocated big block of size " << ( 1 << 16 ) << endl;
  216. }
  217. error = _allocator.deallocate( allocations[0].data );
  218. allocations[0].data = 0;
  219. if ( ESF_SUCCESS != error )
  220. {
  221. ESFDescribeError( error, buffer, sizeof( buffer ) );
  222. ESTF_FAILURE( collector, buffer );
  223. }
  224. ESTF_ASSERT( collector, ESF_SUCCESS == error );
  225. ESTF_ASSERT( collector, ! allocations[0].data );
  226. }
  227. else
  228. {
  229. cerr << "Failed to alloc big block of size " << ( 1 << 16 ) << endl;
  230. }
  231. error = _allocator.destroy();
  232. if ( ESF_SUCCESS != error )
  233. {
  234. ESFDescribeError( error, buffer, sizeof( buffer ) );
  235. ESTF_FAILURE( collector, buffer );
  236. ESTF_ERROR( collector, "Failed to destroy allocator" );
  237. return false;
  238. }
  239. ESTF_ASSERT( collector, ESF_SUCCESS == error );
  240. return true;
  241. }
  242. bool ESFBuddyAllocatorTest::setup() {
  243. return true;
  244. }
  245. bool ESFBuddyAllocatorTest::tearDown() {
  246. return true;
  247. }
  248. ESTFComponentPtr ESFBuddyAllocatorTest::clone() {
  249. ESTFComponentPtr component(new ESFBuddyAllocatorTest());
  250. return component;
  251. }
  252. int ESFBuddyAllocatorTest::generateAllocSize() {
  253. static const int array1[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4,
  254. 16, 16, 32, 32 };
  255. static const int array2[22] = { 10, 12, 14, 16, 18, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 250, 500, 1000,
  256. 2000, 3000, 4000 };
  257. int uniformDeviate = _rand.generateRandom(1, 3);
  258. switch (uniformDeviate) {
  259. case 1:
  260. return _rand.generateRandom(100, 2000);
  261. case 2:
  262. return array1[_rand.generateRandom(0, 31)];
  263. case 3:
  264. return array2[_rand.generateRandom(0, 21)];
  265. }
  266. return 10;
  267. }
  268. int ESFBuddyAllocatorTest::generateAllocLifetime() {
  269. int uniformDeviate = _rand.generateRandom(1, 3);
  270. switch (uniformDeviate) {
  271. case 1:
  272. return _rand.generateRandom(1, 10);
  273. case 2:
  274. return _rand.generateRandom(1, 100);
  275. case 3:
  276. return _rand.generateRandom(1, 1000);
  277. }
  278. return 10;
  279. }