#include "config.h"
#include "heap.h"
#include "processheap.h"
#include "superblock.h"
using namespace BPrivate;
#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::_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::_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::_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."
#endif
int hoardHeap::fMaxThreadHeaps = 1;
int hoardHeap::_numProcessors;
int hoardHeap::_numProcessorsMask;
static int
lg(int num)
{
assert(num > 0);
int power = 0;
int n = 1;
while (n < num) {
n <<= 1;
power++;
}
return power;
}
hoardHeap::hoardHeap(void)
:
_index(0), _reusableSuperblocks(NULL), _reusableSuperblocksCount(0)
#if HEAP_DEBUG
, _magic(HEAP_MAGIC)
#endif
{
initLock();
for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
for (int j = 0; j < SIZE_CLASSES; j++) {
_superblocks[i][j] = NULL;
}
}
for (int k = 0; k < SIZE_CLASSES; k++) {
_leastEmptyBin[k] = 0;
}
}
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);
sb->setOwner(this);
sb->computeFullness();
int fullness = sb->getFullness();
incStats(sizeclass, sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
if (fullness == 0
&& sb->getNumBlocks() > 1
&& sb->getNumBlocks() == sb->getNumAvailable()) {
#if 0
removeSuperblock(sb, sizeclass);
decStats(sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
const size_t s = sizeFromClass(sizeclass);
const int blksize = align(sizeof(block) + s);
#if HEAP_LOG
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()));
#endif
hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
#else
recycle(sb);
#endif
} else {
superblock *&head = _superblocks[fullness][sizeclass];
sb->insertBefore(head);
head = sb;
assert(head->isValid());
_leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
}
}
superblock *
hoardHeap::removeMaxSuperblock(int sizeclass)
{
assert(_magic == HEAP_MAGIC);
superblock *head = NULL;
head = reuse(sizeclass);
if (head) {
decStats(sizeclass,
head->getNumBlocks() - head->getNumAvailable(),
head->getNumBlocks());
return head;
}
int i = 0;
while (i < SUPERBLOCK_FULLNESS_GROUP) {
head = _superblocks[i][sizeclass];
if (head)
break;
i++;
}
if (!head)
return NULL;
assert(head->getNumAvailable() * EMPTY_FRACTION >= head->getNumBlocks());
removeSuperblock(head, sizeclass);
assert(head->isValid());
assert(head->getPrev() == NULL);
assert(head->getNext() == NULL);
return head;
}
void
hoardHeap::removeSuperblock(superblock *sb, int sizeclass)
{
assert(_magic == HEAP_MAGIC);
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;
}
}
sb->remove();
decStats(sizeclass, sb->getNumBlocks() - sb->getNumAvailable(),
sb->getNumBlocks());
}
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);
superblock *&oldHead = _superblocks[fromBin][sizeclass];
if (sb == oldHead) {
oldHead = sb->getNext();
if (oldHead != NULL) {
assert(oldHead->isValid());
}
}
sb->remove();
superblock *&newHead = _superblocks[toBin][sizeclass];
sb->insertBefore(newHead);
newHead = sb;
assert(newHead->isValid());
_leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
}
int
hoardHeap::freeBlock(block * &b, superblock * &sb,
int sizeclass, processHeap *pHeap)
{
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();
if (sb->getNumBlocks() == 1) {
removeSuperblock(sb, sizeclass);
const size_t s = sizeFromClass(sizeclass);
const int blksize = align(sizeof(block) + s);
#if HEAP_LOG
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()));
#endif
hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
return 1;
}
if (newFullness != oldFullness) {
moveSuperblock(sb, sizeclass, oldFullness, newFullness);
} else {
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 0
const size_t s = sizeFromClass(sizeclass);
const int blksize = align(sizeof(block) + s);
#if HEAP_LOG
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()));
#endif
hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
return 1;
#else
recycle(sb);
incStats(sizeclass,
sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
#endif
}
if (this == (hoardHeap *)pHeap)
return 0;
if (_numProcessors > 1) {
int inUse, allocated;
getStats(sizeclass, inUse, allocated);
if ((inUse < allocated - getReleaseThreshold(sizeclass))
&& (EMPTY_FRACTION * inUse <
EMPTY_FRACTION * allocated - allocated)) {
superblock *const maxSb = removeMaxSuperblock(sizeclass);
assert(maxSb != NULL);
assert(maxSb->getNumBlocks() >= maxSb->getNumAvailable());
pHeap->release(maxSb);
}
}
return 0;
}
void
hoardHeap::initNumProcs(void)
{
system_info info;
if (get_system_info(&info) != B_OK)
hoardHeap::_numProcessors = 1;
else
hoardHeap::_numProcessors = info.cpu_count;
fMaxThreadHeaps = 1 << (lg(_numProcessors) + 1);
_numProcessorsMask = fMaxThreadHeaps - 1;
}