usermode/library/malloc-original/src/hoardheap.h

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 
00021 /*
00022   heap.h
00023   ------------------------------------------------------------------------
00024   hoardHeap, the base class for threadHeap and processHeap.
00025   ------------------------------------------------------------------------
00026   @(#) $Id: hoardheap.h,v 1.79 2001/12/20 15:36:18 emery Exp $
00027   ------------------------------------------------------------------------
00028   Emery Berger                    | <http://www.cs.utexas.edu/users/emery>
00029   Department of Computer Sciences |             <http://www.cs.utexas.edu>
00030   University of Texas at Austin   |                <http://www.utexas.edu>
00031   ========================================================================
00032 */
00033 
00034 
00035 #ifndef _HEAP_H_
00036 #define _HEAP_H_
00037 
00038 #include "config.h"
00039 
00040 #include "arch-specific.h"
00041 #include "superblock.h"
00042 #include "heapstats.h"
00043 
00044 class processHeap; // forward declaration
00045 
00046 
00047 class hoardHeap {
00048 
00049 public:
00050 
00051   hoardHeap (void);
00052 
00053   // A superblock that holds more than one object must hold at least
00054   // this many bytes.
00055   enum { SUPERBLOCK_SIZE = 16384 };
00056 
00057   // A thread heap must be at least 1/EMPTY_FRACTION empty before we
00058   // start returning superblocks to the process heap.
00059   enum { EMPTY_FRACTION = SUPERBLOCK_FULLNESS_GROUP - 1 };
00060 
00061   // Reset value for the least-empty bin.  The last bin
00062   // (SUPERBLOCK_FULLNESS_GROUP-1) is for completely full superblocks,
00063   // so we use the next-to-last bin.
00064   enum { RESET_LEAST_EMPTY_BIN = SUPERBLOCK_FULLNESS_GROUP - 2 };
00065 
00066   // The number of empty superblocks that we allow any thread heap to
00067   // hold once the thread heap has fallen below 1/EMPTY_FRACTION
00068   // empty.
00069   enum { MAX_EMPTY_SUPERBLOCKS = 1 } ; // EMPTY_FRACTION / 2 };
00070 
00071   // The maximum number of thread heaps we allow.  (NOT the maximum
00072   // number of threads -- Hoard imposes no such limit.)  This must be
00073   // a power of two! NB: This number is twice the maximum number of
00074   // PROCESSORS supported by Hoard.
00075   enum { MAX_HEAPS = 64 };
00076 
00077   // ANDing with this rounds to MAX_HEAPS.
00078   enum { MAX_HEAPS_MASK = MAX_HEAPS - 1 };
00079 
00080   //
00081   // The number of size classes.
00082   //
00083 
00084   enum { SIZE_CLASSES = 132 };
00085 
00086   // Every object is aligned so that it can always hold a double.
00087   enum { ALIGNMENT = sizeof(double) };
00088 
00089   // ANDing with this rounds to ALIGNMENT.
00090   enum { ALIGNMENT_MASK = ALIGNMENT - 1};
00091 
00092   // Used for sanity checking.
00093   enum { HEAP_MAGIC = 0x0badcafe };
00094 
00095   // Get the usage and allocated statistics.
00096   inline void getStats (int sizeclass, int& U, int& A);
00097 
00098 
00099 #if HEAP_STATS
00100   // How much is the maximum ever in use for this size class?
00101   inline int maxInUse (int sizeclass);
00102 
00103   // How much is the maximum memory allocated for this size class?
00104   inline int maxAllocated (int sizeclass);
00105 #endif
00106 
00107   // Insert a superblock into our list.
00108   void insertSuperblock (int sizeclass,
00109                          superblock * sb,
00110                          processHeap * pHeap);
00111 
00112   // Remove the superblock with the most free space.
00113   superblock * removeMaxSuperblock (int sizeclass);
00114 
00115   // Find an available superblock (i.e., with some space in it).
00116   inline superblock * findAvailableSuperblock (int sizeclass,
00117                                                block *& b,
00118                                                processHeap * pHeap);
00119 
00120   // Lock this heap.
00121   inline void lock (void);
00122 
00123   // Unlock this heap.
00124   inline void unlock (void);
00125 
00126   // Set our index number (which heap we are).
00127   inline void setIndex (int i);
00128 
00129   // Get our index number (which heap we are).
00130   inline int getIndex (void);
00131 
00132   // Free a block into a superblock.
00133   // This is used by processHeap::free().
00134   // Returns 1 iff the superblock was munmapped.
00135   int freeBlock (block *& b,
00136                  superblock *& sb,
00137                  int sizeclass,
00138                  processHeap * pHeap);
00139 
00141 
00142   // Return the size class for a given size.
00143   inline static int sizeClass (const size_t sz);
00144 
00145   // Return the size corresponding to a given size class.
00146   inline static size_t sizeFromClass (const int sizeclass);
00147 
00148   // Return the release threshold corresponding to a given size class.
00149   inline static int getReleaseThreshold (const int sizeclass);
00150 
00151   // Return how many blocks of a given size class fit into a superblock.
00152   inline static int numBlocks (const int sizeclass);
00153 
00154   // Align a value.
00155   inline static size_t align (const size_t sz);
00156 
00157 private:
00158 
00159   // Disable copying and assignment.
00160 
00161   hoardHeap (const hoardHeap&);
00162   const hoardHeap& operator= (const hoardHeap&);
00163 
00164   // Recycle a superblock.
00165   inline void recycle (superblock *);
00166 
00167   // Reuse a superblock (if one is available).
00168   inline superblock * reuse (int sizeclass);
00169 
00170   // Remove a particular superblock.
00171   inline void removeSuperblock (superblock *, int sizeclass);
00172 
00173 public:
00174         // Move a particular superblock from one bin to another.
00175   void moveSuperblock (superblock *,
00176                        int sizeclass,
00177                        int fromBin,
00178                        int toBin);
00179 private:
00180 
00181   // Update memory in-use and allocated statistics.
00182   // (*UStats = just update U.)
00183   inline void incStats (int sizeclass, int updateU, int updateA);
00184 
00185 public:
00186   inline void incUStats (int sizeclass);
00187 private:
00188 
00189   inline void decStats (int sizeclass, int updateU, int updateA);
00190   inline void decUStats (int sizeclass);
00191 
00193 
00194 #if HEAP_DEBUG
00195   // For sanity checking.
00196   const unsigned long _magic;
00197 #else
00198   #define _magic HEAP_MAGIC
00199 #endif
00200 
00201   // Heap statistics.
00202   heapStats     _stats[SIZE_CLASSES];
00203 
00204   // The per-heap lock.
00205   hoardLockType _lock;
00206 
00207   // Which heap this is (0 = the process (global) heap).
00208   int _index;
00209 
00210   // Reusable superblocks.
00211   superblock *  _reusableSuperblocks;
00212   int           _reusableSuperblocksCount;
00213 
00214   // Lists of superblocks.
00215   superblock *  _superblocks[SUPERBLOCK_FULLNESS_GROUP][SIZE_CLASSES];
00216 
00217   // The current least-empty superblock bin.
00218   int   _leastEmptyBin[SIZE_CLASSES];
00219 
00220   // The lookup table for size classes.
00221   static size_t _sizeTable[SIZE_CLASSES];
00222 
00223   // The lookup table for release thresholds.
00224   static size_t _threshold[SIZE_CLASSES];
00225 
00226 public:
00227   // A little helper class that we use to define some statics.
00228   class _initNumProcs {
00229   public:
00230         _initNumProcs(void);
00231   };
00232 
00233   friend class _initNumProcs;
00234 protected:
00235   // number of CPUs, cached
00236   static int _numProcessors;
00237   static int _numProcessorsMask;
00238 };
00239 
00240 
00241 
00242 void hoardHeap::incStats (int sizeclass, int updateU, int updateA) {
00243   assert (_magic == HEAP_MAGIC);
00244   assert (updateU >= 0);
00245   assert (updateA >= 0);
00246   assert (sizeclass >= 0);
00247   assert (sizeclass < SIZE_CLASSES);
00248   _stats[sizeclass].incStats (updateU, updateA);
00249 }
00250 
00251 
00252 
00253 void hoardHeap::incUStats (int sizeclass) {
00254   assert (_magic == HEAP_MAGIC);
00255   assert (sizeclass >= 0);
00256   assert (sizeclass < SIZE_CLASSES);
00257   _stats[sizeclass].incUStats ();
00258 }
00259 
00260 
00261 void hoardHeap::decStats (int sizeclass, int updateU, int updateA) {
00262   assert (_magic == HEAP_MAGIC);
00263   assert (updateU >= 0);
00264   assert (updateA >= 0);
00265   assert (sizeclass >= 0);
00266   assert (sizeclass < SIZE_CLASSES);
00267   _stats[sizeclass].decStats (updateU, updateA);
00268 }
00269 
00270 
00271 void hoardHeap::decUStats (int sizeclass)
00272 {
00273   assert (_magic == HEAP_MAGIC);
00274   assert (sizeclass >= 0);
00275   assert (sizeclass < SIZE_CLASSES);
00276   _stats[sizeclass].decUStats();
00277 }
00278 
00279 
00280 void hoardHeap::getStats (int sizeclass, int& U, int& A) {
00281   assert (_magic == HEAP_MAGIC);
00282   assert (sizeclass >= 0);
00283   assert (sizeclass < SIZE_CLASSES);
00284   _stats[sizeclass].getStats (U, A);
00285 }
00286 
00287 
00288 #if HEAP_STATS
00289 int hoardHeap::maxInUse (int sizeclass) {
00290   assert (_magic == HEAP_MAGIC);
00291   return _stats[sizeclass].getUmax();
00292 }
00293 
00294 
00295 int hoardHeap::maxAllocated (int sizeclass) {
00296   assert (_magic == HEAP_MAGIC);
00297   return _stats[sizeclass].getAmax(); 
00298 }
00299 #endif
00300 
00301 
00302 superblock * hoardHeap::findAvailableSuperblock (int sizeclass,
00303                                                  block *& b,
00304                                                  processHeap * pHeap)
00305 {
00306   assert (this);
00307   assert (_magic == HEAP_MAGIC);
00308   assert (sizeclass >= 0);
00309   assert (sizeclass < SIZE_CLASSES);
00310 
00311   superblock * sb = NULL;
00312   int reUsed = 0;
00313 
00314   // Look through the superblocks, starting with the almost-full ones
00315   // and going to the emptiest ones.  The Least Empty Bin for a
00316   // sizeclass is a conservative approximation (fixed after one
00317   // iteration) of the first bin that has superblocks in it, starting
00318   // with (surprise) the least-empty bin.
00319 
00320   for (int i = _leastEmptyBin[sizeclass]; i >= 0; i--) {
00321     sb = _superblocks[i][sizeclass];
00322     if (sb == NULL) {
00323       if (i == _leastEmptyBin[sizeclass]) {
00324         // There wasn't a superblock in this bin,
00325         // so we adjust the least empty bin.
00326         _leastEmptyBin[sizeclass]--;
00327       }
00328     } else {
00329       assert (sb->getOwner() == this);
00330       break;
00331     }
00332   } 
00333 
00334   if (sb == NULL) {
00335     // Try to reuse a superblock.
00336     sb = reuse (sizeclass);
00337     if (sb) {
00338       assert (sb->getOwner() == this);
00339       reUsed = 1;
00340     }
00341   }
00342 
00343   if (sb != NULL) {
00344     // Sanity checks:
00345     //   This superblock is 'valid'.
00346     assert (sb->isValid());
00347     //   This superblock has the right ownership.
00348     assert (sb->getOwner() == this);
00349     
00350     int oldFullness = sb->getFullness();
00351 
00352     // Now get a block from the superblock.
00353     // This superblock must have space available.
00354     b = sb->getBlock();
00355     assert (b != NULL);
00356     
00357     // Update the stats.
00358     incUStats (sizeclass);
00359     
00360     if (reUsed) {
00361       insertSuperblock (sizeclass, sb, pHeap);
00362       // Fix the stats (since insert will just have incremented them
00363       // by this amount).
00364       decStats (sizeclass,
00365                 sb->getNumBlocks() - sb->getNumAvailable(),
00366                 sb->getNumBlocks());
00367     } else {
00368       // If we've crossed a fullness group,
00369       // move the superblock.
00370       int fullness = sb->getFullness();
00371       
00372       if (fullness != oldFullness) {
00373         // Move the superblock.
00374         moveSuperblock (sb, sizeclass, oldFullness, fullness);
00375       }
00376     }
00377   }
00378 
00379   // Either we didn't find a superblock or we did and got a block.
00380   assert ((sb == NULL) || (b != NULL));
00381   // Either we didn't get a block or we did and we also got a superblock.
00382   assert ((b == NULL) || (sb != NULL));
00383 
00384   return sb;
00385 }
00386 
00387 
00388 int hoardHeap::sizeClass (const size_t sz) {
00389   // Find the size class for a given object size
00390   // (the smallest i such that _sizeTable[i] >= sz).
00391   int sizeclass = 0;
00392   while (_sizeTable[sizeclass] < sz) 
00393     {
00394       sizeclass++;
00395       assert (sizeclass < SIZE_CLASSES);
00396     }
00397   return sizeclass;
00398 }
00399 
00400 
00401 size_t hoardHeap::sizeFromClass (const int sizeclass) {
00402   assert (sizeclass >= 0);
00403   assert (sizeclass < SIZE_CLASSES);
00404   return _sizeTable[sizeclass];
00405 }
00406 
00407 
00408 int hoardHeap::getReleaseThreshold (const int sizeclass) {
00409   assert (sizeclass >= 0);
00410   assert (sizeclass < SIZE_CLASSES);
00411   return _threshold[sizeclass];
00412 }
00413 
00414 
00415 int hoardHeap::numBlocks (const int sizeclass) {
00416   assert (sizeclass >= 0);
00417   assert (sizeclass < SIZE_CLASSES);
00418   const size_t s = sizeFromClass (sizeclass);
00419   assert (s > 0);
00420   const int blksize = align (sizeof(block) + s);
00421   // Compute the number of blocks that will go into this superblock.
00422   int nb = MAX (1, ((SUPERBLOCK_SIZE - sizeof(superblock)) / blksize));
00423   return nb;
00424 }
00425 
00426 
00427 void hoardHeap::lock (void) 
00428 {
00429   assert (_magic == HEAP_MAGIC);
00430   hoardLock (_lock);
00431 }
00432 
00433 
00434 void hoardHeap::unlock (void) {
00435   assert (_magic == HEAP_MAGIC);
00436   hoardUnlock (_lock);
00437 }
00438 
00439 
00440 size_t hoardHeap::align (const size_t sz)
00441 {
00442   // Align sz up to the nearest multiple of ALIGNMENT.
00443   // This is much faster than using multiplication
00444   // and division.
00445   return (sz + ALIGNMENT_MASK) & ~((size_t) ALIGNMENT_MASK);
00446 }
00447 
00448 
00449 void hoardHeap::setIndex (int i) 
00450 {
00451   _index = i; 
00452 }
00453 
00454 
00455 int hoardHeap::getIndex (void)
00456 {
00457   return _index;
00458 }
00459 
00460 
00461 
00462 
00463 void hoardHeap::recycle (superblock * sb)
00464 {
00465   assert (sb != NULL);
00466   assert (sb->getOwner() == this);
00467   assert (sb->getNumBlocks() > 1);
00468   assert (sb->getNext() == NULL);
00469   assert (sb->getPrev() == NULL);
00470   assert (hoardHeap::numBlocks(sb->getBlockSizeClass()) > 1);
00471   sb->insertBefore (_reusableSuperblocks);
00472   _reusableSuperblocks = sb;
00473   ++_reusableSuperblocksCount;
00474   // printf ("count: %d => %d\n", getIndex(), _reusableSuperblocksCount);
00475 }
00476 
00477 
00478 superblock * hoardHeap::reuse (int sizeclass)
00479 {
00480   if (_reusableSuperblocks == NULL) {
00481     return NULL;
00482   }
00483 
00484   // Make sure that we aren't using a sizeclass
00485   // that is too big for a 'normal' superblock.
00486   if (hoardHeap::numBlocks(sizeclass) <= 1) {
00487     return NULL;
00488   }
00489 
00490   // Pop off a superblock from the reusable-superblock list.
00491   assert (_reusableSuperblocksCount > 0);
00492   superblock * sb = _reusableSuperblocks;
00493   _reusableSuperblocks = sb->getNext();
00494   sb->remove();
00495   assert (sb->getNumBlocks() > 1);
00496   --_reusableSuperblocksCount;
00497 
00498   // Reformat the superblock if necessary.
00499   if (sb->getBlockSizeClass() != sizeclass) {
00500     decStats (sb->getBlockSizeClass(),
00501               sb->getNumBlocks() - sb->getNumAvailable(),
00502               sb->getNumBlocks());
00503 
00504 
00505     sb->superblock::~superblock();
00506     
00507     sb = new ((char *) sb) superblock (numBlocks(sizeclass), sizeclass, this);
00508 
00509     incStats (sizeclass,
00510               sb->getNumBlocks() - sb->getNumAvailable(),
00511               sb->getNumBlocks());
00512   }
00513 
00514   assert (sb->getOwner() == this);
00515   assert (sb->getBlockSizeClass() == sizeclass);
00516   return sb;
00517 }
00518 
00519 #endif // _HEAP_H_

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