/sparrowhawk/foundation/unit_tests/ESFBuddyAllocatorTest.cpp
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 24#ifndef ESF_BUDDY_ALLOCATOR_TEST_H 25#include <ESFBuddyAllocatorTest.h> 26#endif 27 28#ifndef ESTF_ASSERT_H 29#include <ESTFAssert.h> 30#endif 31 32#ifndef ESF_SYSTEM_ALLOCATOR_H 33#include <ESFSystemAllocator.h> 34#endif 35 36static const int Allocations = 160; 37static const bool Debug = false; 38static const int Iterations = 2000; 39 40ESFBuddyAllocatorTest::ESFBuddyAllocatorTest() : 41 _rand(), _allocator(17, ESFSystemAllocator::GetInstance()) { 42} 43 44ESFBuddyAllocatorTest::~ESFBuddyAllocatorTest() { 45} 46 47bool ESFBuddyAllocatorTest::run(ESTFResultCollector *collector) { 48 // 49 // This test case follows Knuth's test case for the Buddy System ( and 50 // other allocators ) in The Art of Computer Programming, Volume 1 51 // Fundamental Algorithms Third Edition, p. 146. 52 // 53 54 ESFError error; 55 int bytesAllocated = 0; 56 char buffer[256]; 57 58 error = _allocator.initialize(); 59 60 if (ESF_SUCCESS != error) { 61 ESFDescribeError(error, buffer, sizeof(buffer)); 62 63 ESTF_FAILURE( collector, buffer ); 64 ESTF_ERROR( collector, "Failed to initialize allocator" ); 65 66 return false; 67 } 68 69 struct allocation 70 { 71 int size; 72 int lifetime; 73 void *data; 74 }allocations[Allocations]; 75 76 memset( allocations, 0, sizeof( allocations ) ); 77 78 for ( int i = 0; i < Iterations; ++i ) 79 { 80 for ( int j = 0; j < Allocations; ++j ) 81 { 82 if ( 0 < allocations[j].size && allocations[j].lifetime == i ) 83 { 84 if ( Debug ) 85 { 86 cerr << "Freeing block of size " << allocations[j].size 87 << " at time " << i << endl; 88 } 89 90 char *data = ( char * ) allocations[j].data; 91 92 // Make sure no one else overwrote this block. 93 for ( int k = 0; k < allocations[j].size; ++k ) 94 { 95 ESTF_ASSERT( collector, ( i % 127 ) == data[k] ); 96 } 97 98 error = _allocator.deallocate( allocations[j].data ); 99 allocations[j].data = 0; 100 101 if ( ESF_SUCCESS != error ) 102 { 103 ESFDescribeError( error, buffer, sizeof( buffer ) ); 104 ESTF_FAILURE( collector, buffer ); 105 } 106 107 ESTF_ASSERT( collector, ESF_SUCCESS == error ); 108 ESTF_ASSERT( collector, ! allocations[j].data ); 109 110 bytesAllocated -= allocations[j].size; 111 112 allocations[j].size = 0; 113 allocations[j].lifetime = 0; 114 allocations[j].data = 0; 115 } 116 117 if ( 0 == allocations[j].size && 1 == _rand.generateRandom( 1, 4 ) ) 118 { 119 ESTF_ASSERT( collector, 0 == allocations[j].lifetime ); 120 ESTF_ASSERT( collector, 0 == allocations[j].data ); 121 122 allocations[j].size = generateAllocSize(); 123 allocations[j].lifetime = i + generateAllocLifetime(); 124 125 if ( Debug ) 126 { 127 cerr << "Allocating block of size " << allocations[j].size 128 << " at time " << i << " with lifetime: " 129 << allocations[j].lifetime << endl; 130 } 131 132 error = _allocator.allocate( &allocations[j].data, 133 allocations[j].size ); 134 135 // 136 // We allow failures after half of the allocators memory 137 // has been allocated. 138 // 139 if ( ( bytesAllocated < ( 1 << 16 ) ) || 140 allocations[j].data ) 141 { 142 if ( ESF_SUCCESS != error ) 143 { 144 ESFDescribeError( error, buffer, sizeof( buffer ) ); 145 ESTF_FAILURE( collector, buffer ); 146 } 147 148 ESTF_ASSERT( collector, ESF_SUCCESS == error ); 149 ESTF_ASSERT( collector, allocations[j].data ); 150 } 151 else 152 { 153 if ( ESF_OUT_OF_MEMORY != error ) 154 { 155 ESFDescribeError( error, buffer, sizeof( buffer ) ); 156 ESTF_FAILURE( collector, buffer ); 157 } 158 159 ESTF_ASSERT( collector, ESF_OUT_OF_MEMORY == error ); 160 } 161 162 if ( ! allocations[j].data ) 163 { 164 if ( Debug ) 165 { 166 cerr << "Failed to allocate block of size " 167 << allocations[j].size << " at time " << i 168 << " with lifetime: " 169 << allocations[j].lifetime << endl; 170 } 171 172 allocations[j].lifetime = 0; 173 allocations[j].size = 0; 174 } 175 else 176 { 177 // 178 // We will check this value when we free the block to 179 // make sure no one overwrote it. 180 // 181 memset( allocations[j].data, 182 allocations[j].lifetime % 127, 183 allocations[j].size ); 184 185 bytesAllocated += allocations[j].size; 186 } 187 188 if ( Debug ) 189 { 190 cerr << bytesAllocated << " out of " << ( 1 << 17 ) 191 << " bytes allocated\n"; 192 } 193 } 194 195 if ( Debug ) 196 { 197 int size =0; 198 199 for ( int k = 0; k < Allocations; ++k ) 200 { 201 size += allocations[k].size; 202 } 203 204 ESTF_ASSERT( collector, size == bytesAllocated ); 205 } 206 } 207 } 208 209 // Simulation mostly done, return everything to the allocator. 210 211 for ( int i = 0; i < Allocations; ++i ) 212 { 213 if ( 0 < allocations[i].size ) 214 { 215 if ( Debug ) 216 { 217 cerr << "Freeing block of size " << allocations[i].size 218 << " at cleanup stage\n"; 219 } 220 221 error = _allocator.deallocate( allocations[i].data ); 222 allocations[i].data = 0; 223 224 if ( ESF_SUCCESS != error ) 225 { 226 ESFDescribeError( error, buffer, sizeof( buffer ) ); 227 ESTF_FAILURE( collector, buffer ); 228 } 229 230 ESTF_ASSERT( collector, ESF_SUCCESS == error ); 231 ESTF_ASSERT( collector, ! allocations[i].data ); 232 233 allocations[i].size = 0; 234 allocations[i].lifetime = 0; 235 allocations[i].data = 0; 236 } 237 } 238 239 // 240 // The buddy allocator should have coalesced everything back into one 241 // big block, try a really big allocation. 242 // 243 244 error = _allocator.allocate( &allocations[0].data, 1 << 16 ); 245 246 if ( ESF_SUCCESS != error ) 247 { 248 ESFDescribeError( error, buffer, sizeof( buffer ) ); 249 ESTF_FAILURE( collector, buffer ); 250 } 251 252 ESTF_ASSERT( collector, ESF_SUCCESS == error ); 253 ESTF_ASSERT( collector, allocations[0].data ); 254 255 if ( allocations[0].data ) 256 { 257 memset( allocations[0].data, 'B', 1 << 16 ); 258 259 error = _allocator.destroy(); 260 261 ESTF_ASSERT( collector, ESF_IN_USE == error ); 262 263 if ( Debug ) 264 { 265 cerr << "Allocated big block of size " << ( 1 << 16 ) << endl; 266 } 267 268 error = _allocator.deallocate( allocations[0].data ); 269 allocations[0].data = 0; 270 271 if ( ESF_SUCCESS != error ) 272 { 273 ESFDescribeError( error, buffer, sizeof( buffer ) ); 274 ESTF_FAILURE( collector, buffer ); 275 } 276 277 ESTF_ASSERT( collector, ESF_SUCCESS == error ); 278 ESTF_ASSERT( collector, ! allocations[0].data ); 279 } 280 else 281 { 282 cerr << "Failed to alloc big block of size " << ( 1 << 16 ) << endl; 283 } 284 285 error = _allocator.destroy(); 286 287 if ( ESF_SUCCESS != error ) 288 { 289 ESFDescribeError( error, buffer, sizeof( buffer ) ); 290 ESTF_FAILURE( collector, buffer ); 291 ESTF_ERROR( collector, "Failed to destroy allocator" ); 292 return false; 293 } 294 295 ESTF_ASSERT( collector, ESF_SUCCESS == error ); 296 297 return true; 298} 299 300bool ESFBuddyAllocatorTest::setup() { 301 return true; 302} 303 304bool ESFBuddyAllocatorTest::tearDown() { 305 return true; 306} 307 308ESTFComponentPtr ESFBuddyAllocatorTest::clone() { 309 ESTFComponentPtr component(new ESFBuddyAllocatorTest()); 310 311 return component; 312} 313 314int ESFBuddyAllocatorTest::generateAllocSize() { 315 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, 316 16, 16, 32, 32 }; 317 318 static const int array2[22] = { 10, 12, 14, 16, 18, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 250, 500, 1000, 319 2000, 3000, 4000 }; 320 321 int uniformDeviate = _rand.generateRandom(1, 3); 322 323 switch (uniformDeviate) { 324 case 1: 325 return _rand.generateRandom(100, 2000); 326 327 case 2: 328 return array1[_rand.generateRandom(0, 31)]; 329 330 case 3: 331 return array2[_rand.generateRandom(0, 21)]; 332 } 333 334 return 10; 335} 336 337int ESFBuddyAllocatorTest::generateAllocLifetime() { 338 int uniformDeviate = _rand.generateRandom(1, 3); 339 340 switch (uniformDeviate) { 341 case 1: 342 return _rand.generateRandom(1, 10); 343 344 case 2: 345 return _rand.generateRandom(1, 100); 346 347 case 3: 348 return _rand.generateRandom(1, 1000); 349 } 350 351 return 10; 352}