From babcaa3c29c795532eb273239ba2eec36f74a73d Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Tue, 7 Jan 2025 17:29:34 -0500 Subject: [PATCH] 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). --- headers/private/kernel/util/SimpleAllocator.h | 45 ++++++++++--------- src/system/runtime_loader/heap.cpp | 22 ++++++++- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/headers/private/kernel/util/SimpleAllocator.h b/headers/private/kernel/util/SimpleAllocator.h index 1221c56974..43f489289c 100644 --- a/headers/private/kernel/util/SimpleAllocator.h +++ b/headers/private/kernel/util/SimpleAllocator.h @@ -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; diff --git a/src/system/runtime_loader/heap.cpp b/src/system/runtime_loader/heap.cpp index 5208ace974..37ca75bef9 100644 --- a/src/system/runtime_loader/heap.cpp +++ b/src/system/runtime_loader/heap.cpp @@ -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 sAllocator; @@ -40,12 +44,26 @@ static SimpleAllocator 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; }