1 ///-*-C++-*-////////////////////////////////////////////////////////////////// 2 // 3 // Hoard: A Fast, Scalable, and Memory-Efficient Allocator 4 // for Shared-Memory Multiprocessors 5 // Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery 6 // 7 // Copyright (c) 1998-2000, The University of Texas at Austin. 8 // 9 // This library is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU Library General Public License as 11 // published by the Free Software Foundation, http://www.fsf.org. 12 // 13 // This library is distributed in the hope that it will be useful, but 14 // WITHOUT ANY WARRANTY; without even the implied warranty of 15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 // Library General Public License for more details. 17 // 18 ////////////////////////////////////////////////////////////////////////////// 19 20 /* We use one processHeap for the whole program. */ 21 22 #ifndef _PROCESSHEAP_H_ 23 #define _PROCESSHEAP_H_ 24 25 #include "config.h" 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 30 #include "arch-specific.h" 31 #include "heap.h" 32 #if USE_PRIVATE_HEAPS 33 # include "privateheap.h" 34 # define HEAPTYPE privateHeap 35 #else 36 # define HEAPTYPE threadHeap 37 # include "threadheap.h" 38 #endif 39 40 #if HEAP_LOG 41 # include "memstat.h" 42 # include "log.h" 43 #endif 44 45 46 namespace BPrivate { 47 48 class processHeap : public hoardHeap { 49 public: 50 // Always grab at least this many superblocks' worth of memory which 51 // we parcel out. 52 enum { REFILL_NUMBER_OF_SUPERBLOCKS = 16 }; 53 54 processHeap(); 55 ~processHeap(void) 56 { 57 #if HEAP_STATS 58 stats(); 59 #endif 60 } 61 // Memory deallocation routines. 62 void free(void *ptr); 63 64 // Print out statistics information. 65 void stats(void); 66 67 // Get a thread heap index. 68 inline int getHeapIndex(void); 69 70 // Get thread heap max. 71 inline int getMaxThreadHeaps(void); 72 73 // Get the thread heap with index i. 74 inline HEAPTYPE & getHeap(int i); 75 76 // Extract a superblock. 77 inline superblock *acquire(const int c, hoardHeap * dest); 78 79 // Get space for a superblock. 80 inline char *getSuperblockBuffer(void); 81 82 // Insert a superblock. 83 inline void release(superblock * sb); 84 85 #if HEAP_LOG 86 // Get the log for index i. 87 inline Log < MemoryRequest > &getLog(int i); 88 #endif 89 90 #if HEAP_FRAG_STATS 91 // Declare that we have allocated an object. 92 void setAllocated(int requestedSize, int actualSize); 93 94 // Declare that we have deallocated an object. 95 void setDeallocated(int requestedSize, int actualSize); 96 97 // Return the number of wasted bytes at the high-water mark 98 // (maxAllocated - maxRequested) 99 inline int getFragmentation(void); 100 101 int 102 getMaxAllocated(void) 103 { 104 return _maxAllocated; 105 } 106 107 int 108 getInUseAtMaxAllocated(void) 109 { 110 return _inUseAtMaxAllocated; 111 } 112 113 int 114 getMaxRequested(void) 115 { 116 return _maxRequested; 117 } 118 #endif 119 120 private: 121 // Hide the lock & unlock methods. 122 void 123 lock(void) 124 { 125 hoardHeap::lock(); 126 } 127 128 void 129 unlock(void) 130 { 131 hoardHeap::unlock(); 132 } 133 134 // Prevent copying and assignment. 135 processHeap(const processHeap &); 136 const processHeap & operator=(const processHeap &); 137 138 // The per-thread heaps. 139 HEAPTYPE* theap; 140 141 #if HEAP_FRAG_STATS 142 // Statistics required to compute fragmentation. We cannot 143 // unintrusively keep track of these on a multiprocessor, because 144 // this would become a bottleneck. 145 146 int _currentAllocated; 147 int _currentRequested; 148 int _maxAllocated; 149 int _maxRequested; 150 int _inUseAtMaxAllocated; 151 int _fragmentation; 152 153 // A lock to protect these statistics. 154 hoardLockType _statsLock; 155 #endif 156 157 #if HEAP_LOG 158 Log < MemoryRequest >* _log; 159 #endif 160 161 // A lock for the superblock buffer. 162 hoardLockType _bufferLock; 163 164 char *_buffer; 165 int _bufferCount; 166 }; 167 168 169 HEAPTYPE & 170 processHeap::getHeap(int i) 171 { 172 assert(theap != NULL); 173 assert(i >= 0); 174 assert(i < fMaxThreadHeaps); 175 return theap[i]; 176 } 177 178 179 #if HEAP_LOG 180 Log<MemoryRequest > & 181 processHeap::getLog(int i) 182 { 183 assert(_log != NULL); 184 assert(i >= 0); 185 assert(i < fMaxThreadHeaps + 1); 186 return _log[i]; 187 } 188 #endif 189 190 191 // Hash out the thread id to a heap and return an index to that heap. 192 193 int 194 processHeap::getHeapIndex(void) 195 { 196 // Here we use the number of processors as the maximum number of heaps. 197 // In fact, for efficiency, we just round up to the highest power of two, 198 // times two. 199 int tid = find_thread(NULL) & _numProcessorsMask; 200 assert(tid < fMaxThreadHeaps); 201 return tid; 202 } 203 204 205 // Return the maximum number of heaps. 206 207 int 208 processHeap::getMaxThreadHeaps(void) 209 { 210 return fMaxThreadHeaps; 211 } 212 213 214 superblock * 215 processHeap::acquire(const int sizeclass, hoardHeap * dest) 216 { 217 lock(); 218 219 // Remove the superblock with the most free space. 220 superblock *maxSb = removeMaxSuperblock(sizeclass); 221 if (maxSb) 222 maxSb->setOwner(dest); 223 224 unlock(); 225 226 return maxSb; 227 } 228 229 230 inline char * 231 processHeap::getSuperblockBuffer(void) 232 { 233 char *buf; 234 hoardLock(_bufferLock); 235 if (_bufferCount == 0) { 236 _buffer = (char *)hoardSbrk(SUPERBLOCK_SIZE 237 * REFILL_NUMBER_OF_SUPERBLOCKS); 238 _bufferCount = REFILL_NUMBER_OF_SUPERBLOCKS; 239 } 240 241 buf = _buffer; 242 _buffer += SUPERBLOCK_SIZE; 243 _bufferCount--; 244 hoardUnlock(_bufferLock); 245 246 return buf; 247 } 248 249 250 // Put a superblock back into our list of superblocks. 251 252 void 253 processHeap::release(superblock *sb) 254 { 255 assert(EMPTY_FRACTION * sb->getNumAvailable() > sb->getNumBlocks()); 256 257 lock(); 258 259 // Insert the superblock. 260 insertSuperblock(sb->getBlockSizeClass(), sb, this); 261 262 unlock(); 263 } 264 265 } // namespace BPrivate 266 267 #endif // _PROCESSHEAP_H_ 268