llvm.org GIT mirror llvm / d105a87
Change implementation so that variable sized slabs are used to allow arbitrary sized array allocations git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@7663 91177308-0d34-0410-b5e6-96231b3b80d8 Sumant Kowshik 17 years ago
1 changed file(s) with 202 addition(s) and 76 deletion(s). Raw diff Collapse all Expand all
0 #include
1 #include
12 #include
23
34 #undef assert
45 #define assert(X)
56
67
7 #define NODES_PER_SLAB 65536
8 /* In the current implementation, each slab in the pool has NODES_PER_SLAB
9 * nodes unless the isSingleArray flag is set in which case it contains a
10 * single array of size ArraySize. Small arrays (size <= NODES_PER_SLAB) are
11 * still allocated in the slabs of size NODES_PER_SLAB
12 */
13 #define NODES_PER_SLAB 512
814
915 typedef struct PoolTy {
1016 void *Data;
2329 struct PoolSlab *Next;
2430 unsigned char AllocatedBitVector[NODES_PER_SLAB/8];
2531 unsigned char StartOfAllocation[NODES_PER_SLAB/8];
32
33 unsigned isSingleArray; /* If this slab is used for exactly one array */
34 /* The array is allocated from the start to the end of the slab */
35 unsigned ArraySize; /* The size of the array allocated */
36
2637 char Data[1]; /* Buffer to hold data in this slab... variable sized */
2738
2839 } PoolSlab;
4455 /* poolinit - Initialize a pool descriptor to empty
4556 */
4657 void poolinit(PoolTy *Pool, unsigned NodeSize) {
47 assert(Pool && "Null pool pointer passed into poolinit!");
58 if (!Pool) {
59 printf("Null pool pointer passed into poolinit!\n");
60 exit(1);
61 }
4862
4963 Pool->NodeSize = NodeSize;
5064 Pool->Data = 0;
5468 }
5569
5670 void poolmakeunfreeable(PoolTy *Pool) {
57 assert(Pool && "Null pool pointer passed in to poolmakeunfreeable!");
71 if (!Pool) {
72 printf("Null pool pointer passed in to poolmakeunfreeable!\n");
73 exit(1);
74 }
75
5876 Pool->FreeablePool = 0;
5977 }
6078
6280 */
6381 void pooldestroy(PoolTy *Pool) {
6482 PoolSlab *PS;
65 assert(Pool && "Null pool pointer passed in to pooldestroy!");
83 if (!Pool) {
84 printf("Null pool pointer passed in to pooldestroy!\n");
85 exit(1);
86 }
87
6688 PS = (PoolSlab*)Pool->Data;
6789 while (PS) {
6890 PoolSlab *Next = PS->Next;
7496 static void *FindSlabEntry(PoolSlab *PS, unsigned NodeSize) {
7597 /* Loop through all of the slabs looking for one with an opening */
7698 for (; PS; PS = PS->Next) {
99
100 /* If the slab is a single array, go on to the next slab */
101 /* Don't allocate single nodes in a SingleArray slab */
102 if (PS->isSingleArray)
103 continue;
104
77105 /* Check to see if there are empty entries at the end of the slab... */
78106 if (PS->LastUsed < NODES_PER_SLAB-1) {
79107 /* Mark the returned entry used */
117145 PoolSlab *PS;
118146 void *Result;
119147
120 assert(Pool && "Null pool pointer passed in to poolalloc!");
148 if (!Pool) {
149 printf("Null pool pointer passed in to poolalloc!\n");
150 exit(1);
151 }
152
121153 NodeSize = Pool->NodeSize;
154 // Return if this pool has size 0
155 if (NodeSize == 0)
156 return 0;
157
122158 PS = (PoolSlab*)Pool->Data;
123159
124160 if ((Result = FindSlabEntry(PS, NodeSize)))
127163 /* Otherwise we must allocate a new slab and add it to the list */
128164 PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
129165
130 assert (PS && "Could not allocate memory!");
166 if (!PS) {
167 printf("poolalloc: Could not allocate memory!");
168 exit(1);
169 }
131170
132171 /* Initialize the slab to indicate that the first element is allocated */
133172 PS->FirstUnused = 1;
134173 PS->LastUsed = 0;
174 /* This is not a single array */
175 PS->isSingleArray = 0;
176 PS->ArraySize = 0;
135177
136178 MARK_NODE_ALLOCATED(PS, 0);
137179 SET_START_BIT(PS, 0);
148190 PoolSlab **PPS;
149191 unsigned idxiter;
150192
151 assert(Pool && "Null pool pointer passed in to poolfree!");
193 if (!Pool) {
194 printf("Null pool pointer passed in to poolfree!\n");
195 exit(1);
196 }
197
152198 NodeSize = Pool->NodeSize;
199
200 // Return if this pool has size 0
201 if (NodeSize == 0)
202 return;
203
153204 PS = (PoolSlab*)Pool->Data;
154205 PPS = (PoolSlab**)&Pool->Data;
155206
156 /* Seach for the slab that contains this node... */
157 while (&PS->Data[0] > Node || &PS->Data[NodeSize*NODES_PER_SLAB] < Node) {
158 assert(PS && "free'd node not found in allocation pool specified!");
207 /* Search for the slab that contains this node... */
208 while (&PS->Data[0] > Node || &PS->Data[NodeSize*NODES_PER_SLAB-1] < Node) {
209 if (!PS) {
210 printf("poolfree: node being free'd not found in allocation pool specified!\n");
211 exit(1);
212 }
213
159214 PPS = &PS->Next;
160215 PS = PS->Next;
161216 }
162217
218 /* PS now points to the slab where Node is */
219
163220 Idx = (Node-&PS->Data[0])/NodeSize;
164221 assert(Idx < NODES_PER_SLAB && "Pool slab searching loop broken!");
165222
166 assert(ALLOCATION_BEGINS(PS, Idx) &&
167 "Attempt to free middle of allocated array");
168
169 /* Free the first node */
170 CLEAR_START_BIT(PS, Idx);
171 MARK_NODE_FREE(PS, Idx);
172
173 // Free all nodes
174 idxiter = Idx + 1;
175 while (idxiter < NODES_PER_SLAB && (!ALLOCATION_BEGINS(PS,idxiter)) &&
176 (NODE_ALLOCATED(PS, idxiter))) {
177 MARK_NODE_FREE(PS, idxiter);
178 }
179
180 /* Update the first free field if this node is below the free node line */
181 if (Idx < PS->FirstUnused) PS->FirstUnused = Idx;
182
183 /* If we are not freeing the last element in a slab... */
184 if (idxiter - 1 != PS->LastUsed) {
185 return;
186 }
187
188 /* Otherwise we are freeing the last element in a slab... shrink the
189 * LastUsed marker down to last used node.
190 */
191 PS->LastUsed = Idx;
192 do {
193 --PS->LastUsed;
194 /* Fixme, this should scan the allocated array an entire byte at a time for
195 * performance!
223 if (PS->isSingleArray) {
224
225 /* If this slab is a SingleArray */
226
227 if (Idx != 0) {
228 printf("poolfree: Attempt to free middle of allocated array\n");
229 exit(1);
230 }
231 if (!NODE_ALLOCATED(PS,0)) {
232 printf("poolfree: Attempt to free node that is already freed\n");
233 exit(1);
234 }
235 /* Mark this SingleArray slab as being free by just marking the first
236 entry as free*/
237 MARK_NODE_FREE(PS, 0);
238 } else {
239
240 /* If this slab is not a SingleArray */
241
242 if (!ALLOCATION_BEGINS(PS, Idx)) {
243 printf("poolfree: Attempt to free middle of allocated array\n");
244 }
245
246 /* Free the first node */
247 if (!NODE_ALLOCATED(PS, Idx)) {
248 printf("poolfree: Attempt to free node that is already freed\n");
249 exit(1);
250 }
251 CLEAR_START_BIT(PS, Idx);
252 MARK_NODE_FREE(PS, Idx);
253
254 // Free all nodes
255 idxiter = Idx + 1;
256 while (idxiter < NODES_PER_SLAB && (!ALLOCATION_BEGINS(PS,idxiter)) &&
257 (NODE_ALLOCATED(PS, idxiter))) {
258 MARK_NODE_FREE(PS, idxiter);
259 ++idxiter;
260 }
261
262 /* Update the first free field if this node is below the free node line */
263 if (Idx < PS->FirstUnused) PS->FirstUnused = Idx;
264
265 /* If we are not freeing the last element in a slab... */
266 if (idxiter - 1 != PS->LastUsed) {
267 return;
268 }
269
270 /* Otherwise we are freeing the last element in a slab... shrink the
271 * LastUsed marker down to last used node.
196272 */
197 } while (PS->LastUsed >= 0 && (!NODE_ALLOCATED(PS, PS->LastUsed)));
198
199 assert(PS->FirstUnused <= PS->LastUsed+1 &&
200 "FirstUnused field was out of date!");
273 PS->LastUsed = Idx;
274 do {
275 --PS->LastUsed;
276 /* Fixme, this should scan the allocated array an entire byte at a time
277 * for performance!
278 */
279 } while (PS->LastUsed >= 0 && (!NODE_ALLOCATED(PS, PS->LastUsed)));
280
281 assert(PS->FirstUnused <= PS->LastUsed+1 &&
282 "FirstUnused field was out of date!");
283 }
201284
202285 /* Ok, if this slab is empty, we unlink it from the of slabs and either move
203286 * it to the head of the list, or free it, depending on whether or not there
205288 */
206289 /* Do this only if the pool is freeable */
207290 if (Pool->FreeablePool) {
208 if (PS->LastUsed == -1) { /* Empty slab? */
291 if (PS->isSingleArray) {
292 /* If it is a SingleArray, just free it */
293 *PPS = PS->Next;
294 free(PS);
295 } else if (PS->LastUsed == -1) { /* Empty slab? */
209296 PoolSlab *HeadSlab;
210297 *PPS = PS->Next; /* Unlink from the list of slabs... */
211298
212299 HeadSlab = (PoolSlab*)Pool->Data;
213 if (HeadSlab && HeadSlab->LastUsed == -1){/* List already has empty slab? */
214 free(PS); /* Free memory for slab */
300 if (HeadSlab && HeadSlab->LastUsed == -1){/*List already has empty slab?*/
301 free(PS); /*Free memory for slab */
215302 } else {
216 PS->Next = HeadSlab; /* No empty slab yet, add this */
217 Pool->Data = PS; /* one to the head of the list */
303 PS->Next = HeadSlab; /*No empty slab yet, add this*/
304 Pool->Data = PS; /*one to the head of the list */
218305 }
219306 }
220307 } else {
221308 /* Pool is not freeable for safety reasons */
222309 /* Leave it in the list of PoolSlabs as an empty PoolSlab */
223 if (PS->LastUsed == -1) {
224 PS->FirstUnused = 0;
225
226 /* Do not free the pool, but move it to the head of the list if there is no
227 empty slab there already */
228 PoolSlab *HeadSlab;
229 HeadSlab = (PoolSlab*)Pool->Data;
230 if (HeadSlab && HeadSlab->LastUsed != -1) {
231 PS->Next = HeadSlab;
232 Pool->Data = PS;
310 if (!PS->isSingleArray)
311 if (PS->LastUsed == -1) {
312 PS->FirstUnused = 0;
313
314 /* Do not free the pool, but move it to the head of the list if there is
315 no empty slab there already */
316 PoolSlab *HeadSlab;
317 HeadSlab = (PoolSlab*)Pool->Data;
318 if (HeadSlab && HeadSlab->LastUsed != -1) {
319 PS->Next = HeadSlab;
320 Pool->Data = PS;
321 }
233322 }
234 }
235323 }
236324 }
237325
242330
243331 /* Loop through all of the slabs looking for one with an opening */
244332 for (; PS; PS = PS->Next) {
333
334 /* For large array allocation */
335 if (Size > NODES_PER_SLAB) {
336 /* If this slab is a SingleArray that is free with size > Size, use it */
337 if (PS->isSingleArray && !NODE_ALLOCATED(PS,0) && PS->ArraySize >= Size) {
338 /* Allocate the array in this slab */
339 MARK_NODE_ALLOCATED(PS,0); /* In a single array, only the first node
340 needs to be marked */
341 return &PS->Data[0];
342 } else
343 continue;
344 } else if (PS->isSingleArray)
345 continue; /* Do not allocate small arrays in SingleArray slabs */
346
347 /* For small array allocation */
245348 /* Check to see if there are empty entries at the end of the slab... */
246349 if (PS->LastUsed < NODES_PER_SLAB-Size) {
247350 /* Mark the returned entry used and set the start bit*/
276379 foundArray = 0;
277380
278381 if (foundArray) {
279 /* Successfully allocate out the first unused node */
382 /* Successfully allocate starting from the first unused node */
280383 SET_START_BIT(PS, Idx);
281384 for (i = Idx; i < Idx + Size; ++i)
282385 MARK_NODE_ALLOCATED(PS, i);
302405 void *Result;
303406 unsigned i;
304407
305 assert(Pool && "Null pool pointer passed in to poolallocarray!");
408 if (!Pool) {
409 printf("Null pool pointer passed to poolallocarray!\n");
410 exit(1);
411 }
412
306413 NodeSize = Pool->NodeSize;
414
415 // Return if this pool has size 0
416 if (NodeSize == 0)
417 return 0;
418
307419 PS = (PoolSlab*)Pool->Data;
308
309 assert(Size <= NODES_PER_SLAB &&
310 "Exceeded the maximum size of an individual malloc");
311420
312421 if ((Result = FindSlabEntryArray(PS, NodeSize,Size)))
313422 return Result;
314423
315424 /* Otherwise we must allocate a new slab and add it to the list */
316 PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
317
318 assert (PS && "Could not allocate memory!");
319
320 /* Initialize the slab to indicate that the first element is allocated */
321 PS->FirstUnused = Size;
322 PS->LastUsed = Size - 1;
323
324 SET_START_BIT(PS, 0);
325 for (i = 0; i < Size; ++i) {
326 MARK_NODE_ALLOCATED(PS, i);
425 if (Size > NODES_PER_SLAB) {
426 /* Allocate a new slab of size Size */
427 PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*Size-1);
428 if (!PS) {
429 printf("poolallocarray: Could not allocate memory!\n");
430 exit(1);
431 }
432 PS->isSingleArray = 1;
433 PS->ArraySize = Size;
434 MARK_NODE_ALLOCATED(PS, 0);
435 } else {
436 PS = (PoolSlab*)malloc(sizeof(PoolSlab)+NodeSize*NODES_PER_SLAB-1);
437 if (!PS) {
438 printf("poolallocarray: Could not allocate memory!\n");
439 exit(1);
440 }
441
442 /* Initialize the slab to indicate that the first element is allocated */
443 PS->FirstUnused = Size;
444 PS->LastUsed = Size - 1;
445
446 PS->isSingleArray = 0;
447 PS->ArraySize = 0;
448
449 SET_START_BIT(PS, 0);
450 for (i = 0; i < Size; ++i) {
451 MARK_NODE_ALLOCATED(PS, i);
452 }
327453 }
328454
329455 /* Add the slab to the list... */