[project @ 2002-12-05 23:49:43 by mthomas]
[ghc-hetmet.git] / ghc / rts / Arena.c
1 /* -----------------------------------------------------------------------------
2    $Id: Arena.c,v 1.4 2002/07/28 02:31:11 sof Exp $ 
3    (c) The University of Glasgow 2001
4
5    Arena allocation.  Arenas provide fast memory allocation at the
6    expense of fine-grained recycling of storage: memory may be
7    only be returned to the system by freeing the entire arena, it
8    isn't possible to return individual objects within an arena.
9
10    Do not assume that sequentially allocated objects will be adjacent
11    in memory.
12    
13    Quirks: this allocator makes use of the RTS block allocator.  If
14    the current block doesn't have enough room for the requested
15    object, then a new block is allocated.  This means that allocating
16    large objects will tend to result in wasted space at the end of
17    each block.  In the worst case, half of the allocated space is
18    wasted.  This allocator is therefore best suited to situations in
19    which most allocations are small.
20    -------------------------------------------------------------------------- */
21
22 #include <stdlib.h>
23 #include "Rts.h"
24 #include "RtsUtils.h"
25 #include "BlockAlloc.h"
26 #include "Arena.h"
27
28 // Each arena struct is allocated using malloc().
29 struct _Arena {
30     bdescr *current;
31     StgWord *free;              // ptr to next free byte in current block
32     StgWord *lim;               // limit (== last free byte + 1)
33 };
34
35 // We like to keep track of how many blocks we've allocated for 
36 // Storage.c:memInventory().
37 static long arena_blocks = 0;
38
39 // Begin a new arena
40 Arena *
41 newArena( void )
42 {
43     Arena *arena;
44
45     arena = stgMallocBytes(sizeof(Arena), "newArena");
46     arena->current = allocBlock();
47     arena->current->link = NULL;
48     arena->free = arena->current->start;
49     arena->lim  = arena->current->start + BLOCK_SIZE_W;
50     arena_blocks++;
51
52     return arena;
53 }
54
55 // Allocate some memory in an arena
56 void  *
57 arenaAlloc( Arena *arena, size_t size )
58 {
59     void *p;
60     nat size_w;
61     nat req_blocks;
62     bdescr *bd;
63
64 // The minimum alignment of an allocated block.
65 #define MIN_ALIGN 8
66
67     // size of allocated block in words, rounded up to the nearest 
68     // alignment chunk.
69     size_w = ((size + MIN_ALIGN - 1) / MIN_ALIGN) * (MIN_ALIGN/sizeof(W_));
70
71     if ( arena->free + size_w < arena->lim ) {
72         // enough room in the current block...
73         p = arena->free;
74         arena->free += size_w;
75         return p;
76     } else {
77         // allocate a fresh block...
78         req_blocks =  (lnat)BLOCK_ROUND_UP(size_w*sizeof(W_)) / BLOCK_SIZE;
79         bd = allocGroup(req_blocks);
80         arena_blocks += req_blocks;
81
82         bd->gen_no  = 0;
83         bd->step    = NULL;
84         bd->flags   = 0;
85         bd->free    = bd->start;
86         bd->link    = arena->current;
87         arena->current = bd;
88         arena->free = bd->free + size_w;
89         arena->lim = bd->free + bd->blocks * BLOCK_SIZE_W;
90         return bd->start;
91     }
92 }
93
94 // Free an entire arena
95 void
96 arenaFree( Arena *arena )
97 {
98     bdescr *bd, *next;
99
100     for (bd = arena->current; bd != NULL; bd = next) {
101         next = bd->link;
102         arena_blocks -= bd->blocks;
103         ASSERT(arena_blocks >= 0);
104         freeGroup(bd);
105     }
106     free(arena);
107 }
108
109 unsigned long
110 arenaBlocks( void )
111 {
112     return arena_blocks;
113 }
114