mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-24 05:49:58 +00:00
Merge pull request #1945 from unknownbrackets/perf
Rewrite BlockAllocator in attempt to free memory faster
This commit is contained in:
commit
8438f0f4d2
@ -21,9 +21,8 @@
|
||||
|
||||
// Slow freaking thing but works (eventually) :)
|
||||
|
||||
BlockAllocator::BlockAllocator(int grain) : grain_(grain)
|
||||
BlockAllocator::BlockAllocator(int grain) : grain_(grain), top_(NULL), bottom_(NULL)
|
||||
{
|
||||
blocks.clear();
|
||||
}
|
||||
|
||||
BlockAllocator::~BlockAllocator()
|
||||
@ -37,12 +36,19 @@ void BlockAllocator::Init(u32 rangeStart, u32 rangeSize)
|
||||
rangeStart_ = rangeStart;
|
||||
rangeSize_ = rangeSize;
|
||||
//Initial block, covering everything
|
||||
blocks.push_back(Block(rangeStart_, rangeSize_, false));
|
||||
top_ = new Block(rangeStart_, rangeSize_, false, NULL, NULL);
|
||||
bottom_ = top_;
|
||||
}
|
||||
|
||||
void BlockAllocator::Shutdown()
|
||||
{
|
||||
blocks.clear();
|
||||
while (bottom_ != NULL)
|
||||
{
|
||||
Block *next = bottom_->next;
|
||||
delete bottom_;
|
||||
bottom_ = next;
|
||||
}
|
||||
top_ = NULL;
|
||||
}
|
||||
|
||||
u32 BlockAllocator::AllocAligned(u32 &size, u32 sizeGrain, u32 grain, bool fromTop, const char *tag)
|
||||
@ -65,9 +71,9 @@ u32 BlockAllocator::AllocAligned(u32 &size, u32 sizeGrain, u32 grain, bool fromT
|
||||
if (!fromTop)
|
||||
{
|
||||
//Allocate from bottom of mem
|
||||
for (std::list<Block>::iterator iter = blocks.begin(); iter != blocks.end(); iter++)
|
||||
for (Block *bp = bottom_; bp != NULL; bp = bp->next)
|
||||
{
|
||||
Block &b = *iter;
|
||||
Block &b = *bp;
|
||||
u32 offset = b.start % grain;
|
||||
if (offset != 0)
|
||||
offset = grain - offset;
|
||||
@ -82,7 +88,7 @@ u32 BlockAllocator::AllocAligned(u32 &size, u32 sizeGrain, u32 grain, bool fromT
|
||||
}
|
||||
else
|
||||
{
|
||||
blocks.insert(++iter, Block(b.start + needed, b.size - needed, false));
|
||||
InsertFreeAfter(&b, b.start + needed, b.size - needed);
|
||||
b.taken = true;
|
||||
b.size = needed;
|
||||
b.SetTag(tag);
|
||||
@ -94,9 +100,9 @@ u32 BlockAllocator::AllocAligned(u32 &size, u32 sizeGrain, u32 grain, bool fromT
|
||||
else
|
||||
{
|
||||
// Allocate from top of mem.
|
||||
for (std::list<Block>::reverse_iterator iter = blocks.rbegin(); iter != blocks.rend(); ++iter)
|
||||
for (Block *bp = top_; bp != NULL; bp = bp->prev)
|
||||
{
|
||||
Block &b = *iter;
|
||||
Block &b = *bp;
|
||||
u32 offset = (b.start + b.size - size) % grain;
|
||||
u32 needed = offset + size;
|
||||
if (b.taken == false && b.size >= needed)
|
||||
@ -109,8 +115,7 @@ u32 BlockAllocator::AllocAligned(u32 &size, u32 sizeGrain, u32 grain, bool fromT
|
||||
}
|
||||
else
|
||||
{
|
||||
std::list<Block>::iterator pos = iter.base();
|
||||
blocks.insert(--pos, Block(b.start, b.size - needed, false));
|
||||
InsertFreeBefore(&b, b.start, b.size - needed);
|
||||
b.taken = true;
|
||||
b.start += b.size - needed;
|
||||
b.size = needed;
|
||||
@ -149,10 +154,10 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag)
|
||||
ERROR_LOG(HLE, "Position %08x does not align to grain. Grain will be off.", position);
|
||||
}
|
||||
|
||||
std::list<Block>::iterator iter = GetBlockIterFromAddress(position);
|
||||
if (iter != blocks.end())
|
||||
Block *bp = GetBlockFromAddress(position);
|
||||
if (bp != NULL)
|
||||
{
|
||||
Block &b = *iter;
|
||||
Block &b = *bp;
|
||||
if (b.taken)
|
||||
{
|
||||
ERROR_LOG(HLE, "Block allocator AllocAt failed, block taken! %08x, %i", position, size);
|
||||
@ -163,7 +168,7 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag)
|
||||
//good to go
|
||||
if (b.start == position)
|
||||
{
|
||||
blocks.insert(++iter, Block(b.start + size, b.size - size, false));
|
||||
InsertFreeAfter(&b, b.start + size, b.size - size);
|
||||
b.taken = true;
|
||||
b.size = size;
|
||||
b.SetTag(tag);
|
||||
@ -173,12 +178,9 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag)
|
||||
else
|
||||
{
|
||||
int size1 = position - b.start;
|
||||
blocks.insert(iter, Block(b.start, size1, false));
|
||||
InsertFreeBefore(&b, b.start, size1);
|
||||
if (b.start + b.size > position + size)
|
||||
{
|
||||
iter++;
|
||||
blocks.insert(iter, Block(position + size, b.size - (size + size1), false));
|
||||
}
|
||||
InsertFreeAfter(&b, position + size, b.size - (size + size1));
|
||||
b.taken = true;
|
||||
b.start = position;
|
||||
b.size = size;
|
||||
@ -199,39 +201,53 @@ u32 BlockAllocator::AllocAt(u32 position, u32 size, const char *tag)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void BlockAllocator::MergeFreeBlocks()
|
||||
void BlockAllocator::MergeFreeBlocks(Block *fromBlock)
|
||||
{
|
||||
restart:
|
||||
DEBUG_LOG(HLE, "Merging Blocks");
|
||||
std::list<Block>::iterator iter1, iter2;
|
||||
iter1 = blocks.begin();
|
||||
iter2 = blocks.begin();
|
||||
iter2++;
|
||||
while (iter2 != blocks.end())
|
||||
|
||||
Block *prev = fromBlock->prev;
|
||||
while (prev != NULL && prev->taken == false)
|
||||
{
|
||||
BlockAllocator::Block &b1 = *iter1;
|
||||
BlockAllocator::Block &b2 = *iter2;
|
||||
|
||||
if (b1.taken == false && b2.taken == false)
|
||||
{
|
||||
DEBUG_LOG(HLE, "Block Alloc found adjacent free blocks - merging");
|
||||
b1.size += b2.size;
|
||||
blocks.erase(iter2);
|
||||
CheckBlocks();
|
||||
goto restart; //iterators now invalid - we have to restart our search
|
||||
}
|
||||
iter1++;
|
||||
iter2++;
|
||||
DEBUG_LOG(HLE, "Block Alloc found adjacent free blocks - merging");
|
||||
prev->size += fromBlock->size;
|
||||
if (fromBlock->next == NULL)
|
||||
top_ = prev;
|
||||
else
|
||||
fromBlock->next->prev = prev;
|
||||
prev->next = fromBlock->next;
|
||||
delete fromBlock;
|
||||
fromBlock = prev;
|
||||
prev = fromBlock->prev;
|
||||
}
|
||||
|
||||
if (prev == NULL)
|
||||
bottom_ = fromBlock;
|
||||
else
|
||||
prev->next = fromBlock;
|
||||
|
||||
Block *next = fromBlock->next;
|
||||
while (next != NULL && next->taken == false)
|
||||
{
|
||||
DEBUG_LOG(HLE, "Block Alloc found adjacent free blocks - merging");
|
||||
fromBlock->size += next->size;
|
||||
fromBlock->next = next->next;
|
||||
delete next;
|
||||
next = fromBlock->next;
|
||||
}
|
||||
|
||||
if (next == NULL)
|
||||
top_ = fromBlock;
|
||||
else
|
||||
next->prev = fromBlock;
|
||||
}
|
||||
|
||||
bool BlockAllocator::Free(u32 position)
|
||||
{
|
||||
BlockAllocator::Block *b = GetBlockFromAddress(position);
|
||||
Block *b = GetBlockFromAddress(position);
|
||||
if (b && b->taken)
|
||||
{
|
||||
b->taken = false;
|
||||
MergeFreeBlocks();
|
||||
MergeFreeBlocks(b);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -243,9 +259,13 @@ bool BlockAllocator::Free(u32 position)
|
||||
|
||||
bool BlockAllocator::FreeExact(u32 position)
|
||||
{
|
||||
BlockAllocator::Block *b = GetBlockFromAddress(position);
|
||||
Block *b = GetBlockFromAddress(position);
|
||||
if (b && b->taken && b->start == position)
|
||||
return Free(position);
|
||||
{
|
||||
b->taken = false;
|
||||
MergeFreeBlocks(b);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "BlockAllocator : invalid free %08x", position);
|
||||
@ -253,74 +273,103 @@ bool BlockAllocator::FreeExact(u32 position)
|
||||
}
|
||||
}
|
||||
|
||||
void BlockAllocator::CheckBlocks()
|
||||
BlockAllocator::Block *BlockAllocator::InsertFreeBefore(Block *b, u32 start, u32 size)
|
||||
{
|
||||
for (std::list<Block>::iterator iter = blocks.begin(); iter != blocks.end(); iter++)
|
||||
Block *inserted = new Block(start, size, false, b->prev, b);
|
||||
b->prev = inserted;
|
||||
if (inserted->prev == NULL)
|
||||
bottom_ = inserted;
|
||||
else
|
||||
inserted->prev->next = inserted;
|
||||
|
||||
return inserted;
|
||||
}
|
||||
|
||||
BlockAllocator::Block *BlockAllocator::InsertFreeAfter(Block *b, u32 start, u32 size)
|
||||
{
|
||||
Block *inserted = new Block(start, size, false, b, b->next);
|
||||
b->next = inserted;
|
||||
if (inserted->next == NULL)
|
||||
top_ = inserted;
|
||||
else
|
||||
inserted->next->prev = inserted;
|
||||
|
||||
return inserted;
|
||||
}
|
||||
|
||||
void BlockAllocator::CheckBlocks() const
|
||||
{
|
||||
for (const Block *bp = bottom_; bp != NULL; bp = bp->next)
|
||||
{
|
||||
BlockAllocator::Block &b = *iter;
|
||||
const Block &b = *bp;
|
||||
if (b.start > 0xc0000000) { // probably free'd debug values
|
||||
ERROR_LOG(HLE, "Bogus block in allocator");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::list<BlockAllocator::Block>::iterator BlockAllocator::GetBlockIterFromAddress(u32 addr)
|
||||
inline BlockAllocator::Block *BlockAllocator::GetBlockFromAddress(u32 addr)
|
||||
{
|
||||
for (std::list<Block>::iterator iter = blocks.begin(); iter != blocks.end(); iter++)
|
||||
for (Block *bp = bottom_; bp != NULL; bp = bp->next)
|
||||
{
|
||||
BlockAllocator::Block &b = *iter;
|
||||
if (b.start <= addr && b.start+b.size > addr)
|
||||
Block &b = *bp;
|
||||
if (b.start <= addr && b.start + b.size > addr)
|
||||
{
|
||||
// Got one!
|
||||
return iter;
|
||||
return bp;
|
||||
}
|
||||
}
|
||||
return blocks.end();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BlockAllocator::Block *BlockAllocator::GetBlockFromAddress(u32 addr)
|
||||
const BlockAllocator::Block *BlockAllocator::GetBlockFromAddress(u32 addr) const
|
||||
{
|
||||
std::list<Block>::iterator iter = GetBlockIterFromAddress(addr);
|
||||
if (iter == blocks.end())
|
||||
return 0;
|
||||
else
|
||||
return &(*iter);
|
||||
for (const Block *bp = bottom_; bp != NULL; bp = bp->next)
|
||||
{
|
||||
const Block &b = *bp;
|
||||
if (b.start <= addr && b.start + b.size > addr)
|
||||
{
|
||||
// Got one!
|
||||
return bp;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u32 BlockAllocator::GetBlockStartFromAddress(u32 addr)
|
||||
u32 BlockAllocator::GetBlockStartFromAddress(u32 addr) const
|
||||
{
|
||||
Block *b = GetBlockFromAddress(addr);
|
||||
const Block *b = GetBlockFromAddress(addr);
|
||||
if (b)
|
||||
return b->start;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
u32 BlockAllocator::GetBlockSizeFromAddress(u32 addr)
|
||||
u32 BlockAllocator::GetBlockSizeFromAddress(u32 addr) const
|
||||
{
|
||||
Block *b = GetBlockFromAddress(addr);
|
||||
const Block *b = GetBlockFromAddress(addr);
|
||||
if (b)
|
||||
return b->size;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void BlockAllocator::ListBlocks()
|
||||
void BlockAllocator::ListBlocks() const
|
||||
{
|
||||
INFO_LOG(HLE,"-----------");
|
||||
for (std::list<Block>::const_iterator iter = blocks.begin(); iter != blocks.end(); iter++)
|
||||
for (const Block *bp = bottom_; bp != NULL; bp = bp->next)
|
||||
{
|
||||
const Block &b = *iter;
|
||||
const Block &b = *bp;
|
||||
INFO_LOG(HLE, "Block: %08x - %08x size %08x taken=%i tag=%s", b.start, b.start+b.size, b.size, b.taken ? 1:0, b.tag);
|
||||
}
|
||||
}
|
||||
|
||||
u32 BlockAllocator::GetLargestFreeBlockSize()
|
||||
u32 BlockAllocator::GetLargestFreeBlockSize() const
|
||||
{
|
||||
u32 maxFreeBlock = 0;
|
||||
for (std::list<Block>::const_iterator iter = blocks.begin(); iter != blocks.end(); iter++)
|
||||
for (const Block *bp = bottom_; bp != NULL; bp = bp->next)
|
||||
{
|
||||
const Block &b = *iter;
|
||||
const Block &b = *bp;
|
||||
if (!b.taken)
|
||||
{
|
||||
if (b.size > maxFreeBlock)
|
||||
@ -330,12 +379,12 @@ u32 BlockAllocator::GetLargestFreeBlockSize()
|
||||
return maxFreeBlock;
|
||||
}
|
||||
|
||||
u32 BlockAllocator::GetTotalFreeBytes()
|
||||
u32 BlockAllocator::GetTotalFreeBytes() const
|
||||
{
|
||||
u32 sum = 0;
|
||||
for (std::list<Block>::const_iterator iter = blocks.begin(); iter != blocks.end(); iter++)
|
||||
for (const Block *bp = bottom_; bp != NULL; bp = bp->next)
|
||||
{
|
||||
const Block &b = *iter;
|
||||
const Block &b = *bp;
|
||||
if (!b.taken)
|
||||
{
|
||||
sum += b.size;
|
||||
@ -346,8 +395,42 @@ u32 BlockAllocator::GetTotalFreeBytes()
|
||||
|
||||
void BlockAllocator::DoState(PointerWrap &p)
|
||||
{
|
||||
Block b(0, 0, false);
|
||||
p.Do(blocks, b);
|
||||
int count = 0;
|
||||
|
||||
if (p.mode == p.MODE_READ)
|
||||
{
|
||||
Shutdown();
|
||||
p.Do(count);
|
||||
|
||||
bottom_ = new Block(0, 0, false, NULL, NULL);
|
||||
bottom_->DoState(p);
|
||||
--count;
|
||||
|
||||
top_ = bottom_;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
top_->next = new Block(0, 0, false, top_, NULL);
|
||||
top_->next->DoState(p);
|
||||
top_ = top_->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const Block *bp = bottom_; bp != NULL; bp = bp->next)
|
||||
++count;
|
||||
p.Do(count);
|
||||
|
||||
bottom_->DoState(p);
|
||||
--count;
|
||||
|
||||
Block *last = bottom_;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
last->next->DoState(p);
|
||||
last = last->next;
|
||||
}
|
||||
}
|
||||
|
||||
p.Do(rangeStart_);
|
||||
p.Do(rangeSize_);
|
||||
p.Do(grain_);
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
void Init(u32 _rangeStart, u32 _rangeSize);
|
||||
void Shutdown();
|
||||
|
||||
void ListBlocks();
|
||||
void ListBlocks() const;
|
||||
|
||||
// WARNING: size can be modified upwards!
|
||||
u32 Alloc(u32 &size, bool fromTop = false, const char *tag = 0);
|
||||
@ -53,21 +53,20 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void MergeFreeBlocks();
|
||||
|
||||
u32 GetBlockStartFromAddress(u32 addr);
|
||||
u32 GetBlockSizeFromAddress(u32 addr);
|
||||
u32 GetLargestFreeBlockSize();
|
||||
u32 GetTotalFreeBytes();
|
||||
u32 GetBlockStartFromAddress(u32 addr) const;
|
||||
u32 GetBlockSizeFromAddress(u32 addr) const;
|
||||
u32 GetLargestFreeBlockSize() const;
|
||||
u32 GetTotalFreeBytes() const;
|
||||
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
private:
|
||||
void CheckBlocks();
|
||||
void CheckBlocks() const;
|
||||
|
||||
struct Block
|
||||
{
|
||||
Block(u32 _start, u32 _size, bool _taken) : start(_start), size(_size), taken(_taken)
|
||||
Block(u32 _start, u32 _size, bool _taken, Block *_prev, Block *_next)
|
||||
: start(_start), size(_size), taken(_taken), prev(_prev), next(_next)
|
||||
{
|
||||
strcpy(tag, "(untitled)");
|
||||
}
|
||||
@ -83,14 +82,20 @@ private:
|
||||
u32 size;
|
||||
bool taken;
|
||||
char tag[32];
|
||||
Block *prev;
|
||||
Block *next;
|
||||
};
|
||||
|
||||
std::list<Block> blocks;
|
||||
Block *bottom_;
|
||||
Block *top_;
|
||||
u32 rangeStart_;
|
||||
u32 rangeSize_;
|
||||
|
||||
u32 grain_;
|
||||
|
||||
void MergeFreeBlocks(Block *fromBlock);
|
||||
Block *GetBlockFromAddress(u32 addr);
|
||||
std::list<Block>::iterator GetBlockIterFromAddress(u32 addr);
|
||||
const Block *GetBlockFromAddress(u32 addr) const;
|
||||
Block *InsertFreeBefore(Block *b, u32 start, u32 size);
|
||||
Block *InsertFreeAfter(Block *b, u32 start, u32 size);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user