usermode/library/malloc-original/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 "superblock.h"
00025 
00026 static const char version[] = "The Hoard memory allocator, version 2.1.0 (http://www.hoard.org). Copyright (C) 1998 - 2001 The University of Texas at Austin. $Id: hoardheap.cpp,v 1.84 2001/12/18 02:42:55 emery Exp $";
00027 
00028 size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES]
00029 = {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};
00030 
00031 size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES]
00032 = {2048UL, 1024UL, 682UL, 512UL, 409UL, 341UL, 292UL, 256UL, 227UL, 204UL, 186UL, 170UL, 157UL, 146UL, 136UL, 128UL, 120UL, 113UL, 107UL, 102UL, 97UL, 93UL, 89UL, 85UL, 81UL, 78UL, 75UL, 73UL, 70UL, 68UL, 66UL, 64UL, 62UL, 60UL, 58UL, 56UL, 55UL, 53UL, 52UL, 51UL, 49UL, 48UL, 47UL, 46UL, 45UL, 44UL, 43UL, 42UL, 41UL, 40UL, 40UL, 39UL, 38UL, 37UL, 37UL, 36UL, 35UL, 35UL, 34UL, 34UL, 33UL, 33UL, 32UL, 32UL, 28UL, 25UL, 23UL, 21UL, 19UL, 18UL, 17UL, 16UL, 15UL, 14UL, 13UL, 12UL, 12UL, 11UL, 11UL, 10UL, 10UL, 9UL, 9UL, 9UL, 8UL, 8UL, 8UL, 8UL, 7UL, 6UL, 5UL, 4UL, 4UL, 3UL, 3UL, 2UL, 2UL, 2UL, 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};
00033 
00034 
00035 hoardHeap::hoardHeap (void)
00036   : _index (0),
00037     _reusableSuperblocks (NULL),
00038     _reusableSuperblocksCount (0)
00039 #if HEAP_DEBUG
00040   , _magic (HEAP_MAGIC)
00041 #endif
00042 {
00043   // Initialize the per-heap lock.
00044   hoardLockInit (_lock);
00045   for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
00046     for (int j = 0; j < SIZE_CLASSES; j++) {
00047       // Initialize all superblocks lists to empty.
00048       _superblocks[i][j] = NULL;
00049     }
00050   }
00051   for (int k = 0; k < SIZE_CLASSES; k++) {
00052     _leastEmptyBin[k] = 0;
00053   }
00054 }
00055 
00056 
00057 void hoardHeap::insertSuperblock (int sizeclass,
00058                                   superblock * sb,
00059                                   processHeap * pHeap)
00060 {
00061   assert (sb->isValid());
00062   assert (sb->getBlockSizeClass() == sizeclass);
00063   assert (sb->getPrev() == NULL);
00064   assert (sb->getNext() == NULL);
00065   assert (_magic == HEAP_MAGIC);
00066 
00067   // Now it's ours.
00068   sb->setOwner (this);
00069 
00070   // How full is this superblock?  We'll use this information to put
00071   // it into the right 'bin'.
00072   sb->computeFullness();
00073   int fullness = sb->getFullness();
00074 
00075   // Update the stats.
00076   incStats (sizeclass,
00077             sb->getNumBlocks() - sb->getNumAvailable(),
00078             sb->getNumBlocks());
00079 
00080   if ((fullness == 0) &&
00081       (sb->getNumBlocks() > 1) &&
00082       (sb->getNumBlocks() == sb->getNumAvailable())) {
00083     // This superblock is empty --
00084     // recycle this superblock (make it available for any sizeclass).
00085     recycle (sb);
00086 
00087   } else {
00088 
00089     // Insert it into the appropriate list.
00090     superblock *& head = _superblocks[fullness][sizeclass];
00091     sb->insertBefore (head);
00092     head = sb;
00093     assert (head->isValid());
00094     
00095     // Reset the least-empty bin counter.
00096     _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
00097   }
00098 }
00099 
00100 
00101 superblock * hoardHeap::removeMaxSuperblock (int sizeclass)
00102 {
00103   assert (_magic == HEAP_MAGIC);
00104 
00105   superblock * head = NULL;
00106 
00107   // First check the reusable superblocks list.
00108 
00109   head = reuse (sizeclass);
00110   if (head) {
00111     // We found one. Since we're removing this superblock, update the
00112     // stats accordingly.
00113     decStats (sizeclass,
00114               0,
00115               head->getNumBlocks());
00116 
00117     return head;
00118   }
00119 
00120   // Instead of finding the superblock with the most available space
00121   // (something that would either involve a linear scan through the
00122   // superblocks or maintaining the superblocks in sorted order), we
00123   // just pick one that is no more than
00124   // 1/(SUPERBLOCK_FULLNESS_GROUP-1) more full than the superblock
00125   // with the most available space.  We start with the emptiest group.
00126 
00127   int i = 0;
00128 
00129   // Note: the last group (SUPERBLOCK_FULLNESS_GROUP - 1) is full, so
00130   // we never need to check it. But for robustness, we leave it in.
00131   while (i < SUPERBLOCK_FULLNESS_GROUP) {
00132     head = _superblocks[i][sizeclass];
00133     if (head) {
00134       break;
00135     }
00136     i++;
00137   }
00138 
00139   if (!head) {
00140     return NULL;
00141   }
00142 
00143   // Make sure that this superblock is at least 1/EMPTY_FRACTION
00144   // empty.
00145   assert (head->getNumAvailable() * EMPTY_FRACTION >= head->getNumBlocks());
00146 
00147   removeSuperblock (head, sizeclass);
00148 
00149   assert (head->isValid());
00150   assert (head->getPrev() == NULL);
00151   assert (head->getNext() == NULL);
00152   return head;
00153 }
00154 
00155 
00156 void hoardHeap::removeSuperblock (superblock * sb,
00157                                   int sizeclass)
00158 {
00159   assert (_magic == HEAP_MAGIC);
00160 
00161   assert (sb->isValid());
00162   assert (sb->getOwner() == this);
00163   assert (sb->getBlockSizeClass() == sizeclass);
00164 
00165   for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
00166     if (sb == _superblocks[i][sizeclass]) {
00167       _superblocks[i][sizeclass] = sb->getNext();
00168       if (_superblocks[i][sizeclass] != NULL) {
00169         assert (_superblocks[i][sizeclass]->isValid());
00170       }
00171       break;
00172     }
00173   }
00174 
00175   sb->remove();
00176   decStats (sizeclass, sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
00177 }
00178 
00179 
00180 void hoardHeap::moveSuperblock (superblock * sb,
00181                                 int sizeclass,
00182                                 int fromBin,
00183                                 int toBin)
00184 {
00185   assert (_magic == HEAP_MAGIC);
00186   assert (sb->isValid());
00187   assert (sb->getOwner() == this);
00188   assert (sb->getBlockSizeClass() == sizeclass);
00189   assert (sb->getFullness() == toBin);
00190 
00191   // Remove the superblock from the old bin.
00192 
00193   superblock *& oldHead = _superblocks[fromBin][sizeclass];
00194   if (sb == oldHead) {
00195     oldHead = sb->getNext();
00196     if (oldHead != NULL) {
00197       assert (oldHead->isValid());
00198     }
00199   }
00200 
00201   sb->remove();
00202 
00203   // Insert the superblock into the new bin.
00204 
00205   superblock *& newHead = _superblocks[toBin][sizeclass];
00206   sb->insertBefore (newHead);
00207   newHead = sb;
00208   assert (newHead->isValid());
00209 
00210   // Reset the least-empty bin counter.
00211   _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
00212 }
00213 
00214 
00215 // The heap lock must be held when this procedure is called.
00216 
00217 int hoardHeap::freeBlock (block *& b,
00218                            superblock *& sb,
00219                            int sizeclass,
00220                            processHeap * pHeap)
00221 {
00222   assert (sb->isValid());
00223   assert (b->isValid());
00224   assert (this == sb->getOwner());
00225 
00226   const int oldFullness = sb->getFullness();
00227   sb->putBlock (b);
00228   decUStats (sizeclass);
00229   const int newFullness = sb->getFullness();
00230   
00231   // Free big superblocks.
00232   if (sb->getNumBlocks() == 1) {
00233     removeSuperblock (sb, sizeclass);
00234 #if HEAP_LOG
00235     // Record the memory deallocation.
00236     MemoryRequest m;
00237     m.deallocate ((int) sb->getNumBlocks() * (int) sizeFromClass(sb->getBlockSizeClass()));
00238     pHeap->getLog(getIndex()).append(m);
00239 #endif
00240 #if HEAP_FRAG_STATS
00241     pHeap->setDeallocated (0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
00242 #endif
00243     sb->superblock::~superblock();
00244     hoardFreeMemory (sb);
00245     return 1;
00246   }
00247 
00248   // If the fullness value has changed, move the superblock.
00249   if (newFullness != oldFullness) {
00250     moveSuperblock (sb, sizeclass, oldFullness, newFullness);
00251   } else {
00252     // Move the superblock to the front of its list (to reduce
00253     // paging).
00254     superblock *& head = _superblocks[newFullness][sizeclass];
00255     if (sb != head) {
00256       sb->remove();
00257       sb->insertBefore (head);
00258       head = sb;
00259     }
00260   }
00261  
00262   // If the superblock is now empty, recycle it
00263   // or free it.
00264 
00265   if ((newFullness == 0) &&
00266       (sb->getNumBlocks() == sb->getNumAvailable())) {
00267 
00268     removeSuperblock (sb, sizeclass);
00269     if (_numProcessors == 1) {
00270       hoardFreeMemory (sb);
00271     } else {
00272       recycle (sb);
00273       // Update the stats.  This restores the stats to their state
00274       // before the call to removeSuperblock, above.
00275       incStats (sizeclass, 0, sb->getNumBlocks());
00276     }
00277   }
00278 
00279   // If this is the process heap, then we're done.
00280   if (this == (hoardHeap *) pHeap) {
00281     return 0;
00282   }
00283 
00284   //
00285   // Release a superblock, if necessary.
00286   //
00287 
00288   //
00289   // Check to see if the amount free exceeds the release threshold
00290   // (two superblocks worth of blocks for a given sizeclass) and if
00291   // the heap is sufficiently empty.
00292   //
00293 
00294   // We never move anything to the process heap if we're on a
00295   // uniprocessor.
00296   if (_numProcessors > 1) {
00297 
00298     int inUse, allocated;
00299     getStats (sizeclass, inUse, allocated);
00300     const bool crossedThreshold 
00301       = ((inUse < allocated - getReleaseThreshold(sizeclass)) && 
00302          (EMPTY_FRACTION * inUse < EMPTY_FRACTION * allocated - allocated));
00303     if (crossedThreshold) {
00304       
00305         // We've crossed the magical threshold. Find the superblock with
00306         // the most free blocks and give it to the process heap.
00307         superblock * const maxSb = removeMaxSuperblock (sizeclass);
00308         assert (maxSb != NULL);
00309         
00310         // Update the statistics.
00311         
00312         assert (maxSb->getNumBlocks() >= maxSb->getNumAvailable());
00313         
00314         // Give the superblock back to the process heap.
00315         pHeap->release (maxSb);
00316         
00317     }
00318   }
00319 
00320   return 0;
00321 }
00322 
00323 // Static initialization of the number of processors (and a mask).
00324    
00325 int hoardHeap::_numProcessors;
00326 int hoardHeap::_numProcessorsMask;
00327 
00328 hoardHeap::_initNumProcs::_initNumProcs(void)
00329 {
00330   hoardHeap::_numProcessors = hoardGetNumProcessors();
00331   hoardHeap::_numProcessorsMask = (1 << (lg(hoardGetNumProcessors()) + 4)) - 1;
00332   if (hoardHeap::_numProcessors > MAX_HEAPS) {
00333           hoardHeap::_numProcessorsMask = MAX_HEAPS_MASK;
00334   }
00335 }
00336 
00337 static hoardHeap::_initNumProcs initProcs;

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