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; FreeChunk* chunk = (FreeChunk*)base;
chunk->SetTo(size); chunk->SetTo(size);
fFreeChunkTree.Insert(chunk);
fAvailable += chunk->Size();
#ifdef DEBUG_MAX_HEAP_USAGE #ifdef DEBUG_MAX_HEAP_USAGE
fMaxHeapSize += chunk->Size(); fMaxHeapSize += chunk->Size();
fMaxHeapUsage = fMaxHeapSize - fAvailable;
#endif #endif
_InsertChunk(chunk);
} }
uint32 Available() const { return fAvailable; } uint32 Available() const { return fAvailable; }
@@ -329,13 +326,35 @@ public:
((uint32*)allocated)[i] = 0xdeadbeef; ((uint32*)allocated)[i] = 0xdeadbeef;
#endif #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 // try to join the new free chunk with an existing one
// it may be joined with up to two chunks // it may be joined with up to two chunks
FreeChunk* chunk = fFreeChunkTree.FindMin(); FreeChunk* chunk = fFreeChunkTree.FindMin();
int32 joinCount = 0; int32 joinCount = 0;
while (chunk) { while (chunk != NULL) {
FreeChunk* nextChunk = chunk->Next(); FreeChunk* nextChunk = chunk->Next();
if (chunk->IsTouching(freedChunk)) { if (chunk->IsTouching(freedChunk)) {
@@ -358,22 +377,6 @@ public:
#endif #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: private:
FreeChunkTree fFreeChunkTree; FreeChunkTree fFreeChunkTree;
uint32 fAvailable; 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 const char* const kLockName = "runtime_loader heap";
static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName); static recursive_lock sLock = RECURSIVE_LOCK_INITIALIZER(kLockName);
static void* sLastHeapBase;
static size_t sLastHeapAreaSize;
static area_id sLastHeapArea;
static SimpleAllocator<kAlignment> sAllocator; static SimpleAllocator<kAlignment> sAllocator;
@@ -40,12 +44,26 @@ static SimpleAllocator<kAlignment> sAllocator;
static status_t static status_t
add_area(size_t size) 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; void* base;
area_id area = _kern_create_area("rld heap", &base, area_id area = _kern_create_area("rld heap", &base,
B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); B_RANDOMIZED_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (area < 0) if (area < 0)
return area; return area;
sLastHeapBase = base;
sLastHeapArea = area;
sLastHeapAreaSize = size;
sAllocator.AddChunk(base, size); sAllocator.AddChunk(base, size);
return B_OK; return B_OK;
} }
@@ -54,7 +72,8 @@ add_area(size_t size)
static status_t static status_t
grow_heap(size_t bytes) 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() heap_reinit_after_fork()
{ {
recursive_lock_init(&sLock, kLockName); recursive_lock_init(&sLock, kLockName);
sLastHeapArea = _kern_area_for(sLastHeapBase);
return B_OK; return B_OK;
} }