runtime_loader: Resize heap areas instead of creating new ones.

This is more efficient and works most of the time. Additionally,
we can potentially join with a previous free chunk in the allocator,
avoiding extra fragmentation on the heap.

app_server (on x86_64) only has 1 "rld heap" area after this change
with a size of 0x50000 (320KB), whereas previously it had around 7
with a total size of 0x80000 (512KB).
This commit is contained in:
Augustin Cavalier
2025-01-07 17:30:29 -05:00
parent 7137fc03b2
commit babcaa3c29
2 changed files with 45 additions and 22 deletions
+24 -21
View File
@@ -220,13 +220,10 @@ public:
{
FreeChunk* chunk = (FreeChunk*)base;
chunk->SetTo(size);
fFreeChunkTree.Insert(chunk);
fAvailable += chunk->Size();
#ifdef DEBUG_MAX_HEAP_USAGE
fMaxHeapSize += chunk->Size();
fMaxHeapUsage = fMaxHeapSize - fAvailable;
#endif
_InsertChunk(chunk);
}
uint32 Available() const { return fAvailable; }
@@ -329,13 +326,35 @@ public:
((uint32*)allocated)[i] = 0xdeadbeef;
#endif
_InsertChunk(freedChunk);
}
#ifdef DEBUG_MAX_HEAP_USAGE
uint32 MaxHeapSize() const { return fMaxHeapSize; }
uint32 MaxHeapUsage() const { return fMaxHeapUsage; }
#endif
void DumpChunks()
{
FreeChunk* chunk = fFreeChunkTree.FindMin();
while (chunk != NULL) {
printf("\t%p: chunk size = %ld, end = %p, next = %p\n", chunk,
chunk->Size(), (uint8*)chunk + chunk->CompleteSize(),
chunk->Next());
chunk = chunk->Next();
}
}
private:
void _InsertChunk(FreeChunk* freedChunk)
{
// try to join the new free chunk with an existing one
// it may be joined with up to two chunks
FreeChunk* chunk = fFreeChunkTree.FindMin();
int32 joinCount = 0;
while (chunk) {
while (chunk != NULL) {
FreeChunk* nextChunk = chunk->Next();
if (chunk->IsTouching(freedChunk)) {
@@ -358,22 +377,6 @@ public:
#endif
}
#ifdef DEBUG_MAX_HEAP_USAGE
uint32 MaxHeapSize() const { return fMaxHeapSize; }
uint32 MaxHeapUsage() const { return fMaxHeapUsage; }
#endif
void DumpChunks()
{
FreeChunk* chunk = fFreeChunkTree.FindMin();
while (chunk != NULL) {
printf("\t%p: chunk size = %ld, end = %p, next = %p\n", chunk,
chunk->Size(), (uint8*)chunk + chunk->CompleteSize(),
chunk->Next());
chunk = chunk->Next();
}
}
private:
FreeChunkTree fFreeChunkTree;
uint32 fAvailable;
+21 -1
View File
@@ -31,6 +31,10 @@ const static size_t kHeapGrowthAlignment = 32 * 1024;
static const char* const kLockName = "runtime_loader heap";
static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName);
static void* sLastHeapBase;
static size_t sLastHeapAreaSize;
static area_id sLastHeapArea;
static SimpleAllocator<kAlignment> sAllocator;
@@ -40,12 +44,26 @@ static SimpleAllocator<kAlignment> sAllocator;
static status_t
add_area(size_t size)
{
if (sLastHeapAreaSize != 0) {
// Try to resize the previous area instead of creating a new one.
status_t status = _kern_resize_area(sLastHeapArea, sLastHeapAreaSize + size);
if (status == B_OK) {
sAllocator.AddChunk((uint8*)sLastHeapBase + sLastHeapAreaSize, size);
sLastHeapAreaSize += size;
return B_OK;
}
}
void* base;
area_id area = _kern_create_area("rld heap", &base,
B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (area < 0)
return area;
sLastHeapBase = base;
sLastHeapArea = area;
sLastHeapAreaSize = size;
sAllocator.AddChunk(base, size);
return B_OK;
}
@@ -54,7 +72,8 @@ add_area(size_t size)
static status_t
grow_heap(size_t bytes)
{
return add_area(sAllocator.Align(kAlignment + bytes, kHeapGrowthAlignment));
// Add kAlignment so that the heap has enough space for bookkeeping data.
return add_area(sAllocator.Align(bytes + kAlignment, kHeapGrowthAlignment));
}
@@ -72,6 +91,7 @@ status_t
heap_reinit_after_fork()
{
recursive_lock_init(&sLock, kLockName);
sLastHeapArea = _kern_area_for(sLastHeapBase);
return B_OK;
}