xref: /haiku/src/system/libroot/posix/malloc/hoard2/processheap.h (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
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