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