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 46namespace BPrivate { 47 48class 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 169HEAPTYPE & 170processHeap::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 180Log<MemoryRequest > & 181processHeap::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 193int 194processHeap::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 207int 208processHeap::getMaxThreadHeaps(void) 209{ 210 return fMaxThreadHeaps; 211} 212 213 214superblock * 215processHeap::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 230inline char * 231processHeap::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 252void 253processHeap::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