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();
~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 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
getMaxAllocated(void)102 getMaxAllocated(void)
103 {
104 return _maxAllocated;
105 }
106
107 int
getInUseAtMaxAllocated(void)108 getInUseAtMaxAllocated(void)
109 {
110 return _inUseAtMaxAllocated;
111 }
112
113 int
getMaxRequested(void)114 getMaxRequested(void)
115 {
116 return _maxRequested;
117 }
118 #endif
119
120 private:
121 // Hide the lock & unlock methods.
122 void
lock(void)123 lock(void)
124 {
125 hoardHeap::lock();
126 }
127
128 void
unlock(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 &
getHeap(int i)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 > &
getLog(int i)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
getHeapIndex(void)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
getMaxThreadHeaps(void)208 processHeap::getMaxThreadHeaps(void)
209 {
210 return fMaxThreadHeaps;
211 }
212
213
214 superblock *
acquire(const int sizeclass,hoardHeap * dest)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 *
getSuperblockBuffer(void)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
release(superblock * sb)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