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