b3fa13b0bca2c170cf644890f57a8610fb33e4df
[ghc-hetmet.git] / rts / sm / MBlock.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team 1998-2008
4  *
5  * MegaBlock Allocator Interface.  This file contains all the dirty
6  * architecture-dependent hackery required to get a chunk of aligned
7  * memory from the operating system.
8  *
9  * ---------------------------------------------------------------------------*/
10
11 #include "PosixSource.h"
12
13 #include "Rts.h"
14 #include "RtsUtils.h"
15 #include "MBlock.h"
16 #include "BlockAlloc.h"
17 #include "Trace.h"
18 #include "OSMem.h"
19
20 #include <string.h>
21
22 lnat mblocks_allocated = 0;
23 lnat mpc_misses = 0;
24
25 /* -----------------------------------------------------------------------------
26    The MBlock Map: provides our implementation of HEAP_ALLOCED()
27    -------------------------------------------------------------------------- */
28
29 #if SIZEOF_VOID_P == 4
30 StgWord8 mblock_map[MBLOCK_MAP_SIZE]; // initially all zeros
31
32 static void
33 markHeapAlloced(void *p)
34 {
35     mblock_map[MBLOCK_MAP_ENTRY(p)] = 1;
36 }
37
38 #elif SIZEOF_VOID_P == 8
39
40 MBlockMap **mblock_maps = NULL;
41
42 nat mblock_map_count = 0;
43
44 MbcCacheLine mblock_cache[MBC_ENTRIES];
45
46 static MBlockMap *
47 findMBlockMap(void *p)
48 {
49     nat i;
50     StgWord32 hi = (StgWord32) (((StgWord)p) >> 32);
51     for( i = 0; i < mblock_map_count; i++ )
52     {
53         if(mblock_maps[i]->addrHigh32 == hi)
54         {
55             return mblock_maps[i];
56         }
57     }
58     return NULL;
59 }
60
61 StgBool HEAP_ALLOCED_miss(StgWord mblock, void *p)
62 {
63     MBlockMap *map;
64     MBlockMapLine value;
65     nat entry_no;
66     
67     entry_no = mblock & (MBC_ENTRIES-1);
68
69     map = findMBlockMap(p);
70     if (map)
71     {
72         mpc_misses++;
73         value = map->lines[MBLOCK_MAP_LINE(p)];
74         mblock_cache[entry_no] = (mblock<<1) | value;
75         return value;
76     }
77     else
78     {
79         mblock_cache[entry_no] = (mblock<<1);
80         return 0;
81     }
82 }
83
84 static void
85 markHeapAlloced(void *p)
86 {
87     MBlockMap *map = findMBlockMap(p);
88     if(map == NULL)
89     {
90         mblock_map_count++;
91         mblock_maps = realloc(mblock_maps,
92                               sizeof(MBlockMap*) * mblock_map_count);
93         map = mblock_maps[mblock_map_count-1] = 
94             stgMallocBytes(sizeof(MBlockMap),"markHeapAlloced");
95         memset(map,0,sizeof(MBlockMap));
96         map->addrHigh32 = (StgWord32) (((StgWord)p) >> 32);
97     }
98
99     map->lines[MBLOCK_MAP_LINE(p)] = 1;
100
101     {
102         StgWord mblock;
103         nat entry_no;
104         
105         mblock   = (StgWord)p >> MBLOCK_SHIFT;
106         entry_no = mblock & (MBC_ENTRIES-1);
107         mblock_cache[entry_no] = (mblock << 1) + 1;
108     }
109 }
110 #endif
111
112 /* ----------------------------------------------------------------------------
113    Debugging code for traversing the allocated MBlocks
114    
115    This is used for searching for lost blocks when a memory leak is
116    detected; see Blocks.c:findUnmarkedBlock().
117    ------------------------------------------------------------------------ */
118
119 #ifdef DEBUG
120
121 #if SIZEOF_VOID_P == 4
122
123 STATIC_INLINE
124 void * mapEntryToMBlock(nat i)
125 {
126     return (void *)((StgWord)i << MBLOCK_SHIFT);
127 }
128
129 void * getFirstMBlock(void)
130 {
131     nat i;
132
133     for (i = 0; i < MBLOCK_MAP_SIZE; i++) {
134         if (mblock_map[i]) return mapEntryToMBlock(i);
135     }
136     return NULL;
137 }
138
139 void * getNextMBlock(void *mblock)
140 {
141     nat i;
142
143     for (i = MBLOCK_MAP_ENTRY(mblock) + 1; i < MBLOCK_MAP_SIZE; i++) {
144         if (mblock_map[i]) return mapEntryToMBlock(i);
145     }
146     return NULL;
147 }
148
149 #elif SIZEOF_VOID_P == 8
150
151 void * getNextMBlock(void *p)
152 {
153     MBlockMap *map;
154     nat off, j;
155     nat line_no;
156     MBlockMapLine line;
157
158     for (j = 0; j < mblock_map_count; j++)  {
159         map = mblock_maps[j];
160         if (map->addrHigh32 == (StgWord)p >> 32) break;
161     }
162     if (j == mblock_map_count) return NULL;
163
164     for (; j < mblock_map_count; j++) {
165         map = mblock_maps[j];
166         if (map->addrHigh32 == (StgWord)p >> 32) {
167             line_no = MBLOCK_MAP_LINE(p);
168             off  = (((StgWord)p >> MBLOCK_SHIFT) & (MBC_LINE_SIZE-1)) + 1;
169             // + 1 because we want the *next* mblock
170         } else {
171             line_no = 0; off = 0;
172         }
173         for (; line_no < MBLOCK_MAP_ENTRIES; line_no++) {
174             line = map->lines[line_no];
175             for (; off < MBC_LINE_SIZE; off++) {
176                 if (line & (1<<off)) {
177                     return (void*)(((StgWord)map->addrHigh32 << 32) + 
178                                    line_no * MBC_LINE_SIZE * MBLOCK_SIZE +
179                                    off * MBLOCK_SIZE);
180                 }
181             }
182             off = 0;
183         }
184     }
185     return NULL;
186 }
187
188 void * getFirstMBlock(void)
189 {
190     MBlockMap *map = mblock_maps[0];
191     nat line_no, off;
192     MbcCacheLine line;
193
194     for (line_no = 0; line_no < MBLOCK_MAP_ENTRIES; line_no++) {
195         line = map->lines[line_no];
196         if (line) {
197             for (off = 0; off < MBC_LINE_SIZE; off++) {
198                 if (line & (1<<off)) {
199                     return (void*)(((StgWord)map->addrHigh32 << 32) + 
200                                    line_no * MBC_LINE_SIZE * MBLOCK_SIZE +
201                                    off * MBLOCK_SIZE);
202                 }
203             }
204         }
205     }
206     return NULL;
207 }
208
209 #endif // SIZEOF_VOID_P
210
211 #endif // DEBUG
212
213 /* -----------------------------------------------------------------------------
214    Allocate new mblock(s)
215    -------------------------------------------------------------------------- */
216
217 void *
218 getMBlock(void)
219 {
220   return getMBlocks(1);
221 }
222
223 // The external interface: allocate 'n' mblocks, and return the
224 // address.
225
226 void *
227 getMBlocks(nat n)
228 {
229     nat i;
230     void *ret;
231
232     ret = osGetMBlocks(n);
233
234     debugTrace(DEBUG_gc, "allocated %d megablock(s) at %p",n,ret);
235     
236     // fill in the table
237     for (i = 0; i < n; i++) {
238         markHeapAlloced( ret + i * MBLOCK_SIZE );
239     }
240     
241     mblocks_allocated += n;
242
243     return ret;
244 }
245
246 void
247 freeAllMBlocks(void)
248 {
249     osFreeAllMBlocks();
250 }
251
252 void
253 initMBlocks(void)
254 {
255     osMemInit();
256 #if SIZEOF_VOID_P == 8
257     memset(mblock_cache,0xff,sizeof(mblock_cache));
258 #endif
259 }