usermode/library/malloc-hoard-old/src/hoardheap.cpp

00001 
00002 //
00003 // The Hoard Multiprocessor Memory Allocator
00004 // www.hoard.org
00005 //
00006 // Author: Emery Berger, http://www.cs.utexas.edu/users/emery
00007 //
00008 // Copyright (c) 1998-2001, The University of Texas at Austin.
00009 //
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Library General Public License as
00012 // published by the Free Software Foundation, http://www.fsf.org.
00013 //
00014 // This library is distributed in the hope that it will be useful, but
00015 // WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Library General Public License for more details.
00018 //
00020 #include "config.h"
00021 
00022 #include "hoardheap.h"
00023 #include "processheap.h"
00024 #include "persistentheap.h"
00025 #include "superblock.h"
00026 
00027 size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES]
00028 = {8UL, 16UL, 24UL, 32UL, 40UL, 48UL, 56UL, 64UL, 72UL, 80UL, 88UL, 96UL, 104UL, 112UL, 120UL, 128UL, 136UL, 144UL, 152UL, 160UL, 168UL, 176UL, 184UL, 192UL, 200UL, 208UL, 216UL, 224UL, 232UL, 240UL, 248UL, 256UL, 264UL, 272UL, 280UL, 288UL, 296UL, 304UL, 312UL, 320UL, 328UL, 336UL, 344UL, 352UL, 360UL, 368UL, 376UL, 384UL, 392UL, 400UL, 408UL, 416UL, 424UL, 432UL, 440UL, 448UL, 456UL, 464UL, 472UL, 480UL, 488UL, 496UL, 504UL, 512UL, 576UL, 640UL, 704UL, 768UL, 832UL, 896UL, 960UL, 1024UL, 1088UL, 1152UL, 1216UL, 1280UL, 1344UL, 1408UL, 1472UL, 1536UL, 1600UL, 1664UL, 1728UL, 1792UL, 1856UL, 1920UL, 1984UL, 2048UL, 2112UL, 2560UL, 3072UL, 3584UL, 4096UL, 4608UL, 5120UL, 5632UL, 6144UL, 6656UL, 7168UL, 7680UL, 8192UL, 8704UL, 9216UL, 9728UL, 10240UL, 10752UL, 12288UL, 16384UL, 20480UL, 24576UL, 28672UL, 32768UL, 36864UL, 40960UL, 65536UL, 98304UL, 131072UL, 163840UL, 262144UL, 524288UL, 1048576UL, 2097152UL, 4194304UL, 8388608UL, 16777216UL, 33554432UL, 67108864UL, 134217728UL, 268435456UL, 536870912UL, 1073741824UL, 2147483648UL};
00029 
00030 size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {1024UL, 512UL, 341UL, 256UL, 204UL, 170UL, 146UL, 128UL, 113UL, 102UL, 93UL, 85UL, 78UL, 73UL, 68UL, 64UL, 60UL, 56UL, 53UL, 51UL, 48UL, 46UL, 44UL, 42UL, 40UL, 39UL, 37UL, 36UL, 35UL, 34UL, 33UL, 32UL, 31UL, 30UL, 29UL, 28UL, 27UL, 26UL, 26UL, 25UL, 24UL, 24UL, 23UL, 23UL, 22UL, 22UL, 21UL, 21UL, 20UL, 20UL, 20UL, 19UL, 19UL, 18UL, 18UL, 18UL, 17UL, 17UL, 17UL, 17UL, 16UL, 16UL, 16UL, 16UL, 14UL, 12UL, 11UL, 10UL, 9UL, 9UL, 8UL, 8UL, 7UL, 7UL, 6UL, 6UL, 6UL, 5UL, 5UL, 5UL, 5UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 3UL, 3UL, 2UL, 2UL, 2UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL, 1UL};
00031 
00032 hoardHeap::hoardHeap (void)
00033   : _index (0),
00034     _reusableSuperblocks (NULL),
00035     _reusableSuperblocksCount (0)
00036 #if HEAP_DEBUG
00037   , _magic (HEAP_MAGIC)
00038 #endif
00039 {
00040   // Initialize the per-heap lock.
00041   hoardLockInit (_lock);
00042   for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
00043     for (int j = 0; j < SIZE_CLASSES; j++) {
00044       // Initialize all superblocks lists to empty.
00045       _superblocks[i][j] = NULL;
00046     }
00047   }
00048   // Hoard resets leastEmptyBin[k] to 0 because initially bins
00049   // contain no superblocks. However, in our case the persistent
00050   // heap may have partially-full superblocks. So if 
00051   // findAvailableSuperblock does not find any superblock it checks
00052   // whether the persistentHeap has any. To make this work correctly
00053   // leastEmptyBin has to be set to RESET_LEAST_EMPTY_BIN to make
00054   // sure all bins are checked at least once. 
00055   for (int k = 0; k < SIZE_CLASSES; k++) {
00056     //_leastEmptyBin[k] = 0;
00057     _leastEmptyBin[k] = RESET_LEAST_EMPTY_BIN;
00058   }
00059 }
00060 
00061 // FIXME: Move findAvailableSuperblock under processHeap and persistentHeap?
00062 //
00063 // FIXME:
00064 // Currently findAvailableSuperblock will check whether the persistent heap
00065 // has any partially-full superblock if the current heap does not. 
00066 // This lazy approach avoids distributing persistent superblocks to thread
00067 // heaps when the allocator is first initialized. However it seems that it
00068 // complicated the recycling policy. Consider revising the policy.
00069 superblock * hoardHeap::findAvailableSuperblock (int sizeclass,
00070                                                  block *& b,
00071                                                  persistentHeap * persistentheap)
00072 {
00073   assert (this);
00074   assert (_magic == HEAP_MAGIC);
00075   assert (sizeclass >= 0);
00076   assert (sizeclass < SIZE_CLASSES);
00077 
00078   superblock * sb = NULL;
00079   int reUsed = 0;
00080 
00081   // Look through the superblocks, starting with the almost-full ones
00082   // and going to the emptiest ones.  The Least Empty Bin for a
00083   // sizeclass is a conservative approximation (fixed after one
00084   // iteration) of the first bin that has superblocks in it, starting
00085   // with (surprise) the least-empty bin.
00086   std::cout << "this = " << this << ",  _leastEmptyBin[sizeclass] = " << _leastEmptyBin[sizeclass] << std::endl;
00087   for (int i = 7; i >= 0; i--) {
00088         std::cout << "_superblock: " << i << ", " << sizeclass << ", "<< _superblocks[i][sizeclass]  << std::endl;
00089   }
00090   for (int i = _leastEmptyBin[sizeclass]; i >= 0; i--) {
00091     sb = _superblocks[i][sizeclass];
00092         if (sb == NULL) {
00093       // Check whether the persistent heap has a superblock of fullness i and 
00094           // size class sizeclass available.
00095       sb = persistentheap->removePartiallyFullSuperblock(i, sizeclass);
00096       std::cout << "removePartiallyFullSuperblock: " << i << ", " << sizeclass << ", "<< sb << std::endl;
00097       if (sb) {
00098         // Insert it into the bin list.
00099                 std::cout << "BEFORE" << std::endl;
00100   std::cout << "this = " << this << ",  _leastEmptyBin[sizeclass] = " << _leastEmptyBin[sizeclass] << std::endl;
00101   for (int i = 7; i >= 0; i--) {
00102         std::cout << "_superblock: " << i << ", " << sizeclass << ", "<< _superblocks[i][sizeclass]  << std::endl;
00103   }
00104 
00105         insertSuperblock (sizeclass, sb, persistentheap);
00106                 std::cout << "AFTER" << std::endl;
00107   std::cout << "this = " << this << ",  _leastEmptyBin[sizeclass] = " << _leastEmptyBin[sizeclass] << std::endl;
00108   for (int i = 7; i >= 0; i--) {
00109         std::cout << "_superblock: " << i << ", " << sizeclass << ", "<< _superblocks[i][sizeclass]  << std::endl;
00110   }
00111 
00112         assert (sb->getOwner() == this);
00113         break;
00114           }
00115       if (i == _leastEmptyBin[sizeclass]) {
00116         // There wasn't a superblock in this bin,
00117         // so we adjust the least empty bin.
00118         _leastEmptyBin[sizeclass]--;
00119       }
00120     } else {
00121       assert (sb->getOwner() == this);
00122       break;
00123     }
00124   } 
00125 
00126   if (sb == NULL) {
00127     // Try to reuse a superblock.
00128     sb = reuse (sizeclass);
00129     if (sb) {
00130       assert (sb->getOwner() == this);
00131       reUsed = 1;
00132     }
00133   }
00134 
00135   if (sb != NULL) {
00136     // Sanity checks:
00137     //   This superblock is 'valid'.
00138     assert (sb->isValid());
00139     //   This superblock has the right ownership.
00140     assert (sb->getOwner() == this);
00141     
00142     int oldFullness = sb->getFullness();
00143 
00144     // Now get a block from the superblock.
00145     // This superblock must have space available.
00146     b = sb->acquireBlock();
00147     assert (b != NULL);
00148     
00149     // Update the stats.
00150     incUStats (sizeclass);
00151     
00152     if (reUsed) {
00153       insertSuperblock (sizeclass, sb, persistentheap);
00154       // Fix the stats (since insert will just have incremented them
00155       // by this amount).
00156       decStats (sizeclass,
00157                 sb->getNumBlocks() - sb->getNumAvailable(),
00158                 sb->getNumBlocks());
00159     } else {
00160       // If we've crossed a fullness group,
00161       // move the superblock.
00162       int fullness = sb->getFullness();
00163       
00164       if (fullness != oldFullness) {
00165         // Move the superblock.
00166         moveSuperblock (sb, sizeclass, oldFullness, fullness);
00167       }
00168     }
00169   }
00170 
00171   // Either we didn't find a superblock or we did and got a block.
00172   assert ((sb == NULL) || (b != NULL));
00173   // Either we didn't get a block or we did and we also got a superblock.
00174   assert ((b == NULL) || (sb != NULL));
00175 
00176   return sb;
00177 }
00178 
00179 
00180 
00181 void hoardHeap::insertSuperblock (int sizeclass,
00182                                   superblock * sb,
00183                                   persistentHeap *)
00184 {
00185   assert (sb->isValid());
00186   assert (sb->getBlockSizeClass() == sizeclass);
00187   assert (sb->getPrev() == NULL);
00188   assert (sb->getNext() == NULL);
00189   assert (_magic == HEAP_MAGIC);
00190 
00191   // Now it's ours.
00192   sb->setOwner (this);
00193 
00194   // How full is this superblock?  We'll use this information to put
00195   // it into the right 'bin'.
00196   sb->computeFullness();
00197   int fullness = sb->getFullness();
00198 
00199   // Update the stats.
00200   incStats (sizeclass,
00201             sb->getNumBlocks() - sb->getNumAvailable(),
00202             sb->getNumBlocks());
00203 
00204   if ((fullness == 0) &&
00205       (sb->getNumBlocks() > 1) &&
00206       (sb->getNumBlocks() == sb->getNumAvailable())) {
00207     // This superblock is empty --
00208     // recycle this superblock (make it available for any sizeclass).
00209     recycle (sb);
00210   } else {
00211     // Insert it into the appropriate list.
00212     superblock *& head = _superblocks[fullness][sizeclass];
00213     sb->insertBefore (head);
00214     head = sb;
00215     assert (head->isValid());
00216     
00217     // Reset the least-empty bin counter.
00218     _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
00219   }
00220 }
00221 
00222 void hoardHeap::printSuperblockList()
00223 {
00224   superblock *sb = NULL;
00225 
00226   std::cout  << "printSuperblockList" << std::endl;
00227   for (int i = 0; i < 9; i--) {
00228     sb = _superblocks[i][12];
00229         if (sb) {
00230                 std::cout << "sb: " << sb << std::endl;
00231                 std::cout << "  ->psb: " << sb->getPersistentSuperblock() << std::endl;
00232         }       
00233   }
00234 }
00235 
00236 void hoardHeap::insertSuperblock (int sizeclass,
00237                                   superblock * sb,
00238                                   processHeap *)
00239 {
00240   assert (sb->isValid());
00241   assert (sb->getBlockSizeClass() == sizeclass);
00242   assert (sb->getPrev() == NULL);
00243   assert (sb->getNext() == NULL);
00244   assert (_magic == HEAP_MAGIC);
00245 
00246   // Now it's ours.
00247   sb->setOwner (this);
00248 
00249   // How full is this superblock?  We'll use this information to put
00250   // it into the right 'bin'.
00251   sb->computeFullness();
00252   int fullness = sb->getFullness();
00253 
00254   // Update the stats.
00255   incStats (sizeclass,
00256             sb->getNumBlocks() - sb->getNumAvailable(),
00257             sb->getNumBlocks());
00258 
00259   if ((fullness == 0) &&
00260       (sb->getNumBlocks() > 1) &&
00261       (sb->getNumBlocks() == sb->getNumAvailable())) {
00262     // This superblock is empty --
00263     // recycle this superblock (make it available for any sizeclass).
00264     recycle (sb);
00265   } else {
00266     // Insert it into the appropriate list.
00267     superblock *& head = _superblocks[fullness][sizeclass];
00268     sb->insertBefore (head);
00269     head = sb;
00270     assert (head->isValid());
00271     
00272     // Reset the least-empty bin counter.
00273     _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
00274 
00275   }
00276 }
00277 
00278 
00279 superblock * hoardHeap::removeMaxSuperblock (int sizeclass)
00280 {
00281   assert (_magic == HEAP_MAGIC);
00282 
00283   superblock * head = NULL;
00284 
00285   // First check the reusable superblocks list.
00286 
00287   head = reuse (sizeclass);
00288   if (head) {
00289     // We found one. Since we're removing this superblock, update the
00290     // stats accordingly.
00291     decStats (sizeclass,
00292               0,
00293               head->getNumBlocks());
00294 
00295     return head;
00296   }
00297   // Instead of finding the superblock with the most available space
00298   // (something that would either involve a linear scan through the
00299   // superblocks or maintaining the superblocks in sorted order), we
00300   // just pick one that is no more than
00301   // 1/(SUPERBLOCK_FULLNESS_GROUP-1) more full than the superblock
00302   // with the most available space.  We start with the emptiest group.
00303 
00304   int i = 0;
00305 
00306   // Note: the last group (SUPERBLOCK_FULLNESS_GROUP - 1) is full, so
00307   // we never need to check it. But for robustness, we leave it in.
00308   while (i < SUPERBLOCK_FULLNESS_GROUP) {
00309     head = _superblocks[i][sizeclass];
00310     if (head) {
00311       break;
00312     }
00313     i++;
00314   }
00315 
00316   if (!head) {
00317     return NULL;
00318   }
00319 
00320   // Make sure that this superblock is at least 1/EMPTY_FRACTION
00321   // empty.
00322   assert (head->getNumAvailable() * EMPTY_FRACTION >= head->getNumBlocks());
00323 
00324   removeSuperblock (head, sizeclass);
00325 
00326   assert (head->isValid());
00327   assert (head->getPrev() == NULL);
00328   assert (head->getNext() == NULL);
00329   return head;
00330 }
00331 
00332 superblock * hoardHeap::removePartiallyFullSuperblock (int fullness, int sizeclass)
00333 {
00334   assert (_magic == HEAP_MAGIC);
00335 
00336   superblock * head = NULL;
00337 
00338   head = _superblocks[fullness][sizeclass];
00339 
00340   if (!head) {
00341     return NULL;
00342   }
00343 
00344   // Make sure that this superblock is at least 1/EMPTY_FRACTION
00345   // empty.
00346   assert (head->getNumAvailable() * EMPTY_FRACTION >= head->getNumBlocks());
00347 
00348   removeSuperblock (head, sizeclass);
00349 
00350   assert (head->isValid());
00351   assert (head->getPrev() == NULL);
00352   assert (head->getNext() == NULL);
00353   return head;
00354 }
00355 
00356 
00357 void hoardHeap::removeSuperblock (superblock * sb,
00358                                   int sizeclass)
00359 {
00360   assert (_magic == HEAP_MAGIC);
00361 
00362   assert (sb->isValid());
00363   assert (sb->getOwner() == this);
00364   assert (sb->getBlockSizeClass() == sizeclass);
00365 
00366   for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
00367     if (sb == _superblocks[i][sizeclass]) {
00368       _superblocks[i][sizeclass] = sb->getNext();
00369       if (_superblocks[i][sizeclass] != NULL) {
00370         assert (_superblocks[i][sizeclass]->isValid());
00371       }
00372       break;
00373     }
00374   }
00375 
00376   sb->remove();
00377   decStats (sizeclass, sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
00378 }
00379 
00380 
00381 void hoardHeap::moveSuperblock (superblock * sb,
00382                                 int sizeclass,
00383                                 int fromBin,
00384                                 int toBin)
00385 {
00386   assert (_magic == HEAP_MAGIC);
00387   assert (sb->isValid());
00388   assert (sb->getOwner() == this);
00389   assert (sb->getBlockSizeClass() == sizeclass);
00390   assert (sb->getFullness() == toBin);
00391 
00392   // Remove the superblock from the old bin.
00393 
00394   superblock *& oldHead = _superblocks[fromBin][sizeclass];
00395   if (sb == oldHead) {
00396     oldHead = sb->getNext();
00397     if (oldHead != NULL) {
00398       assert (oldHead->isValid());
00399     }
00400   }
00401 
00402   sb->remove();
00403 
00404   // Insert the superblock into the new bin.
00405 
00406   superblock *& newHead = _superblocks[toBin][sizeclass];
00407   sb->insertBefore (newHead);
00408   newHead = sb;
00409   assert (newHead->isValid());
00410 
00411   // Reset the least-empty bin counter.
00412   _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
00413 }
00414 
00415 
00416 // The heap lock must be held when this procedure is called.
00417 
00418 int hoardHeap::freeBlock (block *& b,
00419                            superblock *& sb,
00420                            int sizeclass,
00421                            persistentHeap * persistentheap)
00422 {
00423   assert (sb->isValid());
00424   assert (b->isValid());
00425   assert (this == sb->getOwner());
00426 
00427   const int oldFullness = sb->getFullness();
00428   sb->putBlock (b);
00429   std::cout << "freeBlock: " << b << " this = " << this 
00430             << ", sizeclass = " << sizeclass
00431             << ", size = " << sizeFromClass(sizeclass) << std::endl;
00432 
00433   decUStats (sizeclass);
00434   const int newFullness = sb->getFullness();
00435   
00436   // Free big superblocks.
00437   if (sb->getNumBlocks() == 1) {
00438     //TODO: currently our persistent allocator handles blocks of size smaller that superblock size
00439     assert(0);
00440     removeSuperblock (sb, sizeclass);
00441 #if HEAP_LOG
00442     // Record the memory deallocation.
00443     MemoryRequest m;
00444     m.deallocate ((int) sb->getNumBlocks() * (int) sizeFromClass(sb->getBlockSizeClass()));
00445     persistentheap->getLog(getIndex()).append(m);
00446 #endif
00447 #if HEAP_FRAG_STATS
00448     persistentheap->setDeallocated (0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
00449 #endif
00450     sb->superblock::~superblock();
00451     hoardFreeMemory (sb);
00452     return 1;
00453   }
00454 
00455   // If the fullness value has changed, move the superblock.
00456   if (newFullness != oldFullness) {
00457     moveSuperblock (sb, sizeclass, oldFullness, newFullness);
00458   } else {
00459     // Move the superblock to the front of its list (to reduce
00460     // paging).
00461     superblock *& head = _superblocks[newFullness][sizeclass];
00462     if (sb != head) {
00463       sb->remove();
00464       sb->insertBefore (head);
00465       head = sb;
00466     }
00467   }
00468  
00469   // If the superblock is now empty, recycle it
00470   // or free it.
00471 
00472   if ((newFullness == 0) &&
00473       (sb->getNumBlocks() == sb->getNumAvailable())) {
00474 
00475     removeSuperblock (sb, sizeclass);
00476     if (_numProcessors == 1) {
00477       hoardFreeMemory (sb);
00478     } else {
00479       recycle (sb);
00480       // Update the stats.  This restores the stats to their state
00481       // before the call to removeSuperblock, above.
00482       incStats (sizeclass, 0, sb->getNumBlocks());
00483     }
00484   }
00485 
00486   // If this is the persistent heap, then we're done.
00487   if (this == (hoardHeap *) persistentheap) {
00488     return 0;
00489   }
00490 
00491   //assert(0);
00492   //FIXME: What is the right policy here for persistent blocks?
00493   //TODO: What is the right policy here for persistent blocks?
00494 
00495   //
00496   // Release a superblock, if necessary.
00497   //
00498 
00499   //
00500   // Check to see if the amount free exceeds the release threshold
00501   // (two superblocks worth of blocks for a given sizeclass) and if
00502   // the heap is sufficiently empty.
00503   //
00504 
00505   // We never move anything to the process heap if we're on a
00506   // uniprocessor.
00507   if (_numProcessors > 1) {
00508 
00509     int inUse, allocated;
00510     getStats (sizeclass, inUse, allocated);
00511     const bool crossedThreshold 
00512       = ((inUse < allocated - getReleaseThreshold(sizeclass)) && 
00513          (EMPTY_FRACTION * inUse < EMPTY_FRACTION * allocated - allocated));
00514     if (crossedThreshold) {
00515       
00516         // We've crossed the magical threshold. Find the superblock with
00517         // the most free blocks and give it to the process heap.
00518         superblock * const maxSb = removeMaxSuperblock (sizeclass);
00519         assert (maxSb != NULL);
00520         
00521         // Update the statistics.
00522         
00523         assert (maxSb->getNumBlocks() >= maxSb->getNumAvailable());
00524         
00525         // Give the superblock back to the process heap.
00526         persistentheap->release (maxSb);
00527         
00528     }
00529   }
00530 
00531   return 0;
00532 }
00533 
00534 // Static initialization of the number of processors (and a mask).
00535    
00536 int hoardHeap::_numProcessors;
00537 int hoardHeap::_numProcessorsMask;
00538 
00539 hoardHeap::_initNumProcs::_initNumProcs(void)
00540 {
00541   hoardHeap::_numProcessors = hoardGetNumProcessors();
00542   hoardHeap::_numProcessorsMask = (1 << (lg(hoardGetNumProcessors()) + 4)) - 1;
00543   if (hoardHeap::_numProcessors > MAX_HEAPS) {
00544           hoardHeap::_numProcessorsMask = MAX_HEAPS_MASK;
00545   }
00546 }
00547 
00548 static hoardHeap::_initNumProcs initProcs;

Generated on Sat Apr 23 11:43:35 2011 for Mnemosyne by  doxygen 1.4.7