usermode/library/pmalloc/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 persistentHeap; // forward declaration
00045 
00046 class hoardHeap {
00047 public:
00048 
00049         hoardHeap (void);
00050 
00051         // A thread heap must be at least 1/EMPTY_FRACTION empty before we
00052         // start returning superblocks to the process heap.
00053         enum { EMPTY_FRACTION = SUPERBLOCK_FULLNESS_GROUP - 1 };
00054 
00055         // Reset value for the least-empty bin.  The last bin
00056         // (SUPERBLOCK_FULLNESS_GROUP-1) is for completely full superblocks,
00057         // so we use the next-to-last bin.
00058         enum { RESET_LEAST_EMPTY_BIN = SUPERBLOCK_FULLNESS_GROUP - 2 };
00059 
00060         // The number of empty superblocks that we allow any thread heap to
00061         // hold once the thread heap has fallen below 1/EMPTY_FRACTION
00062         // empty.
00063         enum { MAX_EMPTY_SUPERBLOCKS = 1 } ; // EMPTY_FRACTION / 2 };
00064 
00065         // The maximum number of thread heaps we allow.  (NOT the maximum
00066         // number of threads -- Hoard imposes no such limit.)  This must be
00067         // a power of two! NB: This number is twice the maximum number of
00068         // PROCESSORS supported by Hoard.
00069         enum { MAX_HEAPS = 16 };
00070 
00071         // ANDing with this rounds to MAX_HEAPS.
00072         enum { MAX_HEAPS_MASK = MAX_HEAPS - 1 };
00073 
00074         //
00075         // The number of size classes.
00076         //
00077 
00078         enum { SIZE_CLASSES = 132 };
00079 
00080         // Every object is aligned so that it can always hold a double.
00081         enum { ALIGNMENT = sizeof(double) };
00082 
00083         // ANDing with this rounds to ALIGNMENT.
00084         enum { ALIGNMENT_MASK = ALIGNMENT - 1};
00085 
00086         // Used for sanity checking.
00087         enum { HEAP_MAGIC = 0x0badcafe };
00088 
00089         // Get the usage and allocated statistics.
00090         inline void getStats (int sizeclass, int& U, int& A);
00091 
00092 
00093 #if HEAP_STATS
00094         // How much is the maximum ever in use for this size class?
00095         inline int maxInUse (int sizeclass);
00096 
00097         // How much is the maximum memory allocated for this size class?
00098         inline int maxAllocated (int sizeclass);
00099 #endif
00100 
00101         // Insert a superblock into our list.
00102         void insertSuperblock (int sizeclass,
00103                                superblock * sb,
00104                                persistentHeap * persistentheap);
00105 
00106         // Remove the superblock with the most free space.
00107         superblock * removeMaxSuperblock (int sizeclass);
00108 
00109         // Remove a superblock of some given fullness.
00110         superblock * removePartiallyFullSuperblock (int fullness, int sizeclass);
00111 
00112         // Find an available superblock (i.e., with some space in it).
00113         superblock * findAvailableSuperblock (int sizeclass,
00114                                               block *& b,
00115                                               persistentHeap * persistentheap);
00116 
00117         // Lock this heap.
00118         inline void lock (void);
00119 
00120         // Unlock this heap.
00121         inline void unlock (void);
00122 
00123         // Set our index number (which heap we are).
00124         inline void setIndex (int i);
00125 
00126         // Get our index number (which heap we are).
00127         inline int getIndex (void);
00128 
00129         // Free a block into a superblock.
00130         // This is used by processHeap::free().
00131         // Returns 1 iff the superblock was munmapped.
00132         int freeBlock (block *& b,
00133                        superblock *& sb,
00134                        int sizeclass,
00135                        persistentHeap * persistentheap);
00136 
00138 
00139         // Return the size class for a given size.
00140         inline static int sizeClass (const size_t sz);
00141 
00142         // Return the size corresponding to a given size class.
00143         inline static size_t sizeFromClass (const int sizeclass);
00144 
00145         // Return the release threshold corresponding to a given size class.
00146         inline static int getReleaseThreshold (const int sizeclass);
00147 
00148         // Return how many blocks of a given size class fit into a superblock.
00149         inline static int numBlocks (const int sizeclass);
00150 
00151         // Align a value.
00152         inline static size_t align (const size_t sz);
00153 
00154         void printSuperblockList();
00155 private:
00156 
00157         // Disable copying and assignment.
00158 
00159         hoardHeap (const hoardHeap&);
00160         const hoardHeap& operator= (const hoardHeap&);
00161 
00162         // Recycle a superblock.
00163         inline void recycle (superblock *);
00164 
00165         // Reuse a superblock (if one is available).
00166         inline superblock * reuse (int sizeclass);
00167 
00168         // Remove a particular superblock.
00169         inline void removeSuperblock (superblock *, int sizeclass);
00170 
00171 public:
00172         // Move a particular superblock from one bin to another.
00173         void moveSuperblock (superblock *,
00174                              int sizeclass,
00175                              int fromBin,
00176                              int toBin);
00177 private:
00178 
00179         // Update memory in-use and allocated statistics.
00180         // (*UStats = just update U.)
00181         inline void incStats (int sizeclass, int updateU, int updateA);
00182 
00183 public:
00184         inline void incUStats (int sizeclass);
00185 private:
00186 
00187         inline void decStats (int sizeclass, int updateU, int updateA);
00188         inline void decUStats (int sizeclass);
00189 
00191 
00192 #if HEAP_DEBUG
00193         // For sanity checking.
00194         const unsigned long _magic;
00195 #else
00196   #define _magic HEAP_MAGIC
00197 #endif
00198 
00199   // Heap statistics.
00200   heapStats     _stats[SIZE_CLASSES];
00201 
00202   // The per-heap lock.
00203   hoardLockType _lock;
00204 
00205   // Which heap this is (0 = the process (global) heap).
00206   int _index;
00207 
00208   // Reusable superblocks.
00209   superblock *  _reusableSuperblocks;
00210   int           _reusableSuperblocksCount;
00211 
00212   // Lists of superblocks.
00213   superblock *  _superblocks[SUPERBLOCK_FULLNESS_GROUP][SIZE_CLASSES];
00214 
00215   // The current least-empty superblock bin.
00216   int   _leastEmptyBin[SIZE_CLASSES];
00217 
00218   // The lookup table for size classes.
00219   static size_t _sizeTable[SIZE_CLASSES];
00220 
00221   // The lookup table for release thresholds.
00222   static size_t _threshold[SIZE_CLASSES];
00223 
00224 public:
00225   // A little helper class that we use to define some statics.
00226   class _initNumProcs {
00227   public:
00228         _initNumProcs(void);
00229   };
00230 
00231   friend class _initNumProcs;
00232 protected:
00233   // number of CPUs, cached
00234   static int _numProcessors;
00235   static int _numProcessorsMask;
00236 };
00237 
00238 
00239 
00240 void hoardHeap::incStats (int sizeclass, int updateU, int updateA) {
00241   assert (_magic == HEAP_MAGIC);
00242   assert (updateU >= 0);
00243   assert (updateA >= 0);
00244   assert (sizeclass >= 0);
00245   assert (sizeclass < SIZE_CLASSES);
00246   _stats[sizeclass].incStats (updateU, updateA);
00247 }
00248 
00249 
00250 
00251 void hoardHeap::incUStats (int sizeclass) {
00252   assert (_magic == HEAP_MAGIC);
00253   assert (sizeclass >= 0);
00254   assert (sizeclass < SIZE_CLASSES);
00255   _stats[sizeclass].incUStats ();
00256 }
00257 
00258 
00259 void hoardHeap::decStats (int sizeclass, int updateU, int updateA) {
00260   assert (_magic == HEAP_MAGIC);
00261   assert (updateU >= 0);
00262   assert (updateA >= 0);
00263   assert (sizeclass >= 0);
00264   assert (sizeclass < SIZE_CLASSES);
00265   _stats[sizeclass].decStats (updateU, updateA);
00266 }
00267 
00268 
00269 void hoardHeap::decUStats (int sizeclass)
00270 {
00271   assert (_magic == HEAP_MAGIC);
00272   assert (sizeclass >= 0);
00273   assert (sizeclass < SIZE_CLASSES);
00274   _stats[sizeclass].decUStats();
00275 }
00276 
00277 
00278 void hoardHeap::getStats (int sizeclass, int& U, int& A) {
00279   assert (_magic == HEAP_MAGIC);
00280   assert (sizeclass >= 0);
00281   assert (sizeclass < SIZE_CLASSES);
00282   _stats[sizeclass].getStats (U, A);
00283 }
00284 
00285 
00286 #if HEAP_STATS
00287 int hoardHeap::maxInUse (int sizeclass) {
00288   assert (_magic == HEAP_MAGIC);
00289   return _stats[sizeclass].getUmax();
00290 }
00291 
00292 
00293 int hoardHeap::maxAllocated (int sizeclass) {
00294   assert (_magic == HEAP_MAGIC);
00295   return _stats[sizeclass].getAmax(); 
00296 }
00297 #endif
00298 
00299 
00300 int hoardHeap::sizeClass (const size_t sz) {
00301   // Find the size class for a given object size
00302   // (the smallest i such that _sizeTable[i] >= sz).
00303   int sizeclass = 0;
00304   while (_sizeTable[sizeclass] < sz) 
00305     {
00306       sizeclass++;
00307       assert (sizeclass < SIZE_CLASSES);
00308     }
00309   return sizeclass;
00310 }
00311 
00312 
00313 size_t hoardHeap::sizeFromClass (const int sizeclass) {
00314   assert (sizeclass >= 0);
00315   assert (sizeclass < SIZE_CLASSES);
00316   return _sizeTable[sizeclass];
00317 }
00318 
00319 
00320 int hoardHeap::getReleaseThreshold (const int sizeclass) {
00321   assert (sizeclass >= 0);
00322   assert (sizeclass < SIZE_CLASSES);
00323   return _threshold[sizeclass];
00324 }
00325 
00326 
00327 int hoardHeap::numBlocks (const int sizeclass) {
00328   assert (sizeclass >= 0);
00329   assert (sizeclass < SIZE_CLASSES);
00330   const size_t s = sizeFromClass (sizeclass);
00331   assert (s > 0);
00332   const int blksize = align (s);
00333   // Compute the number of blocks that will go into this superblock.
00334   int nb =  MAX (1, ((SUPERBLOCK_SIZE) / blksize));
00335   return nb;
00336 }
00337 
00338 
00339 void hoardHeap::lock (void) 
00340 {
00341   assert (_magic == HEAP_MAGIC);
00342   hoardLock (_lock);
00343 }
00344 
00345 
00346 void hoardHeap::unlock (void) {
00347   assert (_magic == HEAP_MAGIC);
00348   hoardUnlock (_lock);
00349 }
00350 
00351 
00352 size_t hoardHeap::align (const size_t sz)
00353 {
00354   // Align sz up to the nearest multiple of ALIGNMENT.
00355   // This is much faster than using multiplication
00356   // and division.
00357   return (sz + ALIGNMENT_MASK) & ~((size_t) ALIGNMENT_MASK);
00358 }
00359 
00360 
00361 void hoardHeap::setIndex (int i) 
00362 {
00363   _index = i; 
00364 }
00365 
00366 
00367 int hoardHeap::getIndex (void)
00368 {
00369   return _index;
00370 }
00371 
00372 
00373 
00374 
00375 void hoardHeap::recycle (superblock * sb)
00376 {
00377         assert (sb != NULL);
00378         assert (sb->getOwner() == this);
00379         assert (sb->getNumBlocks() > 1);
00380         assert (sb->getNext() == NULL);
00381         assert (sb->getPrev() == NULL);
00382         assert (hoardHeap::numBlocks(sb->getBlockSizeClass()) > 1);
00383         sb->insertBefore (_reusableSuperblocks);
00384         _reusableSuperblocks = sb;
00385         ++_reusableSuperblocksCount;
00386         //printf ("hoardHeap::recycle: heap = %d, count = %d, sb = %p\n", getIndex(), _reusableSuperblocksCount, sb);
00387 }
00388 
00389 
00390 superblock * hoardHeap::reuse (int sizeclass)
00391 { 
00392   persistentSuperblock *psb;
00393 
00394   if (_reusableSuperblocks == NULL) {
00395     return NULL;
00396   }
00397 
00398   // Make sure that we aren't using a sizeclass
00399   // that is too big for a 'normal' superblock.
00400   if (hoardHeap::numBlocks(sizeclass) <= 1) {
00401     return NULL;
00402   }
00403 
00404   // Pop off a superblock from the reusable-superblock list.
00405   assert (_reusableSuperblocksCount > 0);
00406   superblock * sb = _reusableSuperblocks;
00407   _reusableSuperblocks = sb->getNext();
00408   sb->remove();
00409   psb = sb->getPersistentSuperblock();
00410   assert (psb != NULL);
00411   assert (sb->getNumBlocks() > 1);
00412   --_reusableSuperblocksCount;
00413 
00414   // Reformat the superblock if necessary.
00415   if (sb->getBlockSizeClass() != sizeclass) {
00416     decStats (sb->getBlockSizeClass(),
00417               sb->getNumBlocks() - sb->getNumAvailable(),
00418               sb->getNumBlocks());
00419     sb->superblock::~superblock();
00420     
00421         //FIXME: what to do with stats inc/dec? do I need to reflect those to the persistent superblock?
00422         //FIXME: what to do with the persistent superblock? keep the same
00423         assert(psb->isFree() == true); // persistent superblock must be free to change its sizeclass
00424         int new_blksize = sizeFromClass(sizeclass);
00425         psb->setBlockSize(new_blksize);
00426 
00427         // BEGIN HACK
00428         // Look at the hack note  under the persistentSuperblock constuctor to see why we reallocate
00429         // memory. Original Hoard didn't do this.
00430         char *buf;
00431         unsigned long moreMemory;
00432 
00433         moreMemory = hoardHeap::align(sizeof(superblock) + (hoardHeap::align (sizeof(block)) * numBlocks(sizeclass)));
00434         // Get some memory from the process heap.
00435         buf = (char *) hoardGetMemory (moreMemory);
00436     //sb = new ((char *) sb) superblock (numBlocks(sizeclass), sizeclass, this, psb);
00437     sb = new ((char *) buf) superblock (numBlocks(sizeclass), sizeclass, this, psb);
00438         // END HACK
00439 
00440     psb->setSuperblock(sb);
00441 
00442     incStats (sizeclass,
00443               sb->getNumBlocks() - sb->getNumAvailable(),
00444               sb->getNumBlocks());
00445   }
00446 
00447   assert (sb->getOwner() == this);
00448   assert (sb->getBlockSizeClass() == sizeclass);
00449   return sb;
00450 }
00451 
00452 #endif // _HEAP_H_

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