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(void); 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 the thread heap with index i. 71 inline HEAPTYPE & getHeap(int i); 72 73 // Extract a superblock. 74 inline superblock *acquire(const int c, hoardHeap * dest); 75 76 // Get space for a superblock. 77 inline char *getSuperblockBuffer(void); 78 79 // Insert a superblock. 80 inline void release(superblock * sb); 81 82#if HEAP_LOG 83 // Get the log for index i. 84 inline Log < MemoryRequest > &getLog(int i); 85#endif 86 87#if HEAP_FRAG_STATS 88 // Declare that we have allocated an object. 89 void setAllocated(int requestedSize, int actualSize); 90 91 // Declare that we have deallocated an object. 92 void setDeallocated(int requestedSize, int actualSize); 93 94 // Return the number of wasted bytes at the high-water mark 95 // (maxAllocated - maxRequested) 96 inline int getFragmentation(void); 97 98 int 99 getMaxAllocated(void) 100 { 101 return _maxAllocated; 102 } 103 104 int 105 getInUseAtMaxAllocated(void) 106 { 107 return _inUseAtMaxAllocated; 108 } 109 110 int 111 getMaxRequested(void) 112 { 113 return _maxRequested; 114 } 115#endif 116 117 private: 118 // Hide the lock & unlock methods. 119 void 120 lock(void) 121 { 122 hoardHeap::lock(); 123 } 124 125 void 126 unlock(void) 127 { 128 hoardHeap::unlock(); 129 } 130 131 // Prevent copying and assignment. 132 processHeap(const processHeap &); 133 const processHeap & operator=(const processHeap &); 134 135 // The per-thread heaps. 136 HEAPTYPE theap[MAX_HEAPS]; 137 138#if HEAP_FRAG_STATS 139 // Statistics required to compute fragmentation. We cannot 140 // unintrusively keep track of these on a multiprocessor, because 141 // this would become a bottleneck. 142 143 int _currentAllocated; 144 int _currentRequested; 145 int _maxAllocated; 146 int _maxRequested; 147 int _inUseAtMaxAllocated; 148 int _fragmentation; 149 150 // A lock to protect these statistics. 151 hoardLockType _statsLock; 152#endif 153 154#if HEAP_LOG 155 Log < MemoryRequest > _log[MAX_HEAPS + 1]; 156#endif 157 158 // A lock for the superblock buffer. 159 hoardLockType _bufferLock; 160 161 char *_buffer; 162 int _bufferCount; 163}; 164 165 166HEAPTYPE & 167processHeap::getHeap(int i) 168{ 169 assert(i >= 0); 170 assert(i < MAX_HEAPS); 171 return theap[i]; 172} 173 174 175#if HEAP_LOG 176Log<MemoryRequest > & 177processHeap::getLog(int i) 178{ 179 assert(i >= 0); 180 assert(i < MAX_HEAPS + 1); 181 return _log[i]; 182} 183#endif 184 185 186// Hash out the thread id to a heap and return an index to that heap. 187 188int 189processHeap::getHeapIndex(void) 190{ 191 // Here we use the number of processors as the maximum number of heaps. 192 // In fact, for efficiency, we just round up to the highest power of two, 193 // times two. 194 int tid = find_thread(NULL) & _numProcessorsMask; 195 assert(tid < MAX_HEAPS); 196 return tid; 197} 198 199 200superblock * 201processHeap::acquire(const int sizeclass, hoardHeap * dest) 202{ 203 lock(); 204 205 // Remove the superblock with the most free space. 206 superblock *maxSb = removeMaxSuperblock(sizeclass); 207 if (maxSb) 208 maxSb->setOwner(dest); 209 210 unlock(); 211 212 return maxSb; 213} 214 215 216inline char * 217processHeap::getSuperblockBuffer(void) 218{ 219 char *buf; 220 hoardLock(_bufferLock); 221 if (_bufferCount == 0) { 222 _buffer = (char *)hoardSbrk(SUPERBLOCK_SIZE 223 * REFILL_NUMBER_OF_SUPERBLOCKS); 224 _bufferCount = REFILL_NUMBER_OF_SUPERBLOCKS; 225 } 226 227 buf = _buffer; 228 _buffer += SUPERBLOCK_SIZE; 229 _bufferCount--; 230 hoardUnlock(_bufferLock); 231 232 return buf; 233} 234 235 236// Put a superblock back into our list of superblocks. 237 238void 239processHeap::release(superblock *sb) 240{ 241 assert(EMPTY_FRACTION * sb->getNumAvailable() > sb->getNumBlocks()); 242 243 lock(); 244 245 // Insert the superblock. 246 insertSuperblock(sb->getBlockSizeClass(), sb, this); 247 248 unlock(); 249} 250 251} // namespace BPrivate 252 253#endif // _PROCESSHEAP_H_ 254