4 Memory pool implementation. It is used in two places-
5 1 - For UGNI management of pinned memory
6 2 - Isomalloc allocation
8 Memory is allocated in terms of blocks from the OS and the user
9 is given back memory after rounding to nearest power of 2.
11 Written by Yanhua Sun 08-27-2011
12 Generalized by Gengbin Zheng 10/5/2011
13 Heavily modified by Nikhil Jain 11/28/2011
16 #define MEMPOOL_DEBUG 0
27 #define INLINE_KEYWORD inline static
29 #define INLINE_KEYWORD static
33 int cutOffPoints
[] = {64,128,256,512,1024,2048,4096, 8192,16384,32768,
34 65536,131072,262144,524288,1048576,2097152,4194304,
35 8388608,16777216,33554432,67108864,134217728,268435456,
36 536870912,1073741824};
38 INLINE_KEYWORD
int which_pow2(size_t size
)
41 for(i
=0; i
<cutOffNum
; i
++) {
42 if(size
<= cutOffPoints
[i
]) {
49 //method to initialize the freelists of a newly allocated block
50 INLINE_KEYWORD
void fillblock(mempool_type
*mptr
,block_header
*block_head
,size_t pool_size
,int expansion
)
53 size_t loc
,left
,prev
,taken
;
57 for(i
=0; i
<cutOffNum
;i
++) {
58 block_head
->freelists
[i
] = 0;
62 taken
= expansion
? sizeof(block_header
) : sizeof(mempool_type
);
63 left
= pool_size
- taken
;
64 loc
= (char*)pool
+ taken
- (char*)mptr
;
65 power
= which_pow2(left
);
66 if(left
< cutOffPoints
[power
]) {
70 if(power
== cutOffNum
) {
71 CmiAbort("Mempool-requested slot is more than what mempool can provide as\
72 one chunk, increase cutOffNum and cutoffPoints in mempool\n");
76 CmiPrintf("Left is %d, Max power obtained is %d\n",left
,power
);
79 for(i
=power
; i
>=0; i
--) {
80 if(left
>=cutOffPoints
[i
]) {
81 block_head
->freelists
[i
] = loc
;
82 loc
+= cutOffPoints
[i
];
83 left
-= cutOffPoints
[i
];
88 for(i
=power
; i
>=0; i
--) {
89 if(block_head
->freelists
[i
]) {
90 head
= (slot_header
*)((char*)mptr
+block_head
->freelists
[i
]);
93 head
->block_ptr
= block_head
;
94 head
->prev
= head
->next
= 0;
97 ((slot_header
*)((char*)mptr
+prev
))->gnext
= block_head
->freelists
[i
];
99 prev
= block_head
->freelists
[i
];
105 //method to check if a request can be met by this block
106 //if yes, alter the block free list appropiately
107 int checkblock(mempool_type
*mptr
,block_header
*current
,int power
)
110 size_t prev
,loc
,gnext
;
111 slot_header
*head
,*head_free
,*head_move
,*head_next
;
112 head_free
= current
->freelists
[power
]?(slot_header
*)((char*)mptr
+current
->freelists
[power
]):NULL
;
114 //if the freelist of required size is empty, check if free
115 //list of some larger size is non-empty and break a slot from it
117 while(head_free
==NULL
&& powiter
<cutOffNum
) {
118 if(current
->freelists
[powiter
]) {
119 head_move
= (slot_header
*)((char*)mptr
+current
->freelists
[powiter
]);
120 gnext
= head_move
->gnext
;
121 loc
= current
->freelists
[powiter
];
122 current
->freelists
[powiter
] = head_move
->next
;
123 current
->freelists
[power
] = loc
;
124 //we get 2 entries for smallest size required
125 loc
= loc
+cutOffPoints
[power
];
126 for(i
=power
+1; i
<powiter
; i
++) {
127 loc
= loc
+cutOffPoints
[i
-1];
128 current
->freelists
[i
] = loc
;
131 head_move
->size
= power
;
132 prev
= current
->freelists
[power
];
133 head_move
->next
= prev
+cutOffPoints
[power
];
134 head
= (slot_header
*)((char*)head_move
+cutOffPoints
[power
]);
135 for(i
=power
; i
<powiter
; i
++) {
137 head
= (slot_header
*)((char*)head
+cutOffPoints
[i
-1]);
141 head
->block_ptr
= current
;
142 head
->prev
= head
->next
= 0;
144 ((slot_header
*)((char*)mptr
+prev
))->gnext
= (char*)head
-(char*)mptr
;
146 prev
= prev
+cutOffPoints
[i
-1];
148 prev
= prev
+cutOffPoints
[i
];
151 ((slot_header
*)((char*)head_move
+cutOffPoints
[power
]))->prev
=
152 current
->freelists
[power
];
155 ((slot_header
*)((char*)mptr
+gnext
))->gprev
= prev
;
157 if(current
->freelists
[powiter
]) {
158 head_next
= (slot_header
*)((char*)mptr
+current
->freelists
[powiter
]);
161 head_free
= (slot_header
*)((char*)mptr
+current
->freelists
[power
]);
166 return head_free
!= NULL
;
169 void removeblocks(mempool_type
*mptr
)
171 block_header
*current
,*prev
,*tofree
,*tail
;
173 mempool_freeblock freefn
;
174 if(mptr
== NULL
) return;
175 freefn
= mptr
->freeblockfn
;
176 tail
= (block_header
*)((char*)mptr
+mptr
->block_tail
);
177 current
= prev
= &(mptr
->block_head
);
178 current
= current
->block_next
?(block_header
*)((char*)mptr
+current
->block_next
):NULL
;
180 while(current
!= NULL
) {
181 if(current
->used
<= 0) {
183 current
= current
->block_next
?(block_header
*)((char*)mptr
+current
->block_next
):NULL
;
185 mptr
->block_tail
= tofree
->block_prev
;
187 prev
->block_next
= tofree
->block_next
;
188 if(current
!= NULL
) {
189 current
->block_prev
= tofree
->block_prev
;
191 mptr
->size
-= tofree
->size
;
192 freefn(tofree
, tofree
->mem_hndl
);
193 if(mptr
->size
< mptr
->limit
) return;
196 current
= current
->block_next
?(block_header
*)((char*)mptr
+current
->block_next
):NULL
;
201 mempool_type
*mempool_init(size_t pool_size
, mempool_newblockfn allocfn
, mempool_freeblock freefn
, size_t limit
)
205 mem_handle_t mem_hndl
;
207 void *pool
= allocfn(&pool_size
, &mem_hndl
, 0);
208 mptr
= (mempool_type
*)pool
;
209 mptr
->newblockfn
= allocfn
;
210 mptr
->freeblockfn
= freefn
;
211 mptr
->block_tail
= 0;
213 mptr
->size
= pool_size
;
214 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
215 mptr
->mempoolLock
= CmiCreateLock();
217 mptr
->block_head
.mptr
= (struct mempool_type
*)pool
;
218 mptr
->block_head
.mem_hndl
= mem_hndl
;
219 mptr
->block_head
.size
= pool_size
;
220 mptr
->block_head
.used
= 0;
221 mptr
->block_head
.block_prev
= 0;
222 mptr
->block_head
.block_next
= 0;
223 #if CMK_CONVERSE_UGNI
224 mptr
->block_head
.msgs_in_send
= 0;
225 mptr
->block_head
.msgs_in_recv
= 0;
227 fillblock(mptr
,&mptr
->block_head
,pool_size
,0);
231 void mempool_destroy(mempool_type
*mptr
)
233 block_header
*current
,*tofree
;
235 mempool_freeblock freefn
;
236 if(mptr
== NULL
) return;
237 freefn
= mptr
->freeblockfn
;
238 current
= tofree
= &(mptr
->block_head
);
240 while(current
!= NULL
) {
242 current
= current
->block_next
?(block_header
*)((char*)mptr
+current
->block_next
):NULL
;
243 freefn(tofree
, tofree
->mem_hndl
);
247 // append slot_header size before the real memory buffer
248 void* mempool_malloc(mempool_type
*mptr
, size_t size
, int expand
)
252 size_t expand_size
, bestfit_size
;
253 int power
; //closest power of cutoffpoint
254 block_header
*current
,*tail
;
255 slot_header
*head_free
,*head_next
;
256 mem_handle_t mem_hndl
;
258 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
259 CmiLock(mptr
->mempoolLock
);
262 bestfit_size
= size
+ sizeof(used_header
);
263 power
= which_pow2(bestfit_size
);
264 if(power
== cutOffNum
) {
265 CmiAbort("Mempool-requested slot is more than what mempool can provide as\
266 one chunk, increase cutOffNum and cutoffPoints in mempool\n");
268 bestfit_size
= cutOffPoints
[power
];
270 CmiPrintf("Request size is %d, power value is %d, size is %d\n",size
,power
,cutOffPoints
[power
]);
274 current
= &mptr
->block_head
;
275 while(current
!= NULL
) {
276 if(checkblock(mptr
,current
,power
)) {
277 head_free
= current
->freelists
[power
]?(slot_header
*)((char*)mptr
+current
->freelists
[power
]):NULL
;
280 current
= current
->block_next
?(block_header
*)((char*)mptr
+current
->block_next
):NULL
;
284 //no space in current blocks, get a new one
285 if(head_free
==NULL
) {
286 if (!expand
) return NULL
;
289 CmiPrintf("Expanding size %lld limit %lld\n",mptr
->size
,mptr
->limit
);
291 //free blocks which are not being used
292 if((mptr
->size
> mptr
->limit
) && (mptr
->limit
> 0)) {
296 tail
= (block_header
*)((char*)mptr
+mptr
->block_tail
);
297 expand_size
= 2*bestfit_size
+ sizeof(block_header
);
298 pool
= mptr
->newblockfn(&expand_size
, &mem_hndl
, 1);
300 CmiPrintf("Mempool-Did not get memory while expanding\n");
304 mptr
->size
+= expand_size
;
305 current
= (block_header
*)pool
;
306 tail
->block_next
= ((char*)current
-(char*)mptr
);
307 current
->block_prev
= mptr
->block_tail
;
308 mptr
->block_tail
= tail
->block_next
;
310 current
->mptr
= mptr
;
311 current
->mem_hndl
= mem_hndl
;
313 current
->size
= expand_size
;
314 current
->block_next
= 0;
315 #if CMK_CONVERSE_UGNI
316 current
->msgs_in_send
= 0;
317 current
->msgs_in_recv
= 0;
320 fillblock(mptr
,current
,expand_size
,1);
321 if(checkblock(mptr
,current
,power
)) {
322 head_free
= current
->freelists
[power
]?(slot_header
*)((char*)mptr
+current
->freelists
[power
]):NULL
;
324 CmiPrintf("Mempool-No free block after expansion, something is broken in mempool\n");
329 if(head_free
!=NULL
) {
330 head_free
->status
= 0;
331 current
->freelists
[power
] = head_free
->next
;
332 head_next
= current
->freelists
[power
]?(slot_header
*)((char*)mptr
+current
->freelists
[power
]):NULL
;
333 if(head_next
!= NULL
) {
337 head_free
->block_ptr
= current
;
338 current
->used
+= power
;
339 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
340 CmiUnlock(mptr
->mempoolLock
);
342 return (char*)head_free
+ sizeof(used_header
);
345 CmiPrintf("Mempool-Reached a location which I should never have reached\n");
349 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
350 void mempool_free_thread( void *ptr_free
)
352 slot_header
*to_free
;
355 to_free
= (slot_header
*)((char*)ptr_free
- sizeof(used_header
));
356 mptr
= (mempool_type
*)(((block_header
*)(to_free
->block_ptr
))->mptr
);
357 CmiLock(mptr
->mempoolLock
);
358 mempool_free(mptr
, ptr_free
);
359 CmiUnlock(mptr
->mempoolLock
);
363 void mempool_free(mempool_type
*mptr
, void *ptr_free
)
366 size_t prev
,loc
,size
,left
;
367 block_header
*block_head
;
368 slot_header
*to_free
, *first
, *current
;
369 slot_header
*used_next
,*temp
;
372 CmiPrintf("Free request for %lld\n",
373 ((char*)ptr_free
- (char*)mptr
- sizeof(used_header
)));
376 to_free
= (slot_header
*)((char*)ptr_free
- sizeof(used_header
));
378 block_head
= to_free
->block_ptr
;
379 block_head
->used
-= to_free
->size
;
381 //find the neighborhood of to_free which is also free and
382 //can be merged to get larger free slots
385 while(current
->status
== 1) {
386 size
+= cutOffPoints
[current
->size
];
388 current
= current
->gprev
?(slot_header
*)((char*)mptr
+current
->gprev
):NULL
;
393 size
-= cutOffPoints
[to_free
->size
];
395 while(current
->status
== 1) {
396 size
+= cutOffPoints
[current
->size
];
397 current
= current
->gnext
?(slot_header
*)((char*)mptr
+current
->gnext
):NULL
;
403 //remove the free slots in neighbor hood from their respective
406 while(current
!=used_next
) {
407 if(current
!=to_free
) {
408 power
= current
->size
;
409 temp
= current
->prev
?(slot_header
*)((char*)mptr
+current
->prev
):NULL
;
411 temp
->next
= current
->next
;
413 block_head
->freelists
[power
] = current
->next
;
415 temp
= current
->next
?(slot_header
*)((char*)mptr
+current
->next
):NULL
;
417 temp
->prev
= current
->prev
;
420 current
= current
->gnext
?(slot_header
*)((char*)mptr
+current
->gnext
):NULL
;
423 //now create the new free slots of as large a size as possible
424 power
= which_pow2(size
);
425 if(size
< cutOffPoints
[power
]) {
432 printf("free was for %lld, merging for %lld, power %lld\n",to_free
->size
,size
,power
);
435 loc
= (char*)first
- (char*)mptr
;
436 for(i
=power
; i
>=0; i
--) {
437 if(left
>=cutOffPoints
[i
]) {
438 current
= (slot_header
*)((char*)mptr
+loc
);
441 current
->block_ptr
= block_head
;
443 current
->gprev
= prev
;
445 current
->gnext
= loc
+ cutOffPoints
[i
];
447 if(block_head
->freelists
[i
] == 0) {
450 current
->next
= block_head
->freelists
[i
];
451 temp
= (slot_header
*)((char*)mptr
+block_head
->freelists
[i
]);
454 block_head
->freelists
[i
] = loc
;
456 loc
+= cutOffPoints
[i
];
457 left
-= cutOffPoints
[i
];
460 if(used_next
!=NULL
) {
461 used_next
->gprev
= (char*)current
- (char*)mptr
;
466 CmiPrintf("Free done\n");
470 #if CMK_CONVERSE_UGNI
471 inline void* getNextRegisteredPool(void *current
)