00001
00016 #define MEMPOOL_DEBUG 0
00017 #if MEMPOOL_DEBUG
00018 #define DEBUG_PRINT(...) CmiPrintf(__VA_ARGS__)
00019 #else
00020 #define DEBUG_PRINT(...)
00021 #endif
00022
00023 #include "converse.h"
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #if CMK_HAS_MALLOC_H
00028 #include <malloc.h>
00029 #endif
00030
00031 #if CMK_C_INLINE
00032 #define INLINE_KEYWORD inline static
00033 #else
00034 #define INLINE_KEYWORD static
00035 #endif
00036
00037 #include "mempool.h"
00038 int cutOffPoints[] = {64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
00039 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304,
00040 8388608, 16777216, 33554432, 67108864, 134217728,
00041 268435456, 536870912, 1073741824};
00042
00043 INLINE_KEYWORD int which_pow2(size_t size)
00044 {
00045 int i;
00046 for (i = 0; i <= cutOffNum; i++)
00047 {
00048 if (size <= cutOffPoints[i])
00049 {
00050 return i;
00051 }
00052 }
00053 return i;
00054 }
00055
00056
00057 INLINE_KEYWORD void fillblock(mempool_type* mptr, block_header* block_head, size_t pool_size, int expansion)
00058 {
00059 for (int i = 0; i < cutOffNum; i++)
00060 {
00061 block_head->freelists[i] = 0;
00062 }
00063
00064 void* pool = block_head;
00065 size_t taken = expansion ? sizeof(block_header) : sizeof(mempool_type);
00066 size_t left = pool_size - taken;
00067 size_t loc = (char*)pool + taken - (char*)mptr;
00068 int power = which_pow2(left);
00069 if (power <= cutOffNum)
00070 {
00071 if (left < cutOffPoints[power])
00072 {
00073 power--;
00074 }
00075 }
00076
00077 if (power >= cutOffNum)
00078 {
00079 CmiAbort(
00080 "Mempool-should never reach here for filling blocks when doing \
00081 small allocations. Please report the bug to Charm++ developers.\n");
00082 }
00083
00084 DEBUG_PRINT("Left is %d, Max power obtained is %d\n", left, power);
00085
00086 for (int i = power; i >= 0; i--)
00087 {
00088 if (left >= cutOffPoints[i])
00089 {
00090 block_head->freelists[i] = loc;
00091 loc += cutOffPoints[i];
00092 left -= cutOffPoints[i];
00093 }
00094 }
00095
00096 slot_header* head;
00097 size_t prev = 0;
00098 for (int i = power; i >= 0; i--)
00099 {
00100 if (block_head->freelists[i])
00101 {
00102 head = (slot_header*)((char*)mptr + block_head->freelists[i]);
00103 head->size = cutOffPoints[i];
00104 head->power = i;
00105 head->status = 1;
00106 head->block_ptr = block_head;
00107 head->prev = head->next = 0;
00108 head->gprev = prev;
00109 if (i != power)
00110 {
00111 ((slot_header*)((char*)mptr + prev))->gnext = block_head->freelists[i];
00112 }
00113 prev = block_head->freelists[i];
00114 }
00115 }
00116 head->gnext = 0;
00117 }
00118
00119
00120
00121 int checkblock(mempool_type* mptr, block_header* current, int power)
00122 {
00123 slot_header* head_free = current->freelists[power] ? (slot_header*)((char*)mptr + current->freelists[power]) : NULL;
00124
00125
00126
00127 int powiter = power + 1;
00128 while (head_free == NULL && powiter < cutOffNum)
00129 {
00130 if (current->freelists[powiter])
00131 {
00132 slot_header* head_move = (slot_header*)((char*)mptr + current->freelists[powiter]);
00133 size_t gnext = head_move->gnext;
00134 size_t loc = current->freelists[powiter];
00135 current->freelists[powiter] = head_move->next;
00136 current->freelists[power] = loc;
00137
00138 loc = loc + cutOffPoints[power];
00139 for (int i = power + 1; i < powiter; i++)
00140 {
00141 loc = loc + cutOffPoints[i - 1];
00142 current->freelists[i] = loc;
00143 }
00144
00145 head_move->size = cutOffPoints[power];
00146 head_move->power = power;
00147 size_t prev = current->freelists[power];
00148 head_move->next = prev + cutOffPoints[power];
00149 slot_header* head = (slot_header*)((char*)head_move + cutOffPoints[power]);
00150 for (int i = power; i < powiter; i++)
00151 {
00152 if (i != power)
00153 {
00154 head = (slot_header*)((char*)head + cutOffPoints[i - 1]);
00155 }
00156 head->size = cutOffPoints[i];
00157 head->power = i;
00158 head->status = 1;
00159 head->block_ptr = current;
00160 head->prev = head->next = 0;
00161 head->gprev = prev;
00162 ((slot_header*)((char*)mptr + prev))->gnext = (char*)head - (char*)mptr;
00163 if (i != power)
00164 {
00165 prev = prev + cutOffPoints[i - 1];
00166 }
00167 else
00168 {
00169 prev = prev + cutOffPoints[i];
00170 }
00171 }
00172 ((slot_header*)((char*)head_move + cutOffPoints[power]))->prev =
00173 current->freelists[power];
00174 head->gnext = gnext;
00175 if (gnext != 0)
00176 {
00177 ((slot_header*)((char*)mptr + gnext))->gprev = prev;
00178 }
00179 if (current->freelists[powiter])
00180 {
00181 slot_header* head_next = (slot_header*)((char*)mptr + current->freelists[powiter]);
00182 head_next->prev = 0;
00183 }
00184 head_free = (slot_header*)((char*)mptr + current->freelists[power]);
00185 }
00186 powiter++;
00187 }
00188
00189 return head_free != NULL;
00190 }
00191
00192 void removeblocks(mempool_type* mptr)
00193 {
00194 if (mptr == NULL) return;
00195 mempool_freeblock freefn = mptr->freeblockfn;
00196 block_header* tail = (block_header*)((char*)mptr + mptr->block_tail);
00197 block_header* prev = &(mptr->block_head);
00198 block_header* current = prev->block_next ? (block_header*)((char*)mptr + prev->block_next) : NULL;
00199
00200 while (current != NULL)
00201 {
00202 if (current->used <= 0)
00203 {
00204 block_header* tofree = current;
00205 current = current->block_next ? (block_header*)((char*)mptr + current->block_next) : NULL;
00206 if (tail == tofree)
00207 {
00208 mptr->block_tail = tofree->block_prev;
00209 }
00210 prev->block_next = tofree->block_next;
00211 if (current != NULL)
00212 {
00213 current->block_prev = tofree->block_prev;
00214 }
00215 mptr->size -= tofree->size;
00216 freefn(tofree, tofree->mem_hndl);
00217 if (mptr->size < mptr->limit) return;
00218 }
00219 else
00220 {
00221 prev = current;
00222 current = current->block_next ? (block_header*)((char*)mptr + current->block_next) : NULL;
00223 }
00224 }
00225 }
00226
00228 mempool_type* mempool_init(size_t pool_size, mempool_newblockfn allocfn, mempool_freeblock freefn, size_t limit)
00229 {
00230 int power = which_pow2(pool_size);
00231 if (power > cutOffNum)
00232 {
00233 pool_size = 1 * 1024 * 1024;
00234 }
00235
00236 mem_handle_t mem_hndl;
00237 void* pool = allocfn(&pool_size, &mem_hndl, 0);
00238 mempool_type* mptr = (mempool_type*)pool;
00239 mptr->newblockfn = allocfn;
00240 mptr->freeblockfn = freefn;
00241 mptr->block_tail = 0;
00242 mptr->limit = limit;
00243 mptr->size = pool_size;
00244 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
00245 mptr->mempoolLock = CmiCreateLock();
00246 #endif
00247 mptr->block_head.mptr = (struct mempool_type*)pool;
00248 mptr->block_head.mem_hndl = mem_hndl;
00249 mptr->block_head.size = pool_size;
00250 mptr->block_head.used = 0;
00251 mptr->block_head.block_prev = 0;
00252 mptr->block_head.block_next = 0;
00253 #if CMK_CONVERSE_UGNI
00254 mptr->block_head.msgs_in_send = 0;
00255 mptr->block_head.msgs_in_recv = 0;
00256 #endif
00257 fillblock(mptr, &mptr->block_head, pool_size, 0);
00258 mptr->large_blocks = 0;
00259 DEBUG_PRINT("Initialized pool of size %zd\n", pool_size);
00260 return mptr;
00261 }
00262
00263 void mempool_destroy(mempool_type* mptr)
00264 {
00265 if (mptr == NULL) return;
00266 mempool_freeblock freefn = mptr->freeblockfn;
00267
00268 large_block_header* lcurr = (mptr->large_blocks) ? (large_block_header*)((char*)mptr + mptr->large_blocks) : NULL;
00269 while (lcurr != NULL)
00270 {
00271 large_block_header* ltofree = lcurr;
00272 lcurr = lcurr->block_next ? (large_block_header*)((char*)mptr + lcurr->block_next) : NULL;
00273 freefn(ltofree, ltofree->mem_hndl);
00274 }
00275
00276 block_header* current = &(mptr->block_head);
00277 while (current != NULL)
00278 {
00279 block_header* tofree = current;
00280 current = current->block_next ? (block_header*)((char*)mptr + current->block_next) : NULL;
00281 freefn(tofree, tofree->mem_hndl);
00282 }
00283 }
00284
00285
00286 void* mempool_malloc(mempool_type* mptr, size_t size, int expand)
00287 {
00288 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
00289 CmiLock(mptr->mempoolLock);
00290 #endif
00291
00292 size_t size_with_used_header = size + sizeof(used_header);
00293 int power = which_pow2(size_with_used_header);
00294 if (power >= cutOffNum)
00295 {
00296 return mempool_large_malloc(mptr, size, expand);
00297 }
00298
00299 size_t bestfit_size = cutOffPoints[power];
00300 DEBUG_PRINT("Request size is %d, power value is %d, size is %d\n", size, power, bestfit_size);
00301
00302 slot_header* head_free = NULL;
00303 block_header* current = &mptr->block_head;
00304 while (current != NULL)
00305 {
00306 if (checkblock(mptr, current, power))
00307 {
00308 head_free = current->freelists[power] ? (slot_header*)((char*)mptr + current->freelists[power]) : NULL;
00309 break;
00310 }
00311 else
00312 {
00313 current = current->block_next ? (block_header*)((char*)mptr + current->block_next) : NULL;
00314 }
00315 }
00316
00317
00318 if (head_free == NULL)
00319 {
00320 if (!expand) return NULL;
00321
00322 DEBUG_PRINT("Expanding size %lld limit %lld\n", mptr->size, mptr->limit);
00323
00324 if ((mptr->size > mptr->limit) && (mptr->limit > 0))
00325 {
00326 removeblocks(mptr);
00327 }
00328
00329 block_header* tail = (block_header*)((char*)mptr + mptr->block_tail);
00330 size_t expand_size = bestfit_size + sizeof(block_header);
00331 mem_handle_t mem_hndl;
00332 void* pool = mptr->newblockfn(&expand_size, &mem_hndl, expand);
00333 if (pool == NULL)
00334 {
00335 DEBUG_PRINT("Mempool-Did not get memory while expanding\n");
00336 return NULL;
00337 }
00338
00339 mptr->size += expand_size;
00340 current = (block_header*)pool;
00341 tail->block_next = ((char*)current - (char*)mptr);
00342 current->block_prev = mptr->block_tail;
00343 mptr->block_tail = tail->block_next;
00344
00345 current->mptr = mptr;
00346 current->mem_hndl = mem_hndl;
00347 current->used = 0;
00348 current->size = expand_size;
00349 current->block_next = 0;
00350 #if CMK_CONVERSE_UGNI
00351 current->msgs_in_send = 0;
00352 current->msgs_in_recv = 0;
00353 #endif
00354
00355 fillblock(mptr, current, expand_size, 1);
00356 if (checkblock(mptr, current, power))
00357 {
00358 head_free = current->freelists[power] ? (slot_header*)((char*)mptr + current->freelists[power]) : NULL;
00359 }
00360 else
00361 {
00362 CmiAbort("Mempool-No free block after expansion, something is broken in mempool\n");
00363 }
00364 }
00365
00366 if (head_free != NULL)
00367 {
00368 head_free->status = 0;
00369 current->freelists[power] = head_free->next;
00370 slot_header* head_next = current->freelists[power] ? (slot_header*)((char*)mptr + current->freelists[power]) : NULL;
00371 if (head_next != NULL)
00372 {
00373 head_next->prev = 0;
00374 }
00375
00376 head_free->block_ptr = current;
00377 current->used += power;
00378 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
00379 CmiUnlock(mptr->mempoolLock);
00380 #endif
00381 DEBUG_PRINT("Malloc done\n");
00382 return (char*)head_free + sizeof(used_header);
00383 }
00384
00385 CmiAbort("Mempool-Reached a location which it should never have reached\n");
00386 }
00387
00388 void* mempool_large_malloc(mempool_type* mptr, size_t size, int expand)
00389 {
00390 size_t expand_size = size + sizeof(large_block_header) + sizeof(used_header);
00391 DEBUG_PRINT("Mempool-Large block allocation\n");
00392 mem_handle_t mem_hndl;
00393 void* pool = mptr->newblockfn(&expand_size, &mem_hndl, expand);
00394
00395 if (pool == NULL)
00396 {
00397 DEBUG_PRINT("Mempool-Did not get memory while expanding\n");
00398 return NULL;
00399 }
00400
00401 large_block_header* current = (large_block_header*)pool;
00402 current->block_prev = current->block_next = 0;
00403
00404 if (mptr->large_blocks != 0)
00405 {
00406 large_block_header* first_block = (large_block_header*)((char*)mptr + mptr->large_blocks);
00407 first_block->block_prev = ((char*)current - (char*)mptr);
00408 current->block_next = mptr->large_blocks;
00409 }
00410 mptr->large_blocks = ((char*)current - (char*)mptr);
00411
00412 current->mptr = mptr;
00413 current->mem_hndl = mem_hndl;
00414 current->size = expand_size;
00415 mptr->size += expand_size;
00416 #if CMK_CONVERSE_UGNI
00417 current->msgs_in_send = 0;
00418 current->msgs_in_recv = 0;
00419 #endif
00420
00421 used_header* head_free = (used_header*)((char*)current + sizeof(large_block_header));
00422 head_free->block_ptr = (block_header*)current;
00423 head_free->size = expand_size - sizeof(large_block_header);
00424 head_free->status = -1;
00425 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
00426 CmiUnlock(mptr->mempoolLock);
00427 #endif
00428 DEBUG_PRINT("Large malloc done\n");
00429 return (char*)head_free + sizeof(used_header);
00430 }
00431
00432 #if CMK_USE_MEMPOOL_ISOMALLOC || (CMK_SMP && CMK_CONVERSE_UGNI)
00433 void mempool_free_thread(void* ptr_free)
00434 {
00435 slot_header* to_free = (slot_header*)((char*)ptr_free - sizeof(used_header));
00436 mempool_type* mptr = to_free->status == -1
00437 ? (mempool_type*)(((large_block_header*)(to_free->block_ptr))->mptr)
00438 : (mempool_type*)(((block_header*)(to_free->block_ptr))->mptr);
00439 CmiLock(mptr->mempoolLock);
00440 mempool_free(mptr, ptr_free);
00441 CmiUnlock(mptr->mempoolLock);
00442 }
00443 #endif
00444
00445 void mempool_free(mempool_type* mptr, void* ptr_free)
00446 {
00447 DEBUG_PRINT("Free request for %lld\n", ((char*)ptr_free - (char*)mptr - sizeof(used_header)));
00448
00449 slot_header* to_free = (slot_header*)((char*)ptr_free - sizeof(used_header));
00450
00451 if (to_free->status == -1)
00452 {
00453 large_block_header* largeblockhead = (large_block_header*)to_free->block_ptr, *temp;
00454 if (mptr->large_blocks == ((char*)largeblockhead - (char*)mptr))
00455 {
00456 mptr->large_blocks = largeblockhead->block_next;
00457 }
00458 else
00459 {
00460 large_block_header* temp = (large_block_header*)((char*)mptr + largeblockhead->block_prev);
00461 temp->block_next = largeblockhead->block_next;
00462 }
00463 if (largeblockhead->block_next != 0)
00464 {
00465 large_block_header* temp = (large_block_header*)((char*)mptr + largeblockhead->block_next);
00466 temp->block_prev = largeblockhead->block_prev;
00467 }
00468 mptr->size -= largeblockhead->size;
00469 mptr->freeblockfn(largeblockhead, largeblockhead->mem_hndl);
00470 DEBUG_PRINT("Large free done\n");
00471 return;
00472 }
00473
00474 to_free->status = 1;
00475 block_header* block_head = to_free->block_ptr;
00476 block_head->used -= to_free->size;
00477
00478
00479
00480 size_t size = 0;
00481 slot_header* first;
00482 slot_header* current = to_free;
00483 while (current->status == 1)
00484 {
00485 size += current->size;
00486 first = current;
00487 current = current->gprev ? (slot_header*)((char*)mptr + current->gprev) : NULL;
00488 if (current == NULL)
00489 break;
00490 }
00491
00492 size -= to_free->size;
00493 current = to_free;
00494 while (current->status == 1)
00495 {
00496 size += current->size;
00497 current = current->gnext ? (slot_header*)((char*)mptr + current->gnext) : NULL;
00498 if (current == NULL)
00499 break;
00500 }
00501 slot_header* used_next = current;
00502
00503
00504
00505 current = first;
00506 while (current != used_next)
00507 {
00508 if (current != to_free)
00509 {
00510 slot_header* temp;
00511 int power = current->power;
00512 temp = current->prev ? (slot_header*)((char*)mptr + current->prev) : NULL;
00513 if (temp != NULL)
00514 {
00515 temp->next = current->next;
00516 }
00517 else
00518 {
00519 block_head->freelists[power] = current->next;
00520 }
00521 temp = current->next ? (slot_header*)((char*)mptr + current->next) : NULL;
00522 if (temp != NULL)
00523 {
00524 temp->prev = current->prev;
00525 }
00526 }
00527 current = current->gnext ? (slot_header*)((char*)mptr + current->gnext) : NULL;
00528 }
00529
00530
00531 int power = which_pow2(size);
00532 if (size < cutOffPoints[power])
00533 {
00534 power--;
00535 }
00536 size_t left = size;
00537
00538 #if MEMPOOL_DEBUG
00539 if (CmiMyPe() == 0)
00540 DEBUG_PRINT("Free was for %zd, merging for %zd, power %d\n", to_free->size, size, power);
00541 #endif
00542
00543 size_t loc = (char*)first - (char*)mptr;
00544 size_t prev;
00545 for (int i = power; i >= 0; i--)
00546 {
00547 if (left >= cutOffPoints[i])
00548 {
00549 current = (slot_header*)((char*)mptr + loc);
00550 current->size = cutOffPoints[i];
00551 current->power = i;
00552 current->status = 1;
00553 current->block_ptr = block_head;
00554 if (i != power)
00555 {
00556 current->gprev = prev;
00557 }
00558 current->gnext = loc + cutOffPoints[i];
00559 current->prev = 0;
00560 if (block_head->freelists[i] == 0)
00561 {
00562 current->next = 0;
00563 }
00564 else
00565 {
00566 current->next = block_head->freelists[i];
00567 slot_header* temp = (slot_header*)((char*)mptr + block_head->freelists[i]);
00568 temp->prev = loc;
00569 }
00570 block_head->freelists[i] = loc;
00571 prev = loc;
00572 loc += cutOffPoints[i];
00573 left -= cutOffPoints[i];
00574 }
00575 }
00576 if (used_next != NULL)
00577 {
00578 used_next->gprev = (char*)current - (char*)mptr;
00579 }
00580 else
00581 {
00582 current->gnext = 0;
00583 }
00584 DEBUG_PRINT("Free done\n");
00585 }
00586
00587 #if CMK_CONVERSE_UGNI
00588 inline void* getNextRegisteredPool(void* current)
00589 {
00590 }
00591 #endif