Applied our coding style, but all clases into the BPrivate namespace.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11953 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-03-22 22:59:41 +00:00
parent f05dec1ea0
commit f557016851
13 changed files with 1569 additions and 1449 deletions
@@ -33,6 +33,7 @@ extern "C" {
#include <OS.h>
#include <unistd.h>
using namespace BPrivate;
static area_id heap_region = -1;
static addr_t brk;
+104 -77
View File
@@ -24,148 +24,175 @@
//#include <assert.h>
namespace BPrivate {
class superblock;
class block {
public:
block (superblock * sb)
:
public:
block(superblock * sb)
:
#if HEAP_DEBUG
_magic (FREE_BLOCK_MAGIC),
_magic(FREE_BLOCK_MAGIC),
#endif
_next (NULL),
_mySuperblock (sb)
{}
_next(NULL), _mySuperblock(sb)
{
}
block& operator= (const block& b) {
block &
operator=(const block & b)
{
#if HEAP_DEBUG
_magic = b._magic;
_magic = b._magic;
#endif
_next = b._next;
_mySuperblock = b._mySuperblock;
_next = b._next;
_mySuperblock = b._mySuperblock;
#if HEAP_FRAG_STATS
_requestedSize = b._requestedSize;
_requestedSize = b._requestedSize;
#endif
return *this;
}
return *this;
}
enum { ALLOCATED_BLOCK_MAGIC = 0xcafecafe,
FREE_BLOCK_MAGIC = 0xbabebabe };
enum {
ALLOCATED_BLOCK_MAGIC = 0xcafecafe,
FREE_BLOCK_MAGIC = 0xbabebabe
};
// Mark this block as free.
inline void markFree (void);
// Mark this block as free.
inline void markFree(void);
// Mark this block as allocated.
inline void markAllocated (void);
// Mark this block as allocated.
inline void markAllocated(void);
// Is this block valid? (i.e.,
// does it have the right magic number?)
inline const int isValid (void) const;
// Is this block valid? (i.e.,
// does it have the right magic number?)
inline const int isValid(void) const;
// Return the block's superblock pointer.
inline superblock * getSuperblock (void);
// Return the block's superblock pointer.
inline superblock *getSuperblock(void);
#if HEAP_FRAG_STATS
void setRequestedSize (size_t s)
{
_requestedSize = s;
}
void
setRequestedSize(size_t s)
{
_requestedSize = s;
}
size_t getRequestedSize (void) { return _requestedSize; }
size_t
getRequestedSize(void)
{
return _requestedSize;
}
#endif
#if USE_PRIVATE_HEAPS
void setActualSize (size_t s) { _actualSize = s; }
size_t getActualSize (void) { return _actualSize; }
void
setActualSize(size_t s)
{
_actualSize = s;
}
size_t
getActualSize(void)
{
return _actualSize;
}
#endif
void
setNext(block * b)
{
_next = b;
}
void setNext (block * b) { _next = b; }
block * getNext (void) { return _next; }
private:
block *
getNext(void)
{
return _next;
}
private:
#if USE_PRIVATE_HEAPS
#if HEAP_DEBUG
union {
unsigned long _magic;
double _d1; // For alignment.
};
union {
unsigned long _magic;
double _d1; // For alignment.
};
#endif
block * _next; // The next block in a linked-list of blocks.
size_t _actualSize; // The actual size of the block.
union {
double _d2; // For alignment.
superblock * _mySuperblock; // A pointer to my superblock.
};
block *_next; // The next block in a linked-list of blocks.
size_t _actualSize; // The actual size of the block.
union {
double _d2; // For alignment.
superblock *_mySuperblock; // A pointer to my superblock.
};
#else // ! USE_PRIVATE_HEAPS
#if HEAP_DEBUG
union {
unsigned long _magic;
double _d3; // For alignment.
};
union {
unsigned long _magic;
double _d3; // For alignment.
};
#endif
block * _next; // The next block in a linked-list of blocks.
superblock * _mySuperblock; // A pointer to my superblock.
block *_next; // The next block in a linked-list of blocks.
superblock *_mySuperblock; // A pointer to my superblock.
#endif // USE_PRIVATE_HEAPS
#if HEAP_FRAG_STATS
union {
double _d4; // This is just for alignment purposes.
size_t _requestedSize; // The amount of space requested (vs. allocated).
};
union {
double _d4; // This is just for alignment purposes.
size_t _requestedSize; // The amount of space requested (vs. allocated).
};
#endif
// Disable copying.
block (const block&);
// Disable copying.
block(const block &);
};
superblock * block::getSuperblock (void)
superblock *
block::getSuperblock(void)
{
#if HEAP_DEBUG
assert (isValid());
assert(isValid());
#endif
return _mySuperblock;
return _mySuperblock;
}
void block::markFree (void)
void
block::markFree(void)
{
#if HEAP_DEBUG
assert (_magic == ALLOCATED_BLOCK_MAGIC);
_magic = FREE_BLOCK_MAGIC;
assert(_magic == ALLOCATED_BLOCK_MAGIC);
_magic = FREE_BLOCK_MAGIC;
#endif
}
void block::markAllocated (void)
void
block::markAllocated(void)
{
#if HEAP_DEBUG
assert (_magic == FREE_BLOCK_MAGIC);
_magic = ALLOCATED_BLOCK_MAGIC;
assert(_magic == FREE_BLOCK_MAGIC);
_magic = ALLOCATED_BLOCK_MAGIC;
#endif
}
const int block::isValid (void) const
const int
block::isValid(void) const
{
#if HEAP_DEBUG
return ((_magic == FREE_BLOCK_MAGIC)
|| (_magic == ALLOCATED_BLOCK_MAGIC));
return _magic == FREE_BLOCK_MAGIC
|| _magic == ALLOCATED_BLOCK_MAGIC;
#else
return 1;
return 1;
#endif
}
} // namespace BPrivate
#endif // _BLOCK_H_
+7 -8
View File
@@ -20,11 +20,11 @@
#define _CONFIG_H_
#ifndef _REENTRANT
#define _REENTRANT // If defined, generate a multithreaded-capable version.
# define _REENTRANT // If defined, generate a multithreaded-capable version.
#endif
#ifndef USER_LOCKS
#define USER_LOCKS 1 // Use our own user-level locks if they're available for the current architecture.
# define USER_LOCKS 1 // Use our own user-level locks if they're available for the current architecture.
#endif
#define HEAP_LOG 0 // If non-zero, keep a log of heap accesses.
@@ -63,15 +63,15 @@ enum { SUPERBLOCK_FULLNESS_GROUP = 9 };
// CACHE_LINE = The number of bytes in a cache line.
#if defined(i386) || defined(WIN32)
#define CACHE_LINE 32
# define CACHE_LINE 32
#endif
#ifdef sparc
#define CACHE_LINE 64
# define CACHE_LINE 64
#endif
#ifdef __sgi
#define CACHE_LINE 128
# define CACHE_LINE 128
#endif
#ifndef CACHE_LINE
@@ -82,11 +82,10 @@ enum { SUPERBLOCK_FULLNESS_GROUP = 9 };
#ifdef __GNUG__
// Use the max operator, an extension to C++ found in GNU C++.
#define MAX(a,b) ((a) >? (b))
# define MAX(a,b) ((a) >? (b))
#else
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
# define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
#endif // _CONFIG_H_
+302 -251
View File
@@ -16,6 +16,7 @@
// Library General Public License for more details.
//
//////////////////////////////////////////////////////////////////////////////
#include "config.h"
#include "heap.h"
@@ -23,7 +24,7 @@
#include "processheap.h"
#include "superblock.h"
static const char version[] = "The Hoard memory allocator, version 2.0 (http://www.hoard.org). Copyright (C) 1998, 1999, 2000 The University of Texas at Austin. $Id: heap.cpp,v 1.2 2005/02/10 18:47:16 axeld Exp $";
using namespace BPrivate;
// NB: Use maketable.cpp to update this
// if SIZE_CLASSES, ALIGNMENT, SIZE_CLASS_BASE, MAX_EMPTY_SUPERBLOCKS,
@@ -31,354 +32,404 @@ static const char version[] = "The Hoard memory allocator, version 2.0 (http://w
#if (MAX_INTERNAL_FRAGMENTATION == 2)
size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {8UL, 16UL, 24UL, 32UL, 40UL, 48UL, 56UL, 72UL, 80UL, 96UL, 120UL, 144UL, 168UL, 200UL, 240UL, 288UL, 344UL, 416UL, 496UL, 592UL, 712UL, 856UL, 1024UL, 1232UL, 1472UL, 1768UL, 2120UL, 2544UL, 3048UL, 3664UL, 4392UL, 5272UL, 6320UL, 7584UL, 9104UL, 10928UL, 13112UL, 15728UL, 18872UL, 22648UL, 27176UL, 32616UL, 39136UL, 46960UL, 56352UL, 67624UL, 81144UL, 97376UL, 116848UL, 140216UL, 168256UL, 201904UL, 242288UL, 290744UL, 348896UL, 418672UL, 502408UL, 602888UL, 723464UL, 868152UL, 1041784UL, 1250136UL, 1500160UL, 1800192UL, 2160232UL, 2592280UL, 3110736UL, 3732880UL, 4479456UL, 5375344UL, 6450408UL, 7740496UL, 9288592UL, 11146312UL, 13375568UL, 16050680UL, 19260816UL, 23112984UL, 27735576UL, 33282688UL, 39939224UL, 47927072UL, 57512488UL, 69014984UL, 82817976UL, 99381576UL, 119257888UL, 143109472UL, 171731360UL, 206077632UL, 247293152UL, 296751776UL, 356102144UL, 427322560UL, 512787072UL, 615344512UL, 738413376UL, 886096064UL, 1063315264UL};
size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {
8UL, 16UL, 24UL, 32UL, 40UL, 48UL, 56UL, 72UL, 80UL, 96UL, 120UL, 144UL,
168UL, 200UL, 240UL, 288UL, 344UL, 416UL, 496UL, 592UL, 712UL, 856UL,
1024UL, 1232UL, 1472UL, 1768UL, 2120UL, 2544UL, 3048UL, 3664UL,
4392UL, 5272UL, 6320UL, 7584UL, 9104UL, 10928UL, 13112UL, 15728UL,
18872UL, 22648UL, 27176UL, 32616UL, 39136UL, 46960UL, 56352UL,
67624UL, 81144UL, 97376UL, 116848UL, 140216UL, 168256UL, 201904UL,
242288UL, 290744UL, 348896UL, 418672UL, 502408UL, 602888UL, 723464UL,
868152UL, 1041784UL, 1250136UL, 1500160UL, 1800192UL, 2160232UL,
2592280UL, 3110736UL, 3732880UL, 4479456UL, 5375344UL, 6450408UL,
7740496UL, 9288592UL, 11146312UL, 13375568UL, 16050680UL, 19260816UL,
23112984UL, 27735576UL, 33282688UL, 39939224UL, 47927072UL,
57512488UL, 69014984UL, 82817976UL, 99381576UL, 119257888UL,
143109472UL, 171731360UL, 206077632UL, 247293152UL, 296751776UL,
356102144UL, 427322560UL, 512787072UL, 615344512UL, 738413376UL,
886096064UL, 1063315264UL
};
size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {4096UL, 2048UL, 1364UL, 1024UL, 816UL, 680UL, 584UL, 452UL, 408UL, 340UL, 272UL, 224UL, 192UL, 160UL, 136UL, 112UL, 92UL, 76UL, 64UL, 52UL, 44UL, 36UL, 32UL, 24UL, 20UL, 16UL, 12UL, 12UL, 8UL, 8UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL};
size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {
4096UL, 2048UL, 1364UL, 1024UL, 816UL, 680UL, 584UL, 452UL, 408UL,
340UL, 272UL, 224UL, 192UL, 160UL, 136UL, 112UL, 92UL, 76UL, 64UL,
52UL, 44UL, 36UL, 32UL, 24UL, 20UL, 16UL, 12UL, 12UL, 8UL, 8UL, 4UL,
4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL
};
#elif (MAX_INTERNAL_FRAGMENTATION == 6)
size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {8UL, 16UL, 24UL, 32UL, 48UL, 72UL, 112UL, 176UL, 288UL, 456UL, 728UL, 1160UL, 1848UL, 2952UL, 4728UL, 7560UL, 12096UL, 19344UL, 30952UL, 49520UL, 79232UL, 126768UL, 202832UL, 324520UL, 519232UL, 830768UL, 1329232UL, 2126768UL, 3402824UL, 5444520UL, 8711232UL, 13937968UL, 22300752UL, 35681200UL, 57089912UL, 91343856UL, 146150176UL, 233840256UL, 374144416UL, 598631040UL, 957809728UL, 1532495488UL};
size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {
8UL, 16UL, 24UL, 32UL, 48UL, 72UL, 112UL, 176UL, 288UL, 456UL, 728UL,
1160UL, 1848UL, 2952UL, 4728UL, 7560UL, 12096UL, 19344UL, 30952UL,
49520UL, 79232UL, 126768UL, 202832UL, 324520UL, 519232UL, 830768UL,
1329232UL, 2126768UL, 3402824UL, 5444520UL, 8711232UL, 13937968UL,
22300752UL, 35681200UL, 57089912UL, 91343856UL, 146150176UL,
233840256UL, 374144416UL, 598631040UL, 957809728UL, 1532495488UL
};
size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {4096UL, 2048UL, 1364UL, 1024UL, 680UL, 452UL, 292UL, 184UL, 112UL, 68UL, 44UL, 28UL, 16UL, 8UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL};
size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {
4096UL, 2048UL, 1364UL, 1024UL, 680UL, 452UL, 292UL, 184UL, 112UL, 68UL,
44UL, 28UL, 16UL, 8UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
4UL, 4UL, 4UL, 4UL, 4UL
};
#elif (MAX_INTERNAL_FRAGMENTATION == 10)
size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {8UL, 16UL, 32UL, 64UL, 128UL, 256UL, 512UL, 1024UL, 2048UL, 4096UL, 8192UL, 16384UL, 32768UL, 65536UL, 131072UL, 262144UL, 524288UL, 1048576UL, 2097152UL, 4194304UL, 8388608UL, 16777216UL, 33554432UL, 67108864UL, 134217728UL, 268435456UL, 536870912UL, 1073741824UL, 2147483648UL};
size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {
8UL, 16UL, 32UL, 64UL, 128UL, 256UL, 512UL, 1024UL, 2048UL, 4096UL,
8192UL, 16384UL, 32768UL, 65536UL, 131072UL, 262144UL, 524288UL,
1048576UL, 2097152UL, 4194304UL, 8388608UL, 16777216UL, 33554432UL,
67108864UL, 134217728UL, 268435456UL, 536870912UL, 1073741824UL,
2147483648UL
};
size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {4096UL, 2048UL, 1024UL, 512UL, 256UL, 128UL, 64UL, 32UL, 16UL, 8UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL};
size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {
4096UL, 2048UL, 1024UL, 512UL, 256UL, 128UL, 64UL, 32UL, 16UL, 8UL, 4UL,
4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
4UL, 4UL, 4UL, 4UL
};
#else
#error "Undefined size class base."
# error "Undefined size class base."
#endif
hoardHeap::hoardHeap (void)
: _index (0),
_reusableSuperblocks (NULL),
_reusableSuperblocksCount (0)
hoardHeap::hoardHeap(void)
:
_index(0), _reusableSuperblocks(NULL), _reusableSuperblocksCount(0)
#if HEAP_DEBUG
, _magic (HEAP_MAGIC)
, _magic(HEAP_MAGIC)
#endif
{
// Initialize the per-heap lock.
hoardLockInit(_lock, "hoard heap");
for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
for (int j = 0; j < SIZE_CLASSES; j++) {
// Initialize all superblocks lists to empty.
_superblocks[i][j] = NULL;
}
}
for (int k = 0; k < SIZE_CLASSES; k++) {
_leastEmptyBin[k] = 0;
}
// Initialize the per-heap lock.
hoardLockInit(_lock, "hoard heap");
for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
for (int j = 0; j < SIZE_CLASSES; j++) {
// Initialize all superblocks lists to empty.
_superblocks[i][j] = NULL;
}
}
for (int k = 0; k < SIZE_CLASSES; k++) {
_leastEmptyBin[k] = 0;
}
}
void hoardHeap::insertSuperblock (int sizeclass,
superblock * sb,
processHeap * pHeap)
void
hoardHeap::insertSuperblock(int sizeclass,
superblock *sb, processHeap *pHeap)
{
assert (sb->isValid());
assert (sb->getBlockSizeClass() == sizeclass);
assert (sb->getPrev() == NULL);
assert (sb->getNext() == NULL);
assert (_magic == HEAP_MAGIC);
assert(sb->isValid());
assert(sb->getBlockSizeClass() == sizeclass);
assert(sb->getPrev() == NULL);
assert(sb->getNext() == NULL);
assert(_magic == HEAP_MAGIC);
// Now it's ours.
sb->setOwner (this);
// Now it's ours.
sb->setOwner(this);
// How full is this superblock? We'll use this information to put
// it into the right 'bin'.
sb->computeFullness();
int fullness = sb->getFullness();
// How full is this superblock? We'll use this information to put
// it into the right 'bin'.
sb->computeFullness();
int fullness = sb->getFullness();
// Update the stats.
incStats (sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
// Update the stats.
incStats(sizeclass, sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
if ((fullness == 0) &&
(sb->getNumBlocks() > 1) &&
(sb->getNumBlocks() == sb->getNumAvailable())) {
// Recycle this superblock.
if (fullness == 0
&& sb->getNumBlocks() > 1
&& sb->getNumBlocks() == sb->getNumAvailable()) {
// Recycle this superblock.
#if 0
removeSuperblock (sb, sizeclass);
// Update the stats.
decStats (sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
// Free it immediately.
const size_t s = sizeFromClass (sizeclass);
const int blksize = align (sizeof(block) + s);
removeSuperblock(sb, sizeclass);
// Update the stats.
decStats(sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
// Free it immediately.
const size_t s = sizeFromClass(sizeclass);
const int blksize = align(sizeof(block) + s);
#if HEAP_LOG
// Record the memory deallocation.
MemoryRequest m;
m.deallocate ((int) sb->getNumBlocks() * (int) sizeFromClass(sb->getBlockSizeClass()));
pHeap->getLog(getIndex()).append(m);
// Record the memory deallocation.
MemoryRequest m;
m.deallocate((int)sb->getNumBlocks() *
(int)sizeFromClass(sb->getBlockSizeClass()));
pHeap->getLog(getIndex()).append(m);
#endif
#if HEAP_FRAG_STATS
pHeap->setDeallocated (0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
pHeap->setDeallocated(0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
#endif
hoardUnsbrk (sb, align (sizeof(superblock) + blksize));
hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
#else
recycle (sb);
recycle(sb);
#endif
} else {
} else {
// Insert it into the appropriate list.
superblock *&head = _superblocks[fullness][sizeclass];
sb->insertBefore(head);
head = sb;
assert(head->isValid());
// Insert it into the appropriate list.
superblock *& head = _superblocks[fullness][sizeclass];
sb->insertBefore (head);
head = sb;
assert (head->isValid());
// Reset the least-empty bin counter.
_leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
}
// Reset the least-empty bin counter.
_leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
}
}
superblock * hoardHeap::removeMaxSuperblock (int sizeclass)
superblock *
hoardHeap::removeMaxSuperblock(int sizeclass)
{
assert (_magic == HEAP_MAGIC);
assert(_magic == HEAP_MAGIC);
superblock * head = NULL;
superblock *head = NULL;
// First check the reusable superblocks list.
// First check the reusable superblocks list.
head = reuse (sizeclass);
if (head) {
// We found one. Since we're removing this superblock, update the
// stats accordingly.
decStats (sizeclass,
head->getNumBlocks() - head->getNumAvailable(),
head->getNumBlocks());
head = reuse(sizeclass);
if (head) {
// We found one. Since we're removing this superblock, update the
// stats accordingly.
decStats(sizeclass,
head->getNumBlocks() - head->getNumAvailable(),
head->getNumBlocks());
return head;
}
return head;
}
// Instead of finding the superblock with the most available space
// (something that would either involve a linear scan through the
// superblocks or maintaining the superblocks in sorted order), we
// just pick one that is no more than
// 1/(SUPERBLOCK_FULLNESS_GROUP-1) more full than the superblock
// with the most available space. We start with the emptiest group.
// Instead of finding the superblock with the most available space
// (something that would either involve a linear scan through the
// superblocks or maintaining the superblocks in sorted order), we
// just pick one that is no more than
// 1/(SUPERBLOCK_FULLNESS_GROUP-1) more full than the superblock
// with the most available space. We start with the emptiest group.
int i = 0;
int i = 0;
// Note: the last group (SUPERBLOCK_FULLNESS_GROUP - 1) is full, so
// we never need to check it. But for robustness, we leave it in.
while (i < SUPERBLOCK_FULLNESS_GROUP) {
head = _superblocks[i][sizeclass];
if (head) {
break;
}
i++;
}
// Note: the last group (SUPERBLOCK_FULLNESS_GROUP - 1) is full, so
// we never need to check it. But for robustness, we leave it in.
while (i < SUPERBLOCK_FULLNESS_GROUP) {
head = _superblocks[i][sizeclass];
if (head)
break;
if (!head) {
return NULL;
}
i++;
}
// Make sure that this superblock is at least 1/EMPTY_FRACTION
// empty.
assert (head->getNumAvailable() * EMPTY_FRACTION >= head->getNumBlocks());
if (!head)
return NULL;
removeSuperblock (head, sizeclass);
// Make sure that this superblock is at least 1/EMPTY_FRACTION
// empty.
assert(head->getNumAvailable() * EMPTY_FRACTION >= head->getNumBlocks());
assert (head->isValid());
assert (head->getPrev() == NULL);
assert (head->getNext() == NULL);
return head;
removeSuperblock(head, sizeclass);
assert(head->isValid());
assert(head->getPrev() == NULL);
assert(head->getNext() == NULL);
return head;
}
void hoardHeap::removeSuperblock (superblock * sb,
int sizeclass)
void
hoardHeap::removeSuperblock(superblock *sb, int sizeclass)
{
assert (_magic == HEAP_MAGIC);
assert(_magic == HEAP_MAGIC);
assert (sb->isValid());
assert (sb->getOwner() == this);
assert (sb->getBlockSizeClass() == sizeclass);
assert(sb->isValid());
assert(sb->getOwner() == this);
assert(sb->getBlockSizeClass() == sizeclass);
for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
if (sb == _superblocks[i][sizeclass]) {
_superblocks[i][sizeclass] = sb->getNext();
if (_superblocks[i][sizeclass] != NULL) {
assert (_superblocks[i][sizeclass]->isValid());
}
break;
}
}
for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
if (sb == _superblocks[i][sizeclass]) {
_superblocks[i][sizeclass] = sb->getNext();
if (_superblocks[i][sizeclass] != NULL) {
assert(_superblocks[i][sizeclass]->isValid());
}
break;
}
}
sb->remove();
decStats (sizeclass, sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
sb->remove();
decStats(sizeclass, sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
}
void hoardHeap::moveSuperblock (superblock * sb,
int sizeclass,
int fromBin,
int toBin)
void
hoardHeap::moveSuperblock(superblock *sb,
int sizeclass, int fromBin, int toBin)
{
assert (_magic == HEAP_MAGIC);
assert (sb->isValid());
assert (sb->getOwner() == this);
assert (sb->getBlockSizeClass() == sizeclass);
assert (sb->getFullness() == toBin);
assert(_magic == HEAP_MAGIC);
assert(sb->isValid());
assert(sb->getOwner() == this);
assert(sb->getBlockSizeClass() == sizeclass);
assert(sb->getFullness() == toBin);
// Remove the superblock from the old bin.
// Remove the superblock from the old bin.
superblock *& oldHead = _superblocks[fromBin][sizeclass];
if (sb == oldHead) {
oldHead = sb->getNext();
if (oldHead != NULL) {
assert (oldHead->isValid());
}
}
superblock *&oldHead = _superblocks[fromBin][sizeclass];
if (sb == oldHead) {
oldHead = sb->getNext();
if (oldHead != NULL) {
assert(oldHead->isValid());
}
}
sb->remove();
sb->remove();
// Insert the superblock into the new bin.
// Insert the superblock into the new bin.
superblock *& newHead = _superblocks[toBin][sizeclass];
sb->insertBefore (newHead);
newHead = sb;
assert (newHead->isValid());
superblock *&newHead = _superblocks[toBin][sizeclass];
sb->insertBefore(newHead);
newHead = sb;
assert(newHead->isValid());
// Reset the least-empty bin counter.
_leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
// Reset the least-empty bin counter.
_leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
}
// The heap lock must be held when this procedure is called.
int hoardHeap::freeBlock (block *& b,
superblock *& sb,
int sizeclass,
processHeap * pHeap)
int
hoardHeap::freeBlock(block * &b, superblock * &sb,
int sizeclass, processHeap *pHeap)
{
assert (sb->isValid());
assert (b->isValid());
assert (this == sb->getOwner());
assert(sb->isValid());
assert(b->isValid());
assert(this == sb->getOwner());
const int oldFullness = sb->getFullness();
sb->putBlock (b);
decUStats (sizeclass);
const int newFullness = sb->getFullness();
// Free big superblocks.
if (sb->getNumBlocks() == 1) {
removeSuperblock (sb, sizeclass);
const size_t s = sizeFromClass (sizeclass);
const int blksize = align (sizeof(block) + s);
const int oldFullness = sb->getFullness();
sb->putBlock(b);
decUStats(sizeclass);
const int newFullness = sb->getFullness();
// Free big superblocks.
if (sb->getNumBlocks() == 1) {
removeSuperblock(sb, sizeclass);
const size_t s = sizeFromClass(sizeclass);
const int blksize = align(sizeof(block) + s);
#if HEAP_LOG
// Record the memory deallocation.
MemoryRequest m;
m.deallocate ((int) sb->getNumBlocks() * (int) sizeFromClass(sb->getBlockSizeClass()));
pHeap->getLog(getIndex()).append(m);
// Record the memory deallocation.
MemoryRequest m;
m.deallocate((int)sb->getNumBlocks()
* (int)sizeFromClass(sb->getBlockSizeClass()));
pHeap->getLog(getIndex()).append(m);
#endif
#if HEAP_FRAG_STATS
pHeap->setDeallocated (0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
pHeap->setDeallocated(0,
sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
#endif
hoardUnsbrk (sb, align (sizeof(superblock) + blksize));
return 1;
}
hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
return 1;
}
// If the fullness value has changed, move the superblock.
if (newFullness != oldFullness) {
moveSuperblock (sb, sizeclass, oldFullness, newFullness);
} else {
// Move the superblock to the front of its list (to reduce
// paging).
superblock *& head = _superblocks[newFullness][sizeclass];
if (sb != head) {
sb->remove();
sb->insertBefore (head);
head = sb;
}
}
// If the superblock is now empty, recycle it.
// If the fullness value has changed, move the superblock.
if (newFullness != oldFullness) {
moveSuperblock(sb, sizeclass, oldFullness, newFullness);
} else {
// Move the superblock to the front of its list (to reduce
// paging).
superblock *&head = _superblocks[newFullness][sizeclass];
if (sb != head) {
sb->remove();
sb->insertBefore(head);
head = sb;
}
}
if ((newFullness == 0) &&
(sb->getNumBlocks() == sb->getNumAvailable())) {
removeSuperblock (sb, sizeclass);
// If the superblock is now empty, recycle it.
if ((newFullness == 0) && (sb->getNumBlocks() == sb->getNumAvailable())) {
removeSuperblock(sb, sizeclass);
#if 0
// Free it immediately.
const size_t s = sizeFromClass (sizeclass);
const int blksize = align (sizeof(block) + s);
// Free it immediately.
const size_t s = sizeFromClass(sizeclass);
const int blksize = align(sizeof(block) + s);
#if HEAP_LOG
// Record the memory deallocation.
MemoryRequest m;
m.deallocate ((int) sb->getNumBlocks() * (int) sizeFromClass(sb->getBlockSizeClass()));
pHeap->getLog(getIndex()).append(m);
// Record the memory deallocation.
MemoryRequest m;
m.deallocate((int)sb->getNumBlocks()
* (int)sizeFromClass(sb->getBlockSizeClass()));
pHeap->getLog(getIndex()).append(m);
#endif
#if HEAP_FRAG_STATS
pHeap->setDeallocated (0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
pHeap->setDeallocated(0,
sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
#endif
hoardUnsbrk (sb, align (sizeof(superblock) + blksize));
return 1;
hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
return 1;
#else
recycle (sb);
// Update the stats. This restores the stats to their state
// before the call to removeSuperblock, above.
incStats (sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
recycle(sb);
// Update the stats. This restores the stats to their state
// before the call to removeSuperblock, above.
incStats(sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
#endif
}
}
// If this is the process heap, then we're done.
if (this == (hoardHeap *) pHeap) {
return 0;
}
// If this is the process heap, then we're done.
if (this == (hoardHeap *)pHeap)
return 0;
//
// Release a superblock, if necessary.
//
//
// Release a superblock, if necessary.
//
//
// Check to see if the amount free exceeds the release threshold
// (two superblocks worth of blocks for a given sizeclass) and if
// the heap is sufficiently empty.
//
//
// Check to see if the amount free exceeds the release threshold
// (two superblocks worth of blocks for a given sizeclass) and if
// the heap is sufficiently empty.
//
// We never move anything to the process heap if we're on a
// uniprocessor.
if (_numProcessors > 1) {
int inUse, allocated;
getStats (sizeclass, inUse, allocated);
if ((inUse < allocated - getReleaseThreshold(sizeclass))
&& (EMPTY_FRACTION * inUse < EMPTY_FRACTION * allocated - allocated)) {
// We've crossed the magical threshold. Find the superblock with
// the most free blocks and give it to the process heap.
superblock * const maxSb = removeMaxSuperblock (sizeclass);
assert (maxSb != NULL);
// Update the statistics.
assert (maxSb->getNumBlocks() >= maxSb->getNumAvailable());
// Give the superblock back to the process heap.
pHeap->release (maxSb);
}
}
// We never move anything to the process heap if we're on a
// uniprocessor.
if (_numProcessors > 1) {
int inUse, allocated;
getStats(sizeclass, inUse, allocated);
if ((inUse < allocated - getReleaseThreshold(sizeclass))
&& (EMPTY_FRACTION * inUse <
EMPTY_FRACTION * allocated - allocated)) {
return 0;
// We've crossed the magical threshold. Find the superblock with
// the most free blocks and give it to the process heap.
superblock *const maxSb = removeMaxSuperblock(sizeclass);
assert(maxSb != NULL);
// Update the statistics.
assert(maxSb->getNumBlocks() >= maxSb->getNumAvailable());
// Give the superblock back to the process heap.
pHeap->release(maxSb);
}
}
return 0;
}
// Static initialization of the number of processors (and a mask).
int hoardHeap::_numProcessors;
int hoardHeap::_numProcessorsMask;
hoardHeap::_initNumProcs::_initNumProcs(void)
{
hoardHeap::_numProcessors = hoardGetNumProcessors();
hoardHeap::_numProcessorsMask = (1 << (lg(hoardGetNumProcessors()) + 1)) - 1;
hoardHeap::_numProcessors = hoardGetNumProcessors();
hoardHeap::_numProcessorsMask =
(1 << (lg(hoardGetNumProcessors()) + 1)) - 1;
}
static hoardHeap::_initNumProcs initProcs;
+383 -365
View File
@@ -30,485 +30,503 @@
#include "superblock.h"
#include "heapstats.h"
class processHeap; // forward declaration
namespace BPrivate {
class processHeap;
class hoardHeap {
public:
hoardHeap(void);
public:
// A superblock that holds more than one object must hold at least
// this many bytes.
enum { SUPERBLOCK_SIZE = 8192 };
hoardHeap (void);
// A thread heap must be at least 1/EMPTY_FRACTION empty before we
// start returning superblocks to the process heap.
enum { EMPTY_FRACTION = SUPERBLOCK_FULLNESS_GROUP - 1 };
// A superblock that holds more than one object must hold at least
// this many bytes.
enum { SUPERBLOCK_SIZE = 8192 };
// Reset value for the least-empty bin. The last bin
// (SUPERBLOCK_FULLNESS_GROUP-1) is for completely full superblocks,
// so we use the next-to-last bin.
enum { RESET_LEAST_EMPTY_BIN = SUPERBLOCK_FULLNESS_GROUP - 2 };
// A thread heap must be at least 1/EMPTY_FRACTION empty before we
// start returning superblocks to the process heap.
enum { EMPTY_FRACTION = SUPERBLOCK_FULLNESS_GROUP - 1 };
// The number of empty superblocks that we allow any thread heap to
// hold once the thread heap has fallen below 1/EMPTY_FRACTION
// empty.
enum { MAX_EMPTY_SUPERBLOCKS = EMPTY_FRACTION };
// Reset value for the least-empty bin. The last bin
// (SUPERBLOCK_FULLNESS_GROUP-1) is for completely full superblocks,
// so we use the next-to-last bin.
enum { RESET_LEAST_EMPTY_BIN = SUPERBLOCK_FULLNESS_GROUP - 2 };
// The maximum number of thread heaps we allow. (NOT the maximum
// number of threads -- Hoard imposes no such limit.) This must be
// a power of two! NB: This number is twice the maximum number of
// PROCESSORS supported by Hoard.
enum { MAX_HEAPS = B_MAX_CPU_COUNT };
// The number of empty superblocks that we allow any thread heap to
// hold once the thread heap has fallen below 1/EMPTY_FRACTION
// empty.
enum { MAX_EMPTY_SUPERBLOCKS = EMPTY_FRACTION };
// ANDing with this rounds to MAX_HEAPS.
enum { MAX_HEAPS_MASK = MAX_HEAPS - 1 };
// The maximum number of thread heaps we allow. (NOT the maximum
// number of threads -- Hoard imposes no such limit.) This must be
// a power of two! NB: This number is twice the maximum number of
// PROCESSORS supported by Hoard.
enum { MAX_HEAPS = B_MAX_CPU_COUNT };
// ANDing with this rounds to MAX_HEAPS.
enum { MAX_HEAPS_MASK = MAX_HEAPS - 1 };
//
// The number of size classes. This combined with the
// SIZE_CLASS_BASE determine the maximum size of an object.
//
// NB: Once this is changed, you must execute maketable.cpp and put
// the generated values into heap.cpp.
//
// The number of size classes. This combined with the
// SIZE_CLASS_BASE determine the maximum size of an object.
//
// NB: Once this is changed, you must execute maketable.cpp and put
// the generated values into heap.cpp.
#if MAX_INTERNAL_FRAGMENTATION == 2
enum { SIZE_CLASSES = 115 };
enum { SIZE_CLASSES = 115 };
#elif MAX_INTERNAL_FRAGMENTATION == 6
enum { SIZE_CLASSES = 46 };
enum { SIZE_CLASSES = 46 };
#elif MAX_INTERNAL_FRAGMENTATION == 10
enum { SIZE_CLASSES = 32 };
enum { SIZE_CLASSES = 32 };
#else
# error "Undefined size class base."
#endif
// Every object is aligned so that it can always hold a double.
enum { ALIGNMENT = sizeof(double) };
// Every object is aligned so that it can always hold a double.
enum { ALIGNMENT = sizeof(double) };
// ANDing with this rounds to ALIGNMENT.
enum { ALIGNMENT_MASK = ALIGNMENT - 1};
// ANDing with this rounds to ALIGNMENT.
enum { ALIGNMENT_MASK = ALIGNMENT - 1 };
// Used for sanity checking.
enum { HEAP_MAGIC = 0x0badcafe };
// Used for sanity checking.
enum { HEAP_MAGIC = 0x0badcafe };
// Get the usage and allocated statistics.
inline void getStats (int sizeclass, int& U, int& A);
// Get the usage and allocated statistics.
inline void getStats(int sizeclass, int &U, int &A);
#if HEAP_STATS
// How much is the maximum ever in use for this size class?
inline int maxInUse (int sizeclass);
// How much is the maximum ever in use for this size class?
inline int maxInUse(int sizeclass);
// How much is the maximum memory allocated for this size class?
inline int maxAllocated (int sizeclass);
// How much is the maximum memory allocated for this size class?
inline int maxAllocated(int sizeclass);
#endif
// Insert a superblock into our list.
void insertSuperblock (int sizeclass,
superblock * sb,
processHeap * pHeap);
// Insert a superblock into our list.
void insertSuperblock(int sizeclass, superblock *sb, processHeap *pHeap);
// Remove the superblock with the most free space.
superblock * removeMaxSuperblock (int sizeclass);
// Remove the superblock with the most free space.
superblock *removeMaxSuperblock(int sizeclass);
// Find an available superblock (i.e., with some space in it).
inline superblock * findAvailableSuperblock (int sizeclass,
block *& b,
processHeap * pHeap);
// Find an available superblock (i.e., with some space in it).
inline superblock *findAvailableSuperblock(int sizeclass,
block * &b, processHeap * pHeap);
// Lock this heap.
inline void lock (void);
// Lock this heap.
inline void lock(void);
// Unlock this heap.
inline void unlock (void);
// Unlock this heap.
inline void unlock(void);
// Set our index number (which heap we are).
inline void setIndex (int i);
// Set our index number (which heap we are).
inline void setIndex(int i);
// Get our index number (which heap we are).
inline int getIndex (void);
// Get our index number (which heap we are).
inline int getIndex(void);
// Free a block into a superblock.
// This is used by processHeap::free().
// Returns 1 iff the superblock was munmapped.
int freeBlock (block *& b,
superblock *& sb,
int sizeclass,
processHeap * pHeap);
// Free a block into a superblock.
// This is used by processHeap::free().
// Returns 1 iff the superblock was munmapped.
int freeBlock(block * &b, superblock * &sb, int sizeclass,
processHeap * pHeap);
//// Utility functions ////
//// Utility functions ////
// Return the size class for a given size.
inline static int sizeClass (const size_t sz);
// Return the size class for a given size.
inline static int sizeClass(const size_t sz);
// Return the size corresponding to a given size class.
inline static size_t sizeFromClass (const int sizeclass);
// Return the size corresponding to a given size class.
inline static size_t sizeFromClass(const int sizeclass);
// Return the release threshold corresponding to a given size class.
inline static int getReleaseThreshold (const int sizeclass);
// Return the release threshold corresponding to a given size class.
inline static int getReleaseThreshold(const int sizeclass);
// Return how many blocks of a given size class fit into a superblock.
inline static int numBlocks (const int sizeclass);
// Return how many blocks of a given size class fit into a superblock.
inline static int numBlocks(const int sizeclass);
// Align a value.
inline static size_t align (const size_t sz);
// Align a value.
inline static size_t align(const size_t sz);
private:
private:
// Disable copying and assignment.
// Disable copying and assignment.
hoardHeap(const hoardHeap &);
const hoardHeap & operator=(const hoardHeap &);
hoardHeap (const hoardHeap&);
const hoardHeap& operator= (const hoardHeap&);
// Recycle a superblock.
inline void recycle(superblock *);
// Recycle a superblock.
inline void recycle (superblock *);
// Reuse a superblock (if one is available).
inline superblock *reuse(int sizeclass);
// Reuse a superblock (if one is available).
inline superblock * reuse (int sizeclass);
// Remove a particular superblock.
void removeSuperblock(superblock *, int sizeclass);
// Remove a particular superblock.
void removeSuperblock (superblock *, int sizeclass);
// Move a particular superblock from one bin to another.
void moveSuperblock(superblock *,
int sizeclass, int fromBin, int toBin);
// Move a particular superblock from one bin to another.
void moveSuperblock (superblock *,
int sizeclass,
int fromBin,
int toBin);
// Update memory in-use and allocated statistics.
// (*UStats = just update U.)
inline void incStats(int sizeclass, int updateU, int updateA);
inline void incUStats(int sizeclass);
// Update memory in-use and allocated statistics.
// (*UStats = just update U.)
inline void incStats (int sizeclass, int updateU, int updateA);
inline void incUStats (int sizeclass);
inline void decStats(int sizeclass, int updateU, int updateA);
inline void decUStats(int sizeclass);
inline void decStats (int sizeclass, int updateU, int updateA);
inline void decUStats (int sizeclass);
//// Members ////
//// Members ////
#if HEAP_DEBUG
// For sanity checking.
const unsigned long _magic;
// For sanity checking.
const unsigned long _magic;
#else
# define _magic HEAP_MAGIC
#endif
// Heap statistics.
heapStats _stats[SIZE_CLASSES];
// Heap statistics.
heapStats _stats[SIZE_CLASSES];
// The per-heap lock.
hoardLockType _lock;
// The per-heap lock.
hoardLockType _lock;
// Which heap this is (0 = the process (global) heap).
int _index;
// Which heap this is (0 = the process (global) heap).
int _index;
// Reusable superblocks.
superblock * _reusableSuperblocks;
int _reusableSuperblocksCount;
// Reusable superblocks.
superblock *_reusableSuperblocks;
int _reusableSuperblocksCount;
// Lists of superblocks.
superblock * _superblocks[SUPERBLOCK_FULLNESS_GROUP][SIZE_CLASSES];
// Lists of superblocks.
superblock *_superblocks[SUPERBLOCK_FULLNESS_GROUP][SIZE_CLASSES];
// The current least-empty superblock bin.
int _leastEmptyBin[SIZE_CLASSES];
// The current least-empty superblock bin.
int _leastEmptyBin[SIZE_CLASSES];
// The lookup table for size classes.
static size_t _sizeTable[SIZE_CLASSES];
// The lookup table for size classes.
static size_t _sizeTable[SIZE_CLASSES];
// The lookup table for release thresholds.
static size_t _threshold[SIZE_CLASSES];
// The lookup table for release thresholds.
static size_t _threshold[SIZE_CLASSES];
public:
// A little helper class that we use to define some statics.
class _initNumProcs {
public:
_initNumProcs(void);
};
public:
// A little helper class that we use to define some statics.
class _initNumProcs {
public:
_initNumProcs(void);
};
friend class _initNumProcs;
protected:
// number of CPUs, cached
static int _numProcessors;
static int _numProcessorsMask;
friend class _initNumProcs;
protected:
// number of CPUs, cached
static int _numProcessors;
static int _numProcessorsMask;
};
void hoardHeap::incStats (int sizeclass, int updateU, int updateA) {
assert (_magic == HEAP_MAGIC);
assert (updateU >= 0);
assert (updateA >= 0);
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
_stats[sizeclass].incStats (updateU, updateA);
}
void hoardHeap::incUStats (int sizeclass) {
assert (_magic == HEAP_MAGIC);
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
_stats[sizeclass].incUStats ();
}
void hoardHeap::decStats (int sizeclass, int updateU, int updateA) {
assert (_magic == HEAP_MAGIC);
assert (updateU >= 0);
assert (updateA >= 0);
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
_stats[sizeclass].decStats (updateU, updateA);
}
void hoardHeap::decUStats (int sizeclass)
void
hoardHeap::incStats(int sizeclass, int updateU, int updateA)
{
assert (_magic == HEAP_MAGIC);
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
_stats[sizeclass].decUStats();
assert(_magic == HEAP_MAGIC);
assert(updateU >= 0);
assert(updateA >= 0);
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
_stats[sizeclass].incStats(updateU, updateA);
}
void hoardHeap::getStats (int sizeclass, int& U, int& A) {
assert (_magic == HEAP_MAGIC);
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
_stats[sizeclass].getStats (U, A);
void
hoardHeap::incUStats(int sizeclass)
{
assert(_magic == HEAP_MAGIC);
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
_stats[sizeclass].incUStats();
}
void
hoardHeap::decStats(int sizeclass, int updateU, int updateA)
{
assert(_magic == HEAP_MAGIC);
assert(updateU >= 0);
assert(updateA >= 0);
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
_stats[sizeclass].decStats(updateU, updateA);
}
void
hoardHeap::decUStats(int sizeclass)
{
assert(_magic == HEAP_MAGIC);
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
_stats[sizeclass].decUStats();
}
void
hoardHeap::getStats(int sizeclass, int &U, int &A)
{
assert(_magic == HEAP_MAGIC);
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
_stats[sizeclass].getStats(U, A);
}
#if HEAP_STATS
int hoardHeap::maxInUse (int sizeclass) {
assert (_magic == HEAP_MAGIC);
return _stats[sizeclass].getUmax();
}
int hoardHeap::maxAllocated (int sizeclass) {
assert (_magic == HEAP_MAGIC);
return _stats[sizeclass].getAmax();
}
#endif
superblock * hoardHeap::findAvailableSuperblock (int sizeclass,
block *& b,
processHeap * pHeap)
int
hoardHeap::maxInUse(int sizeclass)
{
assert (this);
assert (_magic == HEAP_MAGIC);
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
assert(_magic == HEAP_MAGIC);
return _stats[sizeclass].getUmax();
}
superblock * sb = NULL;
int reUsed = 0;
// Look through the superblocks, starting with the almost-full ones
// and going to the emptiest ones. The Least Empty Bin for a
// sizeclass is a conservative approximation (fixed after one
// iteration) of the first bin that has superblocks in it, starting
// with (surprise) the least-empty bin.
int
hoardHeap::maxAllocated(int sizeclass)
{
assert(_magic == HEAP_MAGIC);
return _stats[sizeclass].getAmax();
}
#endif // HEAP_STATS
for (int i = _leastEmptyBin[sizeclass]; i >= 0; i--) {
sb = _superblocks[i][sizeclass];
if (sb == NULL) {
if (i == _leastEmptyBin[sizeclass]) {
// There wasn't a superblock in this bin,
// so we adjust the least empty bin.
_leastEmptyBin[sizeclass]--;
}
} else if(sb->getNumAvailable() > 0){
assert (sb->getOwner() == this);
break;
}
sb = NULL;
}
superblock *
hoardHeap::findAvailableSuperblock(int sizeclass,
block * &b, processHeap * pHeap)
{
assert(this);
assert(_magic == HEAP_MAGIC);
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
superblock *sb = NULL;
int reUsed = 0;
// Look through the superblocks, starting with the almost-full ones
// and going to the emptiest ones. The Least Empty Bin for a
// sizeclass is a conservative approximation (fixed after one
// iteration) of the first bin that has superblocks in it, starting
// with (surprise) the least-empty bin.
for (int i = _leastEmptyBin[sizeclass]; i >= 0; i--) {
sb = _superblocks[i][sizeclass];
if (sb == NULL) {
if (i == _leastEmptyBin[sizeclass]) {
// There wasn't a superblock in this bin,
// so we adjust the least empty bin.
_leastEmptyBin[sizeclass]--;
}
} else if (sb->getNumAvailable() > 0) {
assert(sb->getOwner() == this);
break;
}
sb = NULL;
}
#if 1
if (sb == NULL) {
// Try to reuse a superblock.
sb = reuse (sizeclass);
if (sb) {
assert (sb->getOwner() == this);
reUsed = 1;
}
}
if (sb == NULL) {
// Try to reuse a superblock.
sb = reuse(sizeclass);
if (sb) {
assert(sb->getOwner() == this);
reUsed = 1;
}
}
#endif
if (sb != NULL) {
// Sanity checks:
// This superblock is 'valid'.
assert (sb->isValid());
// This superblock has the right ownership.
assert (sb->getOwner() == this);
if (sb != NULL) {
// Sanity checks:
// This superblock is 'valid'.
assert(sb->isValid());
// This superblock has the right ownership.
assert(sb->getOwner() == this);
int oldFullness = sb->getFullness();
int oldFullness = sb->getFullness();
// Now get a block from the superblock.
// This superblock must have space available.
b = sb->getBlock();
assert (b != NULL);
// Now get a block from the superblock.
// This superblock must have space available.
b = sb->getBlock();
assert(b != NULL);
// Update the stats.
incUStats (sizeclass);
// Update the stats.
incUStats(sizeclass);
if (reUsed) {
insertSuperblock (sizeclass, sb, pHeap);
// Fix the stats (since insert will just have incremented them
// by this amount).
decStats (sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
} else {
// If we've crossed a fullness group,
// move the superblock.
int fullness = sb->getFullness();
if (reUsed) {
insertSuperblock(sizeclass, sb, pHeap);
// Fix the stats (since insert will just have incremented them
// by this amount).
decStats(sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
} else {
// If we've crossed a fullness group,
// move the superblock.
int fullness = sb->getFullness();
if (fullness != oldFullness) {
// Move the superblock.
moveSuperblock (sb, sizeclass, oldFullness, fullness);
}
}
}
if (fullness != oldFullness) {
// Move the superblock.
moveSuperblock(sb, sizeclass, oldFullness, fullness);
}
}
}
// Either we didn't find a superblock or we did and got a block.
assert((sb == NULL) || (b != NULL));
// Either we didn't get a block or we did and we also got a superblock.
assert((b == NULL) || (sb != NULL));
// Either we didn't find a superblock or we did and got a block.
assert ((sb == NULL) || (b != NULL));
// Either we didn't get a block or we did and we also got a superblock.
assert ((b == NULL) || (sb != NULL));
return sb;
return sb;
}
int hoardHeap::sizeClass (const size_t sz) {
// Find the size class for a given object size
// (the smallest i such that _sizeTable[i] >= sz).
int sizeclass = 0;
while (_sizeTable[sizeclass] < sz)
{
sizeclass++;
assert (sizeclass < SIZE_CLASSES);
}
return sizeclass;
}
size_t hoardHeap::sizeFromClass (const int sizeclass) {
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
return _sizeTable[sizeclass];
}
int hoardHeap::getReleaseThreshold (const int sizeclass) {
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
return _threshold[sizeclass];
}
int hoardHeap::numBlocks (const int sizeclass) {
assert (sizeclass >= 0);
assert (sizeclass < SIZE_CLASSES);
const size_t s = sizeFromClass (sizeclass);
assert (s > 0);
const int blksize = align (sizeof(block) + s);
// Compute the number of blocks that will go into this superblock.
int nb = MAX (1, ((SUPERBLOCK_SIZE - sizeof(superblock)) / blksize));
return nb;
}
void hoardHeap::lock (void)
int
hoardHeap::sizeClass(const size_t sz)
{
assert (_magic == HEAP_MAGIC);
hoardLock (_lock);
// Find the size class for a given object size
// (the smallest i such that _sizeTable[i] >= sz).
int sizeclass = 0;
while (_sizeTable[sizeclass] < sz) {
sizeclass++;
assert(sizeclass < SIZE_CLASSES);
}
return sizeclass;
}
void hoardHeap::unlock (void) {
assert (_magic == HEAP_MAGIC);
hoardUnlock (_lock);
}
size_t hoardHeap::align (const size_t sz)
size_t
hoardHeap::sizeFromClass(const int sizeclass)
{
// Align sz up to the nearest multiple of ALIGNMENT.
// This is much faster than using multiplication
// and division.
return (sz + ALIGNMENT_MASK) & ~ALIGNMENT_MASK;
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
return _sizeTable[sizeclass];
}
void hoardHeap::setIndex (int i)
int
hoardHeap::getReleaseThreshold(const int sizeclass)
{
_index = i;
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
return _threshold[sizeclass];
}
int hoardHeap::getIndex (void)
int
hoardHeap::numBlocks(const int sizeclass)
{
return _index;
assert(sizeclass >= 0);
assert(sizeclass < SIZE_CLASSES);
const size_t s = sizeFromClass(sizeclass);
assert(s > 0);
const int blksize = align(sizeof(block) + s);
// Compute the number of blocks that will go into this superblock.
int nb = MAX(1, ((SUPERBLOCK_SIZE - sizeof(superblock)) / blksize));
return nb;
}
void hoardHeap::recycle (superblock * sb)
void
hoardHeap::lock(void)
{
assert (sb != NULL);
assert (sb->getOwner() == this);
assert (sb->getNumBlocks() > 1);
assert (sb->getNext() == NULL);
assert (sb->getPrev() == NULL);
assert (hoardHeap::numBlocks(sb->getBlockSizeClass()) > 1);
sb->insertBefore (_reusableSuperblocks);
_reusableSuperblocks = sb;
++_reusableSuperblocksCount;
// printf ("count: %d => %d\n", getIndex(), _reusableSuperblocksCount);
assert(_magic == HEAP_MAGIC);
hoardLock(_lock);
}
superblock * hoardHeap::reuse (int sizeclass)
void
hoardHeap::unlock(void)
{
if (_reusableSuperblocks == NULL) {
return NULL;
}
// Make sure that we aren't using a sizeclass
// that is too big for a 'normal' superblock.
if (hoardHeap::numBlocks(sizeclass) <= 1) {
return NULL;
}
// Pop off a superblock from the reusable-superblock list.
assert (_reusableSuperblocksCount > 0);
superblock * sb = _reusableSuperblocks;
_reusableSuperblocks = sb->getNext();
sb->remove();
assert (sb->getNumBlocks() > 1);
--_reusableSuperblocksCount;
// Reformat the superblock if necessary.
if (sb->getBlockSizeClass() != sizeclass) {
decStats (sb->getBlockSizeClass(),
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
sb = new ((char *) sb) superblock (numBlocks(sizeclass), sizeclass, this);
incStats (sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
}
assert (sb->getOwner() == this);
assert (sb->getBlockSizeClass() == sizeclass);
return sb;
assert(_magic == HEAP_MAGIC);
hoardUnlock(_lock);
}
size_t
hoardHeap::align(const size_t sz)
{
// Align sz up to the nearest multiple of ALIGNMENT.
// This is much faster than using multiplication
// and division.
return (sz + ALIGNMENT_MASK) & ~ALIGNMENT_MASK;
}
void
hoardHeap::setIndex(int i)
{
_index = i;
}
int
hoardHeap::getIndex(void)
{
return _index;
}
void
hoardHeap::recycle(superblock *sb)
{
assert(sb != NULL);
assert(sb->getOwner() == this);
assert(sb->getNumBlocks() > 1);
assert(sb->getNext() == NULL);
assert(sb->getPrev() == NULL);
assert(hoardHeap::numBlocks(sb->getBlockSizeClass()) > 1);
sb->insertBefore(_reusableSuperblocks);
_reusableSuperblocks = sb;
++_reusableSuperblocksCount;
// printf ("count: %d => %d\n", getIndex(), _reusableSuperblocksCount);
}
superblock *
hoardHeap::reuse(int sizeclass)
{
if (_reusableSuperblocks == NULL)
return NULL;
// Make sure that we aren't using a sizeclass
// that is too big for a 'normal' superblock.
if (hoardHeap::numBlocks(sizeclass) <= 1)
return NULL;
// Pop off a superblock from the reusable-superblock list.
assert(_reusableSuperblocksCount > 0);
superblock *sb = _reusableSuperblocks;
_reusableSuperblocks = sb->getNext();
sb->remove();
assert(sb->getNumBlocks() > 1);
--_reusableSuperblocksCount;
// Reformat the superblock if necessary.
if (sb->getBlockSizeClass() != sizeclass) {
decStats(sb->getBlockSizeClass(),
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
sb = new((char *)sb) superblock(numBlocks(sizeclass),
sizeclass, this);
incStats(sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
}
assert(sb->getOwner() == this);
assert(sb->getBlockSizeClass() == sizeclass);
return sb;
}
} // namespace BPrivate
#endif // _HEAP_H_
+92 -90
View File
@@ -26,148 +26,150 @@
class heapStats {
public:
heapStats (void)
:
U (0),
A (0)
public:
heapStats(void)
: U(0), A(0)
#if HEAP_STATS
,Umax (0),
Amax (0)
, Umax(0), Amax(0)
#endif
{}
{
}
inline const heapStats& operator= (const heapStats& p);
inline const heapStats & operator=(const heapStats & p);
inline void incStats (int updateU, int updateA);
inline void incUStats (void);
inline void incStats(int updateU, int updateA);
inline void incUStats(void);
inline void decStats (int updateU, int updateA);
inline void decUStats (void);
inline void decUStats (int& Uout, int& Aout);
inline void getStats (int& Uout, int& Aout);
inline void decStats(int updateU, int updateA);
inline void decUStats(void);
inline void decUStats(int &Uout, int &Aout);
inline void getStats(int &Uout, int &Aout);
#if HEAP_STATS
inline int getUmax (void);
inline int getAmax (void);
inline int getUmax(void);
inline int getAmax(void);
#endif
private:
// U and A *must* be the first items in this class --
// we will depend on this to atomically update them.
private:
// U and A *must* be the first items in this class --
// we will depend on this to atomically update them.
int U; // Memory in use.
int A; // Memory allocated.
int U; // Memory in use.
int A; // Memory allocated.
#if HEAP_STATS
int Umax;
int Amax;
int Umax;
int Amax;
#endif
};
inline void heapStats::incStats (int updateU, int updateA)
inline void
heapStats::incStats(int updateU, int updateA)
{
assert (updateU >= 0);
assert (updateA >= 0);
assert (U <= A);
assert (U >= 0);
assert (A >= 0);
U += updateU;
A += updateA;
assert(updateU >= 0);
assert(updateA >= 0);
assert(U <= A);
assert(U >= 0);
assert(A >= 0);
U += updateU;
A += updateA;
#if HEAP_STATS
Amax = MAX (Amax, A);
Umax = MAX (Umax, U);
Amax = MAX(Amax, A);
Umax = MAX(Umax, U);
#endif
assert (U <= A);
assert (U >= 0);
assert (A >= 0);
assert(U <= A);
assert(U >= 0);
assert(A >= 0);
}
inline void heapStats::incUStats (void)
inline void
heapStats::incUStats(void)
{
assert (U < A);
assert (U >= 0);
assert (A >= 0);
U++;
assert(U < A);
assert(U >= 0);
assert(A >= 0);
U++;
#if HEAP_STATS
Umax = MAX (Umax, U);
Umax = MAX(Umax, U);
#endif
assert (U >= 0);
assert (A >= 0);
assert(U >= 0);
assert(A >= 0);
}
inline void heapStats::decStats (int updateU, int updateA)
inline void
heapStats::decStats(int updateU, int updateA)
{
assert (updateU >= 0);
assert (updateA >= 0);
assert (U <= A);
assert (U >= updateU);
assert (A >= updateA);
U -= updateU;
A -= updateA;
assert (U <= A);
assert (U >= 0);
assert (A >= 0);
assert(updateU >= 0);
assert(updateA >= 0);
assert(U <= A);
assert(U >= updateU);
assert(A >= updateA);
U -= updateU;
A -= updateA;
assert(U <= A);
assert(U >= 0);
assert(A >= 0);
}
inline void heapStats::decUStats (int& Uout, int& Aout)
inline void
heapStats::decUStats(int &Uout, int &Aout)
{
assert (U <= A);
assert (U > 0);
assert (A >= 0);
U--;
Uout = U;
Aout = A;
assert (U >= 0);
assert (A >= 0);
assert(U <= A);
assert(U > 0);
assert(A >= 0);
U--;
Uout = U;
Aout = A;
assert(U >= 0);
assert(A >= 0);
}
inline void heapStats::decUStats (void)
inline void
heapStats::decUStats(void)
{
assert (U <= A);
assert (U > 0);
assert (A >= 0);
U--;
assert(U <= A);
assert(U > 0);
assert(A >= 0);
U--;
}
inline void heapStats::getStats (int& Uout, int& Aout)
inline void
heapStats::getStats(int &Uout, int &Aout)
{
assert (U >= 0);
assert (A >= 0);
Uout = U;
Aout = A;
assert (U <= A);
assert (U >= 0);
assert (A >= 0);
assert(U >= 0);
assert(A >= 0);
Uout = U;
Aout = A;
assert(U <= A);
assert(U >= 0);
assert(A >= 0);
}
#if HEAP_STATS
inline int heapStats::getUmax (void)
inline int
heapStats::getUmax(void)
{
return Umax;
return Umax;
}
inline int heapStats::getAmax (void)
inline int
heapStats::getAmax(void)
{
return Amax;
return Amax;
}
#endif // HEAP_STATS
#endif // _HEAPSTATS_H_
+128 -126
View File
@@ -23,111 +23,115 @@
#include "config.h"
#if USE_PRIVATE_HEAPS
#include "privateheap.h"
#define HEAPTYPE privateHeap
# include "privateheap.h"
# define HEAPTYPE privateHeap
#else
#define HEAPTYPE threadHeap
#include "threadheap.h"
# define HEAPTYPE threadHeap
# include "threadheap.h"
#endif
#include "processheap.h"
using namespace BPrivate;
processHeap::processHeap (void)
: _buffer (NULL),
_bufferCount (0)
processHeap::processHeap(void)
: _buffer(NULL), _bufferCount(0)
#if HEAP_FRAG_STATS
, _currentAllocated (0),
_currentRequested (0),
_maxAllocated (0),
_inUseAtMaxAllocated (0),
_maxRequested (0)
, _currentAllocated(0),
_currentRequested(0),
_maxAllocated(0), _inUseAtMaxAllocated(0), _maxRequested(0)
#endif
{
int i;
// The process heap is heap 0.
setIndex (0);
for (i = 0; i < MAX_HEAPS; i++) {
// Set every thread's process heap to this one.
theap[i].setpHeap (this);
// Set every thread heap's index.
theap[i].setIndex (i + 1);
}
int i;
// The process heap is heap 0.
setIndex(0);
for (i = 0; i < MAX_HEAPS; i++) {
// Set every thread's process heap to this one.
theap[i].setpHeap(this);
// Set every thread heap's index.
theap[i].setIndex(i + 1);
}
#if HEAP_LOG
for (i = 0; i < MAX_HEAPS + 1; i++) {
char fname[255];
sprintf (fname, "log%d", i);
unlink (fname);
_log[i].open (fname);
}
for (i = 0; i < MAX_HEAPS + 1; i++) {
char fname[255];
sprintf(fname, "log%d", i);
unlink(fname);
_log[i].open(fname);
}
#endif
#if HEAP_FRAG_STATS
hoardLockInit(_statsLock, "hoard stats");
hoardLockInit(_statsLock, "hoard stats");
#endif
hoardLockInit(_bufferLock, "hoard buffer");
hoardLockInit(_bufferLock, "hoard buffer");
}
// Print out statistics information.
void processHeap::stats (void) {
void
processHeap::stats(void)
{
#if HEAP_STATS
int umax = 0;
int amax = 0;
for (int j = 0; j < MAX_HEAPS; j++) {
for (int i = 0; i < SIZE_CLASSES; i++) {
amax += theap[j].maxAllocated(i) * sizeFromClass (i);
umax += theap[j].maxInUse(i) * sizeFromClass (i);
}
}
printf ("Amax <= %d, Umax <= %d\n", amax, umax);
#if HEAP_FRAG_STATS
amax = getMaxAllocated();
umax = getMaxRequested();
printf ("Maximum allocated = %d\nMaximum in use = %d\nIn use at max allocated = %d\n", amax, umax, getInUseAtMaxAllocated());
printf ("Still in use = %d\n", _currentRequested);
printf ("Fragmentation (3) = %f\n", (float) amax / (float) getInUseAtMaxAllocated());
printf ("Fragmentation (4) = %f\n", (float) amax / (float) umax);
#endif
int umax = 0;
int amax = 0;
for (int j = 0; j < MAX_HEAPS; j++) {
for (int i = 0; i < SIZE_CLASSES; i++) {
amax += theap[j].maxAllocated(i) * sizeFromClass(i);
umax += theap[j].maxInUse(i) * sizeFromClass(i);
}
}
printf("Amax <= %d, Umax <= %d\n", amax, umax);
#if HEAP_FRAG_STATS
amax = getMaxAllocated();
umax = getMaxRequested();
printf
("Maximum allocated = %d\nMaximum in use = %d\nIn use at max allocated = %d\n",
amax, umax, getInUseAtMaxAllocated());
printf("Still in use = %d\n", _currentRequested);
printf("Fragmentation (3) = %f\n",
(float)amax / (float)getInUseAtMaxAllocated());
printf("Fragmentation (4) = %f\n", (float)amax / (float)umax);
#endif
#endif // HEAP_STATS
#if HEAP_LOG
printf ("closing logs.\n");
fflush (stdout);
for (int i = 0; i < MAX_HEAPS + 1; i++) {
_log[i].close();
}
printf("closing logs.\n");
fflush(stdout);
for (int i = 0; i < MAX_HEAPS + 1; i++) {
_log[i].close();
}
#endif
}
#if HEAP_FRAG_STATS
void processHeap::setAllocated (int requestedSize,
int actualSize)
void
processHeap::setAllocated(int requestedSize, int actualSize)
{
hoardLock (_statsLock);
_currentRequested += requestedSize;
_currentAllocated += actualSize;
if (_currentRequested > _maxRequested) {
_maxRequested = _currentRequested;
}
if (_currentAllocated > _maxAllocated) {
_maxAllocated = _currentAllocated;
_inUseAtMaxAllocated = _currentRequested;
}
hoardUnlock (_statsLock);
hoardLock(_statsLock);
_currentRequested += requestedSize;
_currentAllocated += actualSize;
if (_currentRequested > _maxRequested) {
_maxRequested = _currentRequested;
}
if (_currentAllocated > _maxAllocated) {
_maxAllocated = _currentAllocated;
_inUseAtMaxAllocated = _currentRequested;
}
hoardUnlock(_statsLock);
}
void processHeap::setDeallocated (int requestedSize,
int actualSize)
void
processHeap::setDeallocated(int requestedSize, int actualSize)
{
hoardLock (_statsLock);
_currentRequested -= requestedSize;
_currentAllocated -= actualSize;
hoardUnlock (_statsLock);
hoardLock(_statsLock);
_currentRequested -= requestedSize;
_currentAllocated -= actualSize;
hoardUnlock(_statsLock);
}
#endif
#endif // HEAP_FRAG_STATS
// free (ptr, pheap):
@@ -136,74 +140,72 @@ void processHeap::setDeallocated (int requestedSize,
// updates the thread heap's statistics;
// may release the superblock to the process heap.
void processHeap::free (void * ptr)
void
processHeap::free(void *ptr)
{
// Return if ptr is 0.
// This is the behavior prescribed by the standard.
if (ptr == 0)
return;
// Return if ptr is 0.
// This is the behavior prescribed by the standard.
if (ptr == 0) {
return;
}
// Find the block and superblock corresponding to this ptr.
// Find the block and superblock corresponding to this ptr.
block *b = (block *) ptr - 1;
assert(b->isValid());
block * b = (block *) ptr - 1;
assert (b->isValid());
// Check to see if this block came from a memalign() call.
if (((unsigned long)b->getNext() & 1) == 1) {
// It did. Set the block to the actual block header.
b = (block *) ((unsigned long)b->getNext() & ~1);
assert(b->isValid());
}
// Check to see if this block came from a memalign() call.
if (((unsigned long) b->getNext() & 1) == 1) {
// It did. Set the block to the actual block header.
b = (block *) ((unsigned long) b->getNext() & ~1);
assert (b->isValid());
}
b->markFree();
b->markFree();
superblock *sb = b->getSuperblock();
assert(sb);
assert(sb->isValid());
superblock * sb = b->getSuperblock();
assert (sb);
assert (sb->isValid());
const int sizeclass = sb->getBlockSizeClass();
const int sizeclass = sb->getBlockSizeClass();
//
// Return the block to the superblock,
// find the heap that owns this superblock
// and update its statistics.
//
//
// Return the block to the superblock,
// find the heap that owns this superblock
// and update its statistics.
//
hoardHeap *owner;
hoardHeap * owner;
// By acquiring the up lock on the superblock,
// we prevent it from moving to the global heap.
// This eventually pins it down in one heap,
// so this loop is guaranteed to terminate.
// (It should generally take no more than two iterations.)
sb->upLock();
while (1) {
owner = sb->getOwner();
owner->lock();
if (owner == sb->getOwner()) {
break;
} else {
owner->unlock();
}
// Suspend to allow ownership to quiesce.
hoardYield();
}
// By acquiring the up lock on the superblock,
// we prevent it from moving to the global heap.
// This eventually pins it down in one heap,
// so this loop is guaranteed to terminate.
// (It should generally take no more than two iterations.)
sb->upLock();
while (1) {
owner = sb->getOwner();
owner->lock();
if (owner == sb->getOwner()) {
break;
} else {
owner->unlock();
}
// Suspend to allow ownership to quiesce.
hoardYield();
}
#if HEAP_LOG
MemoryRequest m;
m.free (ptr);
getLog (owner->getIndex()).append(m);
MemoryRequest m;
m.free(ptr);
getLog(owner->getIndex()).append(m);
#endif
#if HEAP_FRAG_STATS
setDeallocated (b->getRequestedSize(), 0);
setDeallocated(b->getRequestedSize(), 0);
#endif
int sbUnmapped = owner->freeBlock (b, sb, sizeclass, this);
int sbUnmapped = owner->freeBlock(b, sb, sizeclass, this);
owner->unlock();
if (!sbUnmapped) {
sb->upUnlock();
}
owner->unlock();
if (!sbUnmapped)
sb->upUnlock();
}
+154 -139
View File
@@ -30,149 +30,155 @@
#include "arch-specific.h"
#include "heap.h"
#if USE_PRIVATE_HEAPS
#include "privateheap.h"
#define HEAPTYPE privateHeap
# include "privateheap.h"
# define HEAPTYPE privateHeap
#else
#define HEAPTYPE threadHeap
#include "threadheap.h"
# define HEAPTYPE threadHeap
# include "threadheap.h"
#endif
#if HEAP_LOG
#include "memstat.h"
#include "log.h"
# include "memstat.h"
# include "log.h"
#endif
namespace BPrivate {
class processHeap : public hoardHeap {
public:
// Always grab at least this many superblocks' worth of memory which
// we parcel out.
enum { REFILL_NUMBER_OF_SUPERBLOCKS = 16 };
public:
// Always grab at least this many superblocks' worth of memory which
// we parcel out.
enum { REFILL_NUMBER_OF_SUPERBLOCKS = 16 };
processHeap (void);
~processHeap (void) {
processHeap(void);
~processHeap(void)
{
#if HEAP_STATS
stats();
stats();
#endif
}
}
// Memory deallocation routines.
void free(void *ptr);
// Memory deallocation routines.
void free (void * ptr);
// Print out statistics information.
void stats(void);
// Print out statistics information.
void stats (void);
// Get a thread heap index.
inline int getHeapIndex(void);
// Get a thread heap index.
inline int getHeapIndex (void);
// Get the thread heap with index i.
inline HEAPTYPE & getHeap(int i);
// Get the thread heap with index i.
inline HEAPTYPE& getHeap (int i);
// Extract a superblock.
inline superblock *acquire(const int c, hoardHeap * dest);
// Extract a superblock.
inline superblock * acquire (const int c,
hoardHeap * dest);
// Get space for a superblock.
inline char *getSuperblockBuffer(void);
// Get space for a superblock.
inline char * getSuperblockBuffer (void);
// Insert a superblock.
inline void release (superblock * sb);
// Insert a superblock.
inline void release(superblock * sb);
#if HEAP_LOG
// Get the log for index i.
inline Log<MemoryRequest>& getLog (int i);
// Get the log for index i.
inline Log < MemoryRequest > &getLog(int i);
#endif
#if HEAP_FRAG_STATS
// Declare that we have allocated an object.
void setAllocated (int requestedSize,
int actualSize);
// Declare that we have allocated an object.
void setAllocated(int requestedSize, int actualSize);
// Declare that we have deallocated an object.
void setDeallocated (int requestedSize,
int actualSize);
// Declare that we have deallocated an object.
void setDeallocated(int requestedSize, int actualSize);
// Return the number of wasted bytes at the high-water mark
// (maxAllocated - maxRequested)
inline int getFragmentation (void);
// Return the number of wasted bytes at the high-water mark
// (maxAllocated - maxRequested)
inline int getFragmentation(void);
int getMaxAllocated (void) {
return _maxAllocated;
}
int
getMaxAllocated(void)
{
return _maxAllocated;
}
int getInUseAtMaxAllocated (void) {
return _inUseAtMaxAllocated;
}
int getMaxRequested (void) {
return _maxRequested;
}
int
getInUseAtMaxAllocated(void)
{
return _inUseAtMaxAllocated;
}
int
getMaxRequested(void)
{
return _maxRequested;
}
#endif
private:
private:
// Hide the lock & unlock methods.
void
lock(void)
{
hoardHeap::lock();
}
// Hide the lock & unlock methods.
void
unlock(void)
{
hoardHeap::unlock();
}
void lock (void) {
hoardHeap::lock();
}
// Prevent copying and assignment.
processHeap(const processHeap &);
const processHeap & operator=(const processHeap &);
void unlock (void) {
hoardHeap::unlock();
}
// Prevent copying and assignment.
processHeap (const processHeap&);
const processHeap& operator= (const processHeap&);
// The per-thread heaps.
HEAPTYPE theap[MAX_HEAPS];
// The per-thread heaps.
HEAPTYPE theap[MAX_HEAPS];
#if HEAP_FRAG_STATS
// Statistics required to compute fragmentation. We cannot
// unintrusively keep track of these on a multiprocessor, because
// this would become a bottleneck.
// Statistics required to compute fragmentation. We cannot
// unintrusively keep track of these on a multiprocessor, because
// this would become a bottleneck.
int _currentAllocated;
int _currentRequested;
int _maxAllocated;
int _maxRequested;
int _inUseAtMaxAllocated;
int _fragmentation;
int _currentAllocated;
int _currentRequested;
int _maxAllocated;
int _maxRequested;
int _inUseAtMaxAllocated;
int _fragmentation;
// A lock to protect these statistics.
hoardLockType _statsLock;
// A lock to protect these statistics.
hoardLockType _statsLock;
#endif
#if HEAP_LOG
Log<MemoryRequest> _log[MAX_HEAPS + 1];
Log < MemoryRequest > _log[MAX_HEAPS + 1];
#endif
// A lock for the superblock buffer.
hoardLockType _bufferLock;
// A lock for the superblock buffer.
hoardLockType _bufferLock;
char * _buffer;
int _bufferCount;
char *_buffer;
int _bufferCount;
};
HEAPTYPE& processHeap::getHeap (int i)
HEAPTYPE &
processHeap::getHeap(int i)
{
assert (i >= 0);
assert (i < MAX_HEAPS);
return theap[i];
assert(i >= 0);
assert(i < MAX_HEAPS);
return theap[i];
}
#if HEAP_LOG
Log<MemoryRequest>& processHeap::getLog (int i)
Log<MemoryRequest > &
processHeap::getLog(int i)
{
assert (i >= 0);
assert (i < MAX_HEAPS + 1);
return _log[i];
assert(i >= 0);
assert(i < MAX_HEAPS + 1);
return _log[i];
}
#endif
@@ -180,77 +186,86 @@ Log<MemoryRequest>& processHeap::getLog (int i)
#ifdef NEED_LG
// Return ceil(log_2(num)).
// num must be positive.
static int lg (int num)
static int
lg(int num)
{
assert (num > 0);
int power = 0;
int n = 1;
// Invariant: 2^power == n.
while (n < num) {
n <<= 1;
power++;
}
return power;
assert(num > 0);
int power = 0;
int n = 1;
// Invariant: 2^power == n.
while (n < num) {
n <<= 1;
power++;
}
return power;
}
#endif /* NEED_LG */
// Hash out the thread id to a heap and return an index to that heap.
int processHeap::getHeapIndex (void) {
// Here we use the number of processors as the maximum number of heaps.
// In fact, for efficiency, we just round up to the highest power of two,
// times two.
int tid = hoardGetThreadID() & _numProcessorsMask;
assert (tid < MAX_HEAPS);
return tid;
int
processHeap::getHeapIndex(void)
{
// Here we use the number of processors as the maximum number of heaps.
// In fact, for efficiency, we just round up to the highest power of two,
// times two.
int tid = hoardGetThreadID() & _numProcessorsMask;
assert(tid < MAX_HEAPS);
return tid;
}
superblock * processHeap::acquire (const int sizeclass,
hoardHeap * dest)
superblock *
processHeap::acquire(const int sizeclass, hoardHeap * dest)
{
lock ();
lock();
// Remove the superblock with the most free space.
superblock * maxSb = removeMaxSuperblock (sizeclass);
if (maxSb) {
maxSb->setOwner (dest);
}
// Remove the superblock with the most free space.
superblock *maxSb = removeMaxSuperblock(sizeclass);
if (maxSb)
maxSb->setOwner(dest);
unlock ();
unlock();
return maxSb;
return maxSb;
}
inline char * processHeap::getSuperblockBuffer (void)
inline char *
processHeap::getSuperblockBuffer(void)
{
char * buf;
hoardLock (_bufferLock);
if (_bufferCount == 0) {
_buffer = (char *) hoardSbrk (SUPERBLOCK_SIZE * REFILL_NUMBER_OF_SUPERBLOCKS);
_bufferCount = REFILL_NUMBER_OF_SUPERBLOCKS;
}
buf = _buffer;
_buffer += SUPERBLOCK_SIZE;
_bufferCount--;
hoardUnlock (_bufferLock);
return buf;
char *buf;
hoardLock(_bufferLock);
if (_bufferCount == 0) {
_buffer = (char *)hoardSbrk(SUPERBLOCK_SIZE
* REFILL_NUMBER_OF_SUPERBLOCKS);
_bufferCount = REFILL_NUMBER_OF_SUPERBLOCKS;
}
buf = _buffer;
_buffer += SUPERBLOCK_SIZE;
_bufferCount--;
hoardUnlock(_bufferLock);
return buf;
}
// Put a superblock back into our list of superblocks.
void processHeap::release (superblock * sb)
void
processHeap::release(superblock *sb)
{
assert (EMPTY_FRACTION * sb->getNumAvailable() > sb->getNumBlocks());
assert(EMPTY_FRACTION * sb->getNumAvailable() > sb->getNumBlocks());
lock();
lock();
// Insert the superblock.
insertSuperblock (sb->getBlockSizeClass(), sb, this);
// Insert the superblock.
insertSuperblock(sb->getBlockSizeClass(), sb, this);
unlock();
unlock();
}
} // namespace BPrivate
#endif // _PROCESSHEAP_H_
+70 -70
View File
@@ -22,7 +22,7 @@
The superblock class controls a number of blocks (which are
allocatable units of memory).
------------------------------------------------------------------------
@(#) $Id: superblock.cpp,v 1.2 2005/02/10 18:47:16 axeld Exp $
@(#) $Id$
------------------------------------------------------------------------
Emery Berger | <http://www.cs.utexas.edu/users/emery>
Department of Computer Sciences | <http://www.cs.utexas.edu>
@@ -39,94 +39,94 @@
#include "processheap.h"
#include "superblock.h"
using namespace BPrivate;
superblock::superblock (int numBlocks, // The number of blocks in the sb.
int szclass, // The size class of the blocks.
hoardHeap * o) // The heap that "owns" this sb.
:
superblock::superblock(int numBlocks, // The number of blocks in the sb.
int szclass, // The size class of the blocks.
hoardHeap * o) // The heap that "owns" this sb.
:
#if HEAP_DEBUG
_magic (SUPERBLOCK_MAGIC),
_magic(SUPERBLOCK_MAGIC),
#endif
_sizeClass (szclass),
_numBlocks (numBlocks),
_numAvailable (0),
_fullness (0),
_freeList (NULL),
_owner (o),
_next (NULL),
_prev (NULL)
_sizeClass(szclass),
_numBlocks(numBlocks),
_numAvailable(0),
_fullness(0), _freeList(NULL), _owner(o), _next(NULL), _prev(NULL)
{
assert (_numBlocks >= 1);
assert(_numBlocks >= 1);
// Determine the size of each block.
const int blksize =
hoardHeap::align (sizeof(block) + hoardHeap::sizeFromClass(_sizeClass));
// Determine the size of each block.
const int blksize = hoardHeap::align(sizeof(block)
+ hoardHeap::sizeFromClass(_sizeClass));
// Make sure this size is in fact aligned.
assert ((blksize & hoardHeap::ALIGNMENT_MASK) == 0);
// Make sure this size is in fact aligned.
assert((blksize & hoardHeap::ALIGNMENT_MASK) == 0);
// Set the first block to just past this superblock header.
block * b
= (block *) hoardHeap::align ((unsigned long) (this + 1));
// Set the first block to just past this superblock header.
block *b = (block *) hoardHeap::align((unsigned long)(this + 1));
// Initialize all the blocks,
// and insert the block pointers into the linked list.
for (int i = 0; i < _numBlocks; i++) {
// Make sure the block is on a double-word boundary.
assert (((unsigned int) b & hoardHeap::ALIGNMENT_MASK) == 0);
new (b) block (this);
assert (b->getSuperblock() == this);
b->setNext (_freeList);
_freeList = b;
b = (block *) ((char *) b + blksize);
}
_numAvailable = _numBlocks;
computeFullness();
assert ((unsigned long) b <= hoardHeap::align (sizeof(superblock) + blksize * _numBlocks) + (unsigned long) this);
// Initialize all the blocks,
// and insert the block pointers into the linked list.
for (int i = 0; i < _numBlocks; i++) {
// Make sure the block is on a double-word boundary.
assert(((unsigned int)b & hoardHeap::ALIGNMENT_MASK) == 0);
new(b) block(this);
assert(b->getSuperblock() == this);
b->setNext(_freeList);
_freeList = b;
b = (block *)((char *)b + blksize);
}
hoardLockInit(_upLock, "hoard superblock");
_numAvailable = _numBlocks;
computeFullness();
assert((unsigned long)b <= hoardHeap::align(sizeof(superblock) + blksize * _numBlocks)
+ (unsigned long)this);
hoardLockInit(_upLock, "hoard superblock");
}
superblock * superblock::makeSuperblock (int sizeclass,
processHeap * pHeap)
superblock *
superblock::makeSuperblock(int sizeclass, processHeap * pHeap)
{
// We need to get more memory.
// We need to get more memory.
char * buf;
int numBlocks = hoardHeap::numBlocks(sizeclass);
char *buf;
int numBlocks = hoardHeap::numBlocks(sizeclass);
// Compute how much memory we need.
unsigned long moreMemory;
if (numBlocks > 1) {
moreMemory = hoardHeap::SUPERBLOCK_SIZE;
assert (moreMemory >= hoardHeap::align(sizeof(superblock) + (hoardHeap::align (sizeof(block) + hoardHeap::sizeFromClass(sizeclass))) * numBlocks));
// Compute how much memory we need.
unsigned long moreMemory;
if (numBlocks > 1) {
moreMemory = hoardHeap::SUPERBLOCK_SIZE;
assert(moreMemory >= hoardHeap::align(sizeof(superblock)
+ (hoardHeap::align(sizeof(block)
+ hoardHeap::sizeFromClass(sizeclass))) * numBlocks));
// Get some memory from the process heap.
buf = (char *) pHeap->getSuperblockBuffer();
// Get some memory from the process heap.
buf = (char *)pHeap->getSuperblockBuffer();
} else {
// One object.
assert(numBlocks == 1);
} else {
// One object.
assert (numBlocks == 1);
size_t blksize = hoardHeap::align(sizeof(block)
+ hoardHeap::sizeFromClass(sizeclass));
moreMemory = hoardHeap::align(sizeof(superblock) + blksize);
size_t blksize = hoardHeap::align (sizeof(block) + hoardHeap::sizeFromClass(sizeclass));
moreMemory = hoardHeap::align (sizeof(superblock) + blksize);
// Get space from the system.
buf = (char *)hoardSbrk(moreMemory);
}
// Get space from the system.
buf = (char *) hoardSbrk (moreMemory);
}
// Make sure that we actually got the memory.
if (buf == NULL)
return 0;
// Make sure that we actually got the memory.
if (buf == NULL) {
return 0;
}
buf = (char *) hoardHeap::align ((unsigned long) buf);
buf = (char *)hoardHeap::align((unsigned long)buf);
// Make sure this buffer is double-word aligned.
assert (buf == (char *) hoardHeap::align ((unsigned long) buf));
assert ((((unsigned long) buf) & hoardHeap::ALIGNMENT_MASK) == 0);
// Make sure this buffer is double-word aligned.
assert(buf == (char *)hoardHeap::align((unsigned long)buf));
assert((((unsigned long)buf) & hoardHeap::ALIGNMENT_MASK) == 0);
// Instantiate the new superblock in the buffer.
superblock * sb = new (buf) superblock (numBlocks, sizeclass, NULL);
return sb;
// Instantiate the new superblock in the buffer.
return new(buf) superblock(numBlocks, sizeclass, NULL);
}
+177 -159
View File
@@ -23,7 +23,7 @@
The superblock class controls a number of blocks (which are
allocatable units of memory).
------------------------------------------------------------------------
@(#) $Id: superblock.h,v 1.1 2002/10/05 17:13:30 axeld Exp $
@(#) $Id$
------------------------------------------------------------------------
Emery Berger | <http://www.cs.utexas.edu/users/emery>
Department of Computer Sciences | <http://www.cs.utexas.edu>
@@ -44,244 +44,262 @@
#include "arch-specific.h"
#include "block.h"
class hoardHeap; // forward declaration
class processHeap; // forward declaration
namespace BPrivate {
class hoardHeap; // forward declaration
class processHeap; // forward declaration
class superblock {
public:
// Construct a superblock for a given size class and set the heap
// owner.
superblock(int numblocks, int sizeclass, hoardHeap *owner);
~superblock(void) {}
public:
// Make (allocate or re-use) a superblock for a given size class.
static superblock *makeSuperblock(int sizeclass, processHeap *pHeap);
// Construct a superblock for a given size class and set the heap
// owner.
superblock (int numblocks,
int sizeclass,
hoardHeap * owner);
// Find out who allocated this superblock.
inline hoardHeap *getOwner(void);
~superblock (void)
{}
// Set the superblock's owner.
inline void setOwner(hoardHeap *o);
// Make (allocate or re-use) a superblock for a given size class.
static superblock * makeSuperblock (int sizeclass, processHeap * pHeap);
// Get a block from the superblock.
inline block *getBlock(void);
// Find out who allocated this superblock.
inline hoardHeap * getOwner (void);
// Put a block back in the superblock.
inline void putBlock(block *b);
// Set the superblock's owner.
inline void setOwner (hoardHeap * o);
// How many blocks are available?
inline int getNumAvailable(void);
// Get a block from the superblock.
inline block * getBlock (void);
// How many blocks are there, in total?
inline int getNumBlocks(void);
// Put a block back in the superblock.
inline void putBlock (block * b);
// What size class are blocks in this superblock?
inline int getBlockSizeClass(void);
// How many blocks are available?
inline int getNumAvailable (void);
// Insert this superblock before the next one.
inline void insertBefore(superblock *nextSb);
// How many blocks are there, in total?
inline int getNumBlocks (void);
// Return the next pointer (to the next superblock in the list).
inline superblock *const getNext(void);
// What size class are blocks in this superblock?
inline int getBlockSizeClass (void);
// Return the prev pointer (to the previous superblock in the list).
inline superblock *const getPrev(void);
// Insert this superblock before the next one.
inline void insertBefore (superblock * nextSb);
// Compute the 'fullness' of this superblock.
inline void computeFullness(void);
// Return the next pointer (to the next superblock in the list).
inline superblock * const getNext (void);
// Return the prev pointer (to the previous superblock in the list).
inline superblock * const getPrev (void);
// Compute the 'fullness' of this superblock.
inline void computeFullness (void);
// Return the 'fullness' of this superblock.
inline int getFullness (void);
// Return the 'fullness' of this superblock.
inline int getFullness(void);
#if HEAP_FRAG_STATS
// Return the amount of waste in every allocated block.
int getMaxInternalFragmentation (void);
// Return the amount of waste in every allocated block.
int getMaxInternalFragmentation(void);
#endif
// Remove this superblock from its linked list.
inline void remove (void);
// Remove this superblock from its linked list.
inline void remove(void);
// Is this superblock valid? (i.e.,
// does it have the right magic number?)
inline int isValid (void);
// Is this superblock valid? (i.e.,
// does it have the right magic number?)
inline int isValid(void);
void upLock (void) {
hoardLock (_upLock);
}
void
upLock(void)
{
hoardLock(_upLock);
}
void upUnlock (void) {
hoardUnlock (_upLock);
}
void
upUnlock(void)
{
hoardUnlock(_upLock);
}
private:
private:
// Disable copying and assignment.
// Disable copying and assignment.
superblock(const superblock &);
const superblock & operator=(const superblock &);
superblock (const superblock&);
const superblock& operator= (const superblock&);
// Used for sanity checking.
enum { SUPERBLOCK_MAGIC = 0xCAFEBABE };
// Used for sanity checking.
enum { SUPERBLOCK_MAGIC = 0xCAFEBABE };
#if HEAP_DEBUG
unsigned long _magic;
unsigned long _magic;
#endif
const int _sizeClass; // The size class of blocks in the superblock.
const int _numBlocks; // The number of blocks in the superblock.
int _numAvailable; // The number of blocks available.
int _fullness; // How full is this superblock?
// (which SUPERBLOCK_FULLNESS group is it in)
block * _freeList; // A pointer to the first free block.
hoardHeap * _owner; // The heap who owns this superblock.
superblock * _next; // The next superblock in the list.
superblock * _prev; // The previous superblock in the list.
const int _sizeClass; // The size class of blocks in the superblock.
const int _numBlocks; // The number of blocks in the superblock.
int _numAvailable; // The number of blocks available.
int _fullness; // How full is this superblock?
// (which SUPERBLOCK_FULLNESS group is it in)
block *_freeList; // A pointer to the first free block.
hoardHeap *_owner; // The heap who owns this superblock.
superblock *_next; // The next superblock in the list.
superblock *_prev; // The previous superblock in the list.
hoardLockType _upLock; // Lock this when moving a superblock to the global (process) heap.
hoardLockType _upLock; // Lock this when moving a superblock to the global (process) heap.
// We insert a cache pad here to prevent false sharing with the
// first block (which immediately follows the superblock).
double _pad[CACHE_LINE / sizeof(double)];
// We insert a cache pad here to prevent false sharing with the
// first block (which immediately follows the superblock).
double _pad[CACHE_LINE / sizeof(double)];
};
hoardHeap * superblock::getOwner (void)
hoardHeap *
superblock::getOwner(void)
{
assert (isValid());
hoardHeap * o = _owner;
return o;
assert(isValid());
hoardHeap *o = _owner;
return o;
}
void superblock::setOwner (hoardHeap * o)
void
superblock::setOwner(hoardHeap *o)
{
assert (isValid());
_owner = o;
assert(isValid());
_owner = o;
}
block * superblock::getBlock (void)
block *
superblock::getBlock(void)
{
assert (isValid());
// Pop off a block from this superblock's freelist,
// if there is one available.
if (_freeList == NULL) {
// The freelist is empty.
assert (getNumAvailable() == 0);
return NULL;
}
assert (getNumAvailable() > 0);
block * b = _freeList;
_freeList = _freeList->getNext();
_numAvailable--;
assert(isValid());
// Pop off a block from this superblock's freelist,
// if there is one available.
if (_freeList == NULL) {
// The freelist is empty.
assert(getNumAvailable() == 0);
return NULL;
}
b->setNext(NULL);
assert(getNumAvailable() > 0);
block *b = _freeList;
_freeList = _freeList->getNext();
_numAvailable--;
computeFullness();
b->setNext(NULL);
return b;
computeFullness();
return b;
}
void superblock::putBlock (block * b)
void
superblock::putBlock(block *b)
{
assert (isValid());
// Push a block onto the superblock's freelist.
assert (b->isValid());
assert (b->getSuperblock() == this);
assert (getNumAvailable() < getNumBlocks());
b->setNext (_freeList);
_freeList = b;
_numAvailable++;
computeFullness();
assert(isValid());
// Push a block onto the superblock's freelist.
assert(b->isValid());
assert(b->getSuperblock() == this);
assert(getNumAvailable() < getNumBlocks());
b->setNext(_freeList);
_freeList = b;
_numAvailable++;
computeFullness();
}
int superblock::getNumAvailable (void)
int
superblock::getNumAvailable(void)
{
assert (isValid());
return _numAvailable;
assert(isValid());
return _numAvailable;
}
int superblock::getNumBlocks (void)
int
superblock::getNumBlocks(void)
{
assert (isValid());
return _numBlocks;
assert(isValid());
return _numBlocks;
}
int superblock::getBlockSizeClass (void)
int
superblock::getBlockSizeClass(void)
{
assert (isValid());
return _sizeClass;
assert(isValid());
return _sizeClass;
}
superblock * const superblock::getNext (void)
superblock * const
superblock::getNext(void)
{
assert (isValid());
return _next;
assert(isValid());
return _next;
}
superblock * const superblock::getPrev (void)
superblock * const
superblock::getPrev(void)
{
assert (isValid());
return _prev;
assert(isValid());
return _prev;
}
void superblock::insertBefore (superblock * nextSb) {
assert (isValid());
// Insert this superblock before the next one (nextSb).
assert (nextSb != this);
_next = nextSb;
if (nextSb) {
_prev = nextSb->_prev;
nextSb->_prev = this;
}
}
void superblock::remove (void) {
// Remove this superblock from a doubly-linked list.
if (_next) {
_next->_prev = _prev;
}
if (_prev) {
_prev->_next = _next;
}
_prev = NULL;
_next = NULL;
}
int superblock::isValid (void)
void
superblock::insertBefore(superblock * nextSb)
{
assert (_numBlocks > 0);
assert (_numAvailable <= _numBlocks);
assert (_sizeClass >= 0);
return 1;
assert(isValid());
// Insert this superblock before the next one (nextSb).
assert(nextSb != this);
_next = nextSb;
if (nextSb) {
_prev = nextSb->_prev;
nextSb->_prev = this;
}
}
void superblock::computeFullness (void)
void
superblock::remove(void)
{
assert (isValid());
_fullness = (((SUPERBLOCK_FULLNESS_GROUP - 1)
// Remove this superblock from a doubly-linked list.
if (_next)
_next->_prev = _prev;
if (_prev)
_prev->_next = _next;
_prev = NULL;
_next = NULL;
}
int
superblock::isValid(void)
{
assert(_numBlocks > 0);
assert(_numAvailable <= _numBlocks);
assert(_sizeClass >= 0);
return 1;
}
void
superblock::computeFullness(void)
{
assert(isValid());
_fullness = (((SUPERBLOCK_FULLNESS_GROUP - 1)
* (getNumBlocks() - getNumAvailable())) / getNumBlocks());
}
int superblock::getFullness (void)
int
superblock::getFullness(void)
{
assert (isValid());
return _fullness;
assert(isValid());
return _fullness;
}
} // namespace BPrivate
#endif // _SUPERBLOCK_H_
+55 -51
View File
@@ -26,10 +26,13 @@
#include "threadheap.h"
#include "processheap.h"
using namespace BPrivate;
threadHeap::threadHeap (void)
: _pHeap (0)
{}
threadHeap::threadHeap(void)
:_pHeap(0)
{
}
// malloc (sz):
@@ -38,73 +41,74 @@ threadHeap::threadHeap (void)
// side effects: allocates a block from a superblock;
// may call sbrk() (via makeSuperblock).
void * threadHeap::malloc (const size_t size)
void *
threadHeap::malloc(const size_t size)
{
const int sizeclass = sizeClass (size);
block * b = NULL;
const int sizeclass = sizeClass(size);
block *b = NULL;
lock();
lock();
// Look for a free block.
// We usually have memory locally so we first look for space in the
// superblock list.
// Look for a free block.
// We usually have memory locally so we first look for space in the
// superblock list.
superblock * sb = findAvailableSuperblock (sizeclass, b, _pHeap);
superblock *sb = findAvailableSuperblock(sizeclass, b, _pHeap);
if (sb == NULL) {
if (sb == NULL) {
// We don't have memory locally.
// Try to get more from the process heap.
// We don't have memory locally.
// Try to get more from the process heap.
assert(_pHeap);
sb = _pHeap->acquire((int)sizeclass, this);
assert (_pHeap);
sb = _pHeap->acquire ((int) sizeclass, this);
// If we didn't get any memory from the process heap,
// we'll have to allocate our own superblock.
if (sb == NULL) {
sb = superblock::makeSuperblock (sizeclass, _pHeap);
if (sb == NULL) {
// We're out of memory!
unlock ();
return NULL;
}
// If we didn't get any memory from the process heap,
// we'll have to allocate our own superblock.
if (sb == NULL) {
sb = superblock::makeSuperblock(sizeclass, _pHeap);
if (sb == NULL) {
// We're out of memory!
unlock();
return NULL;
}
#if HEAP_LOG
// Record the memory allocation.
MemoryRequest m;
m.allocate ((int) sb->getNumBlocks() * (int) sizeFromClass(sb->getBlockSizeClass()));
_pHeap->getLog(getIndex()).append(m);
// Record the memory allocation.
MemoryRequest m;
m.allocate((int)sb->getNumBlocks() *
(int)sizeFromClass(sb->getBlockSizeClass()));
_pHeap->getLog(getIndex()).append(m);
#endif
#if HEAP_FRAG_STATS
_pHeap->setAllocated (0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
_pHeap->setAllocated(0,
sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
#endif
}
}
// Get a block from the superblock.
b = sb->getBlock();
assert(b != NULL);
// Get a block from the superblock.
b = sb->getBlock ();
assert (b != NULL);
// Insert the superblock into our list.
insertSuperblock(sizeclass, sb, _pHeap);
}
// Insert the superblock into our list.
insertSuperblock (sizeclass, sb, _pHeap);
}
assert(b != NULL);
assert(b->isValid());
assert(sb->isValid());
assert (b != NULL);
assert (b->isValid());
assert (sb->isValid());
b->markAllocated();
b->markAllocated();
#if HEAP_LOG
MemoryRequest m;
m.malloc ((void *) (b + 1), align(size));
_pHeap->getLog(getIndex()).append(m);
MemoryRequest m;
m.malloc((void *)(b + 1), align(size));
_pHeap->getLog(getIndex()).append(m);
#endif
#if HEAP_FRAG_STATS
b->setRequestedSize (align(size));
_pHeap->setAllocated (align(size), 0);
b->setRequestedSize(align(size));
_pHeap->setAllocated(align(size), 0);
#endif
unlock();
unlock();
// Skip past the block header and return the pointer.
return (void *) (b + 1);
// Skip past the block header and return the pointer.
return (void *)(b + 1);
}
+90 -95
View File
@@ -26,143 +26,138 @@
#include "heap.h"
class processHeap; // forward declaration
namespace BPrivate {
class processHeap; // forward declaration
//
// We use one threadHeap for each thread (processor).
//
class threadHeap : public hoardHeap {
public:
threadHeap(void);
public:
// Memory allocation routines.
void *malloc(const size_t sz);
inline void *memalign(size_t alignment, size_t sz);
threadHeap (void);
// Find out how large an allocated object is.
inline static size_t objectSize(void *ptr);
// Memory allocation routines.
void * malloc (const size_t sz);
inline void * memalign (size_t alignment, size_t sz);
// Set our process heap.
inline void setpHeap(processHeap *p);
// Find out how large an allocated object is.
inline static size_t objectSize (void * ptr);
private:
// Prevent copying and assignment.
threadHeap(const threadHeap &);
const threadHeap &operator=(const threadHeap &);
// Set our process heap.
inline void setpHeap (processHeap * p);
// Our process heap.
processHeap *_pHeap;
private:
// Prevent copying and assignment.
threadHeap (const threadHeap&);
const threadHeap& operator= (const threadHeap&);
// Our process heap.
processHeap * _pHeap;
// We insert a cache pad here to avoid false sharing (the
// processHeap holds an array of threadHeaps, and we don't want
// these to share any cache lines).
double _pad[CACHE_LINE / sizeof(double)];
// We insert a cache pad here to avoid false sharing (the
// processHeap holds an array of threadHeaps, and we don't want
// these to share any cache lines).
double _pad[CACHE_LINE / sizeof(double)];
};
void * threadHeap::memalign (size_t alignment,
size_t size)
void *
threadHeap::memalign(size_t alignment, size_t size)
{
// Calculate the amount of space we need
// to satisfy the alignment requirements.
// Calculate the amount of space we need
// to satisfy the alignment requirements.
size_t newSize;
size_t newSize;
// If the alignment is less than the required alignment,
// just call malloc.
if (alignment <= ALIGNMENT) {
return this->malloc (size);
}
// If the alignment is less than the required alignment,
// just call malloc.
if (alignment <= ALIGNMENT)
return this->malloc(size);
if (alignment < sizeof(block)) {
alignment = sizeof(block);
}
if (alignment < sizeof(block))
alignment = sizeof(block);
// Alignment must be a power of two!
assert ((alignment & (alignment - 1)) == 0);
// Alignment must be a power of two!
assert((alignment & (alignment - 1)) == 0);
// Leave enough room to align the block within the malloced space.
newSize = size + sizeof(block) + alignment;
// Leave enough room to align the block within the malloced space.
newSize = size + sizeof(block) + alignment;
// Now malloc the space up with a little extra (we'll put the block
// pointer in right behind the allocated space).
// Now malloc the space up with a little extra (we'll put the block
// pointer in right behind the allocated space).
void * ptr = this->malloc (newSize);
if ((((unsigned long) ptr) & -((long) alignment)) == 0) {
// ptr is already aligned, so return it.
assert (((unsigned long) ptr % alignment) == 0);
return ptr;
void *ptr = this->malloc(newSize);
if ((((unsigned long) ptr) & -((long) alignment)) == 0) {
// ptr is already aligned, so return it.
assert(((unsigned long) ptr % alignment) == 0);
return ptr;
} else {
// Align ptr.
char *newptr = (char *)(((unsigned long)ptr + alignment - 1) & -((long)alignment));
} else {
// If there's not enough room for the block header, skip to the
// next aligned space within the block..
if ((unsigned long)newptr - (unsigned long)ptr < sizeof(block))
newptr += alignment;
// Align ptr.
char * newptr = (char *)
(((unsigned long) ptr + alignment - 1) & -((long) alignment));
assert(((unsigned long)newptr % alignment) == 0);
// If there's not enough room for the block header, skip to the
// next aligned space within the block..
if ((unsigned long) newptr - (unsigned long) ptr < sizeof(block)) {
newptr += alignment;
}
assert (((unsigned long) newptr % alignment) == 0);
// Copy the block from the start of the allocated memory.
block *b = ((block *)ptr - 1);
// Copy the block from the start of the allocated memory.
block * b = ((block *) ptr - 1);
assert(b->isValid());
assert(b->getSuperblock()->isValid());
assert (b->isValid());
assert (b->getSuperblock()->isValid());
// Make sure there's enough room for the block header.
assert(((unsigned long)newptr - (unsigned long)ptr) >=
sizeof(block));
// Make sure there's enough room for the block header.
assert (((unsigned long) newptr - (unsigned long) ptr) >= sizeof(block));
block *p = ((block *)newptr - 1);
block * p = ((block *) newptr - 1);
// Make sure there's enough room allocated for size bytes.
assert(((unsigned long)p - sizeof(block)) >= (unsigned long)b);
// Make sure there's enough room allocated for size bytes.
assert (((unsigned long) p - sizeof(block)) >= (unsigned long) b);
if (p != b) {
assert((unsigned long)newptr > (unsigned long)ptr);
// Copy the block header.
*p = *b;
assert(p->isValid());
assert(p->getSuperblock()->isValid());
if (p != b) {
assert ((unsigned long) newptr > (unsigned long) ptr);
// Copy the block header.
*p = *b;
assert (p->isValid());
assert (p->getSuperblock()->isValid());
// Set the next pointer to point to b with the 1 bit set.
// When this block is freed, it will be treated specially.
p->setNext((block *)((unsigned long)b | 1));
} else
assert(ptr != newptr);
// Set the next pointer to point to b with the 1 bit set.
// When this block is freed, it will be treated specially.
p->setNext ((block *) ((unsigned long) b | 1));
} else {
assert (ptr != newptr);
}
assert (((unsigned long) ptr + newSize) >= ((unsigned long) newptr + size));
return newptr;
}
assert(((unsigned long)ptr + newSize) >=
((unsigned long)newptr + size));
return newptr;
}
}
size_t threadHeap::objectSize (void * ptr)
size_t
threadHeap::objectSize(void *ptr)
{
// Find the superblock pointer.
// Find the superblock pointer.
block *b = ((block *)ptr - 1);
assert(b->isValid());
superblock *sb = b->getSuperblock();
assert(sb);
block * b = ((block *) ptr - 1);
assert (b->isValid());
superblock * sb = b->getSuperblock ();
assert (sb);
// Return the size.
return sizeFromClass (sb->getBlockSizeClass());
// Return the size.
return sizeFromClass(sb->getBlockSizeClass());
}
void threadHeap::setpHeap (processHeap * p)
void threadHeap::setpHeap(processHeap *p)
{
_pHeap = p;
_pHeap = p;
}
#endif // _THREADHEAP_H_
} // namespace BPrivate
#endif // _THREADHEAP_H_
+6 -18
View File
@@ -23,11 +23,14 @@
*/
#include <string.h>
#include "config.h"
#include "threadheap.h"
#include "processheap.h"
#include "arch-specific.h"
using namespace BPrivate;
inline static processHeap *
getAllocator(void)
@@ -38,21 +41,7 @@ getAllocator(void)
return theAllocator;
}
#define HOARD_MALLOC(x) malloc(x)
#define HOARD_FREE(x) free(x)
#define HOARD_REALLOC(x,y) realloc(x,y)
#define HOARD_CALLOC(x,y) calloc(x,y)
#define HOARD_MEMALIGN(x,y) memalign(x,y)
#define HOARD_VALLOC(x) valloc(x)
extern "C" void * HOARD_MALLOC(size_t);
extern "C" void HOARD_FREE(void *);
extern "C" void * HOARD_REALLOC(void *, size_t);
extern "C" void * HOARD_CALLOC(size_t, size_t);
extern "C" void * HOARD_MEMALIGN(size_t, size_t);
extern "C" void * HOARD_VALLOC(size_t);
#if 0
void * operator new (size_t size)
{
return HOARD_MALLOC (size);
@@ -80,6 +69,7 @@ void operator delete[] (void * ptr)
{
HOARD_FREE (ptr);
}
#endif
extern "C" void *
@@ -133,7 +123,7 @@ extern "C" void *
realloc(void *ptr, size_t sz)
{
if (ptr == NULL)
return HOARD_MALLOC (sz);
return malloc(sz);
if (sz == 0) {
free(ptr);
@@ -148,7 +138,6 @@ realloc(void *ptr, size_t sz)
return ptr;
// Allocate a new block of size sz.
void *buffer = malloc(sz);
// Copy the contents of the original object
@@ -158,7 +147,6 @@ realloc(void *ptr, size_t sz)
memcpy(buffer, ptr, minSize);
// Free the old block.
free(ptr);
// Return a pointer to the new one.