PageRenderTime 69ms CodeModel.GetById 49ms app.highlight 16ms RepoModel.GetById 0ms app.codeStats 0ms

/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
 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}