diff options
author | Doug Gilbert <dgilbert@us.ibm.com> | 2011-09-26 13:36:33 -0500 |
---|---|---|
committer | Douglas R. Gilbert <dgilbert@us.ibm.com> | 2011-10-25 11:16:20 -0500 |
commit | 5ab488739184f2b2649193e3f9da695ee334d04f (patch) | |
tree | 3d47e74b8dd290598527988adccff0ff57c72dc0 /src/kernel/pagemgr.C | |
parent | d127ad9d985ffd7a42dba798bee66654242c4fe6 (diff) | |
download | talos-hostboot-5ab488739184f2b2649193e3f9da695ee334d04f.tar.gz talos-hostboot-5ab488739184f2b2649193e3f9da695ee334d04f.zip |
new HEAP manager to reduce fragmentation
Change-Id: Ibe725a43e6366d9113ec99df1cc6aafa7bbb770e
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/431
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Reviewed-by: Douglas R. Gilbert <dgilbert@us.ibm.com>
Diffstat (limited to 'src/kernel/pagemgr.C')
-rw-r--r-- | src/kernel/pagemgr.C | 90 |
1 files changed, 81 insertions, 9 deletions
diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C index 826e1bc4d..82e743ef1 100644 --- a/src/kernel/pagemgr.C +++ b/src/kernel/pagemgr.C @@ -24,8 +24,10 @@ #include <kernel/pagemgr.H> #include <util/singleton.H> #include <kernel/console.H> -#include <sys/vfs.h> #include <arch/ppc.H> +#include <util/locked/pqueue.H> + +size_t PageManager::cv_coalesce_count = 0; void PageManager::init() { @@ -51,14 +53,11 @@ uint64_t PageManager::queryAvail() PageManager::PageManager() : iv_pagesAvail(0), iv_pagesTotal(0) { - // Determine first page of un-allocated memory. - uint64_t addr = (uint64_t) VFS_LAST_ADDRESS; - if (0 != (addr % PAGESIZE)) - addr = (addr - (addr % PAGESIZE)) + PAGESIZE; - - // Determine number of pages available. - page_t* page = (page_t*)((void*) addr); + // Determine first page of un-allocated memory + // and number of pages available. + uint64_t addr = firstPageAddr(); size_t length = (MEMLEN - addr) / PAGESIZE; + page_t* page = reinterpret_cast<page_t *>(addr); iv_pagesTotal = length; // Update statistics. @@ -70,7 +69,7 @@ PageManager::PageManager() : iv_pagesAvail(0), iv_pagesTotal(0) (uint64_t)page); // Populate L3 cache lines. - uint64_t* cache_line = (uint64_t*) addr; + uint64_t* cache_line = reinterpret_cast<uint64_t*>(addr); uint64_t* end_cache_line = (uint64_t*) VmmManager::FULL_MEM_SIZE; while (cache_line != end_cache_line) { @@ -163,3 +162,76 @@ void PageManager::push_bucket(page_t* p, size_t n) first_page[n].push(p); } +void PageManager::coalesce( void ) +{ + Singleton<PageManager>::instance()._coalesce(); +} + + +// Coalsesce adjacent free memory blocks +void PageManager::_coalesce( void ) +{ + // Look at all the "free buckets" and find blocks to merge + // Since this is binary, all merges will be from the same free bucket + // Each bucket is a stack of non-allocated memory blocks of the same size + // Once two blocks are merged they become a single block twice the size. + // The source blocks must be removed from the current bucket (stack) and + // the new block needs to be pushed onto the next biggest stack. + for(size_t bucket = 0; bucket < (BUCKETS-1); ++bucket) + { + // Move the this stack bucket into a priority queue + // sorted by address, highest to lowest + Util::Locked::PQueue<page_t,page_t*> pq; + page_t * p = NULL; + while(NULL != (p = first_page[bucket].pop())) + { + p->key = p; + pq.insert(p); + } + + while(NULL != (p = pq.remove())) + { + // p needs to be the even buddy to prevent merging of wrong block. + // To determine this, get the index of the block as if the whole + // page memory space were blocks of this size. + uint64_t p_idx = (reinterpret_cast<uint64_t>(p) - firstPageAddr())/ + ((1 << bucket)*PAGESIZE); + if(0 != (p_idx % 2)) // odd index + { + first_page[bucket].push(p); // can't merge + } + else // it's even + { + // If p can be merged then the next block in pq will be the + // match. The address of p also can't be greater than what's + // in pq or something is really messed up, therefore if + // pq.remove_if() returns something then it's a match. + page_t * p_seek = (page_t*)((uint64_t)p + + (1 << bucket)*PAGESIZE); + page_t * p_next = pq.remove_if(p_seek); + if(p_next == p_seek) + { + // new block is twice the size and goes into the next + // bucket size + push_bucket(p,bucket+1); + ++cv_coalesce_count; + } + else + { + // Can't merge p + first_page[bucket].push(p); + + if(p_next) // This should be null - if then overlaping mem + { + first_page[bucket].push(p_next); + printk("pagemgr::coalesce Expected %p, got %p\n", + p_seek, p_next); + } + } + } + } + } + printkd("PAGEMGR coalesced total %ld\n", cv_coalesce_count); +} + + |