From dde0ba62233248d527aa7336bca599bce52b13d7 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 5 Jul 2008 01:12:34 +0000 Subject: [PATCH] Make the all_areas list ordered by base and take advantage of this ordering when looking up the target area on free(). This makes free() scale better with large area counts, as the lookup can abort early when it knows that no area below the only candidate can contain the address. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26258 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/heap.cpp | 45 ++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/system/kernel/heap.cpp b/src/system/kernel/heap.cpp index 1b7bbae64a..c7a7662959 100644 --- a/src/system/kernel/heap.cpp +++ b/src/system/kernel/heap.cpp @@ -641,7 +641,7 @@ heap_validate_heap(heap_allocator *heap) uint32 totalPageCount = 0; uint32 totalFreePageCount = 0; heap_area *area = heap->all_areas; - while (area) { + while (area != NULL) { // validate the free pages list uint32 freePageCount = 0; heap_page *lastPage = NULL; @@ -693,9 +693,9 @@ heap_validate_heap(heap_allocator *heap) area = heap->areas; heap_area *lastArea = NULL; uint32 lastFreeCount = 0; - while (area) { + while (area != NULL) { if (area->free_page_count < lastFreeCount) - panic("ordering of area list broken\n"); + panic("size ordering of area list broken\n"); if (area->prev != lastArea) panic("area list entry has invalid prev link\n"); @@ -705,6 +705,16 @@ heap_validate_heap(heap_allocator *heap) area = area->next; } + lastArea = NULL; + area = heap->all_areas; + while (area != NULL) { + if (lastArea != NULL && lastArea->base < area->base) + panic("base ordering of all_areas list broken\n"); + + lastArea = area; + area = area->all_next; + } + // validate the bins for (uint32 i = 0; i < heap->bin_count; i++) { heap_bin *bin = &heap->bins[i]; @@ -845,8 +855,19 @@ heap_add_area(heap_allocator *heap, area_id areaID, addr_t base, size_t size) area->prev = lastArea; } - area->all_next = heap->all_areas; - heap->all_areas = area; + // insert this area in the all_areas list so it stays ordered by base + if (heap->all_areas == NULL || heap->all_areas->base < area->base) { + area->all_next = heap->all_areas; + heap->all_areas = area; + } else { + heap_area *insert = heap->all_areas; + while (insert->all_next && insert->all_next->base > area->base) + insert = insert->all_next; + + area->all_next = insert->all_next; + insert->all_next = area; + } + heap->total_pages += area->page_count; heap->total_free_pages += area->free_page_count; @@ -1283,9 +1304,19 @@ heap_free(heap_allocator *heap, void *address) heap_area *area = heap->all_areas; while (area) { - if ((addr_t)address >= area->base - && (addr_t)address < area->base + area->size) + // since the all_areas list is ordered by base with the biggest + // base at the top, we need only find the first area with a base + // smaller than our address to become our only candidate for freeing + if (area->base <= (addr_t)address) { + if ((addr_t)address >= area->base + area->size) { + // the only candidate area doesn't contain the address, + // set it to NULL so we return below (none of the other areas + // can contain the address as the list is ordered) + area = NULL; + } + break; + } area = area->all_next; }