source: soft/giet_vm/giet_libs/malloc.c @ 685

Last change on this file since 685 was 680, checked in by guerin, 9 years ago

malloc: use giet_tty_printf

  • Property svn:executable set to *
File size: 15.7 KB
Line 
1////////////////////////////////////////////////////////////////////////////////
2// File     : malloc.c
3// Date     : 05/03/2013
4// Author   : Jean-Baptiste Bréjon / alain greiner
5// Copyright (c) UPMC-LIP6
6////////////////////////////////////////////////////////////////////////////////
7
8#include "malloc.h"
9#include "stdio.h"
10#include "giet_config.h"
11
12// Global variables defining the heap descriptors array (one heap per cluster)
13giet_heap_t     heap[X_SIZE][Y_SIZE];
14
15// Macro returning the smallest power of 2 larger or equal to size value
16#define GET_SIZE_INDEX(size)                (size <= 0x00000001) ? 0  :\
17                                            (size <= 0x00000002) ? 1  :\
18                                            (size <= 0x00000004) ? 2  :\
19                                            (size <= 0x00000008) ? 3  :\
20                                            (size <= 0x00000010) ? 4  :\
21                                            (size <= 0x00000020) ? 5  :\
22                                            (size <= 0x00000040) ? 6  :\
23                                            (size <= 0x00000080) ? 7  :\
24                                            (size <= 0x00000100) ? 8  :\
25                                            (size <= 0x00000200) ? 9  :\
26                                            (size <= 0x00000400) ? 10 :\
27                                            (size <= 0x00000800) ? 11 :\
28                                            (size <= 0x00001000) ? 12 :\
29                                            (size <= 0x00002000) ? 13 :\
30                                            (size <= 0x00004000) ? 14 :\
31                                            (size <= 0x00008000) ? 15 :\
32                                            (size <= 0x00010000) ? 16 :\
33                                            (size <= 0x00020000) ? 17 :\
34                                            (size <= 0x00040000) ? 18 :\
35                                            (size <= 0x00080000) ? 19 :\
36                                            (size <= 0x00100000) ? 20 :\
37                                            (size <= 0x00200000) ? 21 :\
38                                            (size <= 0x00400000) ? 22 :\
39                                            (size <= 0x00800000) ? 23 :\
40                                            (size <= 0x01000000) ? 24 :\
41                                            (size <= 0x02000000) ? 25 :\
42                                            (size <= 0x04000000) ? 26 :\
43                                            (size <= 0x08000000) ? 27 :\
44                                            (size <= 0x10000000) ? 28 :\
45                                            (size <= 0x20000000) ? 29 :\
46                                            (size <= 0x40000000) ? 30 :\
47                                            (size <= 0x80000000) ? 31 :\
48                                                                   32
49////////////////////////////////////////
50void display_free_array( unsigned int x,
51                         unsigned int y )
52{
53    unsigned int next;
54    unsigned int id;
55    unsigned int iter;
56
57    giet_tty_printf("\nUser Heap[%d][%d] base = %x / size = %x\n", x , y , 
58                   heap[x][y].heap_base, heap[x][y].heap_size );
59    for ( id = 0 ; id < 32 ; id++ )
60    { 
61        next = heap[x][y].free[id];
62        giet_tty_printf(" - free[%d] = " , id );
63        iter = 0;
64        while ( next != 0 )
65        {
66            giet_tty_printf("%x | ", next );
67            next = (*(unsigned int*)next);
68            iter++;
69        }
70        giet_tty_printf("0\n");
71    }
72}  // end display_free_array()
73
74
75
76////////////////////////////////
77void heap_init( unsigned int x,
78                unsigned int y )
79{
80    unsigned int heap_base;        // heap segment base
81    unsigned int heap_size;        // heap segment size
82    unsigned int heap_index;       // size_index in free[array]
83
84    unsigned int alloc_base;       // alloc[] array base
85    unsigned int alloc_size;       // alloc[] array size
86    unsigned int alloc_index;      // size_index in alloc[array]
87
88    unsigned int index;            // iterator
89
90    // get heap_base, heap size, and heap index
91    giet_heap_info( &heap_base, &heap_size, x, y );
92    heap_index = GET_SIZE_INDEX( heap_size );
93
94#if GIET_DEBUG_USER_MALLOC
95giet_tty_printf("\n[DEBUG USER_MALLOC] Starting Heap[%d][%d] initialisation /"
96                " base = %x / size = %x\n", x, y, heap_base, heap_size );
97#endif
98
99    // checking heap segment constraints
100    if ( heap_size == 0 )                                    // heap segment exist
101    {
102        giet_exit("ERROR in malloc() : heap not found \n");
103    }
104    if ( heap_size != (1<<heap_index) )                      // heap size power of 2
105    {
106        giet_exit("ERROR in malloc() : heap size must be power of 2\n");
107    }
108    if ( heap_base % heap_size )                             // heap segment aligned
109    {
110        giet_exit("ERROR in malloc() : heap segment must be aligned\n");
111    }
112
113    // compute size of block containin alloc[] array
114    alloc_size = heap_size / MIN_BLOCK_SIZE;
115    if ( alloc_size < MIN_BLOCK_SIZE) alloc_size = MIN_BLOCK_SIZE;
116
117    // get index for the corresponding block
118    alloc_index = GET_SIZE_INDEX( alloc_size );
119
120    // compute alloc[] array base address
121    alloc_base = heap_base + heap_size - alloc_size;
122
123    // reset the free[] array
124    for ( index = 0 ; index < 32 ; index++ )
125    {
126        heap[x][y].free[index] = 0;
127    }
128
129    // reset the alloc_size array
130    unsigned int   word;
131    unsigned int*  tab = (unsigned int*)alloc_base;
132    for ( word = 0 ; word < (alloc_size>>2) ; word++ )  tab[word] = 0;
133 
134    // split the heap into various sizes blocks,
135    // initializes the free[] array and NEXT pointers
136    // base is the block base address
137    unsigned int   base = heap_base;
138    unsigned int*  ptr;
139    for ( index = heap_index-1 ; index >= alloc_index ; index-- )
140    {
141        heap[x][y].free[index] = base;
142        ptr = (unsigned int*)base;
143        *ptr = 0;
144        base = base + (1<<index);
145    }
146
147    heap[x][y].init       = HEAP_INITIALIZED;
148    heap[x][y].x          = x;
149    heap[x][y].y          = y;
150    heap[x][y].heap_base  = heap_base;
151    heap[x][y].heap_size  = heap_size;
152    heap[x][y].alloc_size = alloc_size;
153    heap[x][y].alloc_base = alloc_base;
154
155    lock_init( &heap[x][y].lock );
156
157#if GIET_DEBUG_USER_MALLOC
158giet_tty_printf("\n[DEBUG USER_MALLOC] Completing Heap[%d][%d] initialisation\n", x, y );
159display_free_array(x,y);
160#endif
161               
162}  // end heap_init()
163
164////////////////////////////////////////////
165unsigned int split_block( giet_heap_t* heap,
166                          unsigned int vaddr, 
167                          unsigned int searched_index,
168                          unsigned int requested_index )
169{
170    // push the upper half block into free[searched_index-1]
171    unsigned int* new            = (unsigned int*)(vaddr + (1<<(searched_index-1)));
172    *new                         = heap->free[searched_index-1]; 
173    heap->free[searched_index-1] = (unsigned int)new;
174       
175    if ( searched_index == requested_index + 1 )  // terminal case: return lower half block
176    {
177        return vaddr;
178    }
179    else            // non terminal case : lower half block must be split again
180    {                               
181        return split_block( heap, vaddr, searched_index-1, requested_index );
182    }
183} // end split_block()
184
185//////////////////////////////////////////
186unsigned int get_block( giet_heap_t* heap,
187                        unsigned int searched_index,
188                        unsigned int requested_index )
189{
190    // test terminal case
191    if ( (1<<searched_index) > heap->heap_size )  // failure : return a NULL value
192    {
193        return 0;
194    }
195    else                            // search a block in free[searched_index]
196    {
197        unsigned int vaddr = heap->free[searched_index];
198        if ( vaddr == 0 )     // block not found : search in free[searched_index+1]
199        {
200            return get_block( heap, searched_index+1, requested_index );
201        }
202        else                // block found : pop it from free[searched_index]
203        {
204            // pop the block from free[searched_index]
205            unsigned int next = *((unsigned int*)vaddr); 
206            heap->free[searched_index] = next;
207           
208            // test if the block must be split
209            if ( searched_index == requested_index )  // no split required
210            {
211                return vaddr;
212            }
213            else                                      // split is required
214            {
215                return split_block( heap, vaddr, searched_index, requested_index );
216            }
217        } 
218    }
219} // end get_block()
220
221////////////////////////////////////////
222void * remote_malloc( unsigned int size,
223                      unsigned int x,
224                      unsigned int y ) 
225{
226
227#if GIET_DEBUG_USER_MALLOC
228giet_tty_printf("\n[DEBUG USER_MALLOC] request for Heap[%d][%d] / size = %x\n", 
229                 x, y, size );
230#endif
231
232    // checking arguments
233    if (size == 0) 
234    {
235        giet_exit("\nERROR in remote_malloc() : requested size = 0 \n");
236    }
237    if ( x >= X_SIZE )
238    {
239        giet_exit("\nERROR in remote_malloc() : x coordinate too large\n");
240    }
241    if ( y >= Y_SIZE )
242    {
243        giet_exit("\nERROR in remote_malloc() : y coordinate too large\n");
244    }
245
246    // checking initialization
247    if ( heap[x][y].init != HEAP_INITIALIZED )
248    {
249        giet_exit("\nERROR in remote_malloc() : heap not initialized\n");
250    }
251
252    // normalize size
253    if ( size < MIN_BLOCK_SIZE ) size = MIN_BLOCK_SIZE;
254
255    // compute requested_index for the free[] array
256    unsigned int requested_index = GET_SIZE_INDEX( size );
257
258    // take the lock protecting access to heap[x][y]
259    lock_acquire( &heap[x][y].lock );
260
261    // call the recursive function get_block
262    unsigned int base = get_block( &heap[x][y], 
263                                   requested_index, 
264                                   requested_index );
265
266    // check block found
267    if ( base == 0 )
268    {
269        lock_release( &heap[x][y].lock );
270        giet_exit("\nERROR in remote_malloc() : no more space\n");
271    }
272
273    // compute pointer in alloc[] array
274    unsigned offset    = (base - heap[x][y].heap_base) / MIN_BLOCK_SIZE;
275    unsigned char* ptr = (unsigned char*)(heap[x][y].alloc_base + offset);
276
277    // check the alloc[] array
278    if ( *ptr != 0 )
279    {
280        lock_release( &heap[x][y].lock );
281        giet_exit("\nERROR in remote_malloc() : block already allocated ???\n");
282    }
283
284    // update alloc_array
285    *ptr = requested_index;
286
287    // release the lock
288    lock_release( &heap[x][y].lock );
289 
290#if GIET_DEBUG_USER_MALLOC
291giet_tty_printf("\n[DEBUG USER_MALLOC] allocated block from heap[%d][%d] : "
292                "base = %x / size = %x\n", x , y , base , size );
293display_free_array(x,y);
294#endif
295
296    return (void*)base;
297
298} // end remote_malloc()
299
300
301//////////////////////////////////
302void * malloc( unsigned int size )
303{
304    // get cluster coordinates
305    unsigned int    x;
306    unsigned int    y;
307    unsigned int    lpid;
308    giet_proc_xyp( &x, &y, &lpid );
309
310    return remote_malloc( size, x, y );
311} 
312
313///////////////////////////////////////////
314void update_free_array( giet_heap_t* heap,
315                        unsigned int base,
316                        unsigned int size_index )
317{
318    // This recursive function try to merge the released block
319    // with the companion block if this companion block is free.
320    // This companion has the same size, and almost the same address
321    // (only one address bit is different)
322    // - If the companion is not in free[size_index],
323    //   the released block is pushed in free[size_index].
324    // - If the companion is found, it is evicted from free[size_index]
325    //   and the merged bloc is pushed in the free[size_index+1].
326
327
328    // compute released block size
329    unsigned int size = 1<<size_index;
330
331    // compute companion block and merged block base addresses
332    unsigned int companion_base; 
333    unsigned int merged_base; 
334
335    if ( (base & size) == 0 )   // the released block is aligned on (2*size)
336    {
337        companion_base  = base + size;
338        merged_base     = base;
339    }
340    else
341    {
342        companion_base  = base - size;
343        merged_base     = base - size;
344    }
345
346    // scan all blocks in free[size_index]
347    // the iter & prev variables are actually addresses
348    unsigned int  found = 0;
349    unsigned int  iter  = heap->free[size_index];
350    unsigned int  prev  = (unsigned int)&heap->free[size_index];
351    while ( iter ) 
352    {
353        if ( iter == companion_base ) 
354        {
355            found = 1;
356            break;
357        }
358        prev = iter;
359        iter = *(unsigned int*)iter;
360    }
361
362    if ( found == 0 )  // Companion not found => push in free[size_index] 
363    {
364        *(unsigned int*)base   = heap->free[size_index];
365        heap->free[size_index] = base;
366    }
367    else               // Companion found : merge
368    {
369        // evict the searched block from free[size_index]
370        *(unsigned int*)prev = *(unsigned int*)iter;
371
372        // call the update_free() function for free[size_index+1]
373        update_free_array( heap, merged_base , size_index+1 );
374    }
375}
376
377//////////////////////
378void free( void* ptr )
379{
380    // get the cluster coordinate from ptr value
381    unsigned int x;
382    unsigned int y;
383    giet_get_xy( ptr, &x, &y );
384
385#if GIET_DEBUG_USER_MALLOC
386giet_tty_printf("\n[DEBUG USER_MALLOC] Free for vaddr = %x / x = %d / y = %d\n",
387                 (unsigned int)ptr, x, y );
388#endif
389
390    // check ptr value
391    unsigned int base = (unsigned int)ptr;
392    if ( (base < heap[x][y].heap_base) || 
393         (base >= (heap[x][y].heap_base + heap[x][y].heap_size)) )
394    {
395        giet_exit("ERROR in free() : illegal pointer for released block");
396    }
397 
398    // get the lock protecting heap[x][y]
399    lock_acquire( &heap[x][y].lock );
400
401    // compute released block index in alloc[] array
402    unsigned index = (base - heap[x][y].heap_base ) / MIN_BLOCK_SIZE;
403 
404    // get the released block size_index
405    unsigned char* pchar      = (unsigned char*)(heap[x][y].alloc_base + index);
406    unsigned int   size_index = (unsigned int)*pchar;
407
408    // check block allocation
409    if ( size_index == 0 )
410    {
411        lock_release( &heap[x][y].lock );
412        giet_exit("\nERROR in free() : released block not allocated ???\n");
413    }
414
415    // check released block alignment
416    if ( base % (1 << size_index) )
417    {
418        giet_exit("\nERROR in free() : released block not aligned\n");
419    }
420
421    // call the recursive function update_free_array()
422    update_free_array( &heap[x][y], base, size_index ); 
423
424    // release the lock
425    lock_release( &heap[x][y].lock );
426
427#if GIET_DEBUG_USER_MALLOC
428display_free_array(x,y);
429#endif
430
431} // end free()
432
433//////////////////////
434// reference: http://stackoverflow.com/a/6563989/4244300
435void * almalloc( unsigned int align, unsigned int size )
436{
437    unsigned int total_size;
438    void* ptr;
439
440    // check if align is a power of two
441    if ( !align || (align & (align - 1)) )
442        return NULL;
443
444    // reserve memory for data + offset + book-keeping
445    total_size = size + align + sizeof(void*);
446    ptr = malloc( total_size );
447
448    if ( ptr )
449    {
450        void* start = ptr;
451        void** book;
452
453        // find aligned ptr
454        ptr += sizeof(void*);
455        ptr += align - ((unsigned int)ptr % align);
456
457        // keep original ptr just before the actual data
458        book = ptr - sizeof(void*);
459        *book = start;
460    }
461
462    return ptr;
463}
464
465//////////////////////
466void alfree( void* ptr )
467{
468    if ( ptr )
469    {
470        void** book = ptr - sizeof(void*);
471        free(*book);
472    }
473}
474
475// Local Variables:
476// tab-width: 4
477// c-basic-offset: 4
478// c-file-offsets:((innamespace . 0)(inline-open . 0))
479// indent-tabs-mode: nil
480// End:
481// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
482
483
484
Note: See TracBrowser for help on using the repository browser.