diff options
author | Matthew Barth <msbarth@us.ibm.com> | 2011-10-20 15:49:12 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2011-10-25 15:12:23 -0500 |
commit | 0ad20184aec21ef0560a9eee7e7c26a36ace07e1 (patch) | |
tree | bb402e0c2342a791074fde9939701a1bbf9dedef | |
parent | 5ab488739184f2b2649193e3f9da695ee334d04f (diff) | |
download | talos-hostboot-0ad20184aec21ef0560a9eee7e7c26a36ace07e1.tar.gz talos-hostboot-0ad20184aec21ef0560a9eee7e7c26a36ace07e1.zip |
Update kernel 'EVICT' pages path to cast out pages when low on memory.
Change-Id: I79b9cfad5d80267c6709b094d7f852d89e08534b
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/452
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
-rw-r--r-- | src/include/kernel/block.H | 10 | ||||
-rw-r--r-- | src/include/kernel/pagemgr.H | 61 | ||||
-rw-r--r-- | src/kernel/basesegment.C | 5 | ||||
-rw-r--r-- | src/kernel/block.C | 72 | ||||
-rw-r--r-- | src/kernel/pagemgr.C | 5 | ||||
-rw-r--r-- | src/kernel/syscall.C | 2 | ||||
-rw-r--r-- | src/usr/testcore/kernel/vmmbasetest.H | 66 |
7 files changed, 111 insertions, 110 deletions
diff --git a/src/include/kernel/block.H b/src/include/kernel/block.H index 01187617f..60aeadaf0 100644 --- a/src/include/kernel/block.H +++ b/src/include/kernel/block.H @@ -143,16 +143,8 @@ class Block /** * @brief Cast out older phyiscal memory pages * @param[in] i_type - Castout contraint @see VmmManager::castOutPages() - * @return number of pages cast out */ - size_t castOutPages(uint64_t i_type); - - /** - * @brief Evict a memory page - * @param[in] i_pte shadow page table entry - * @return true of page was evicted - */ - bool evictPage(ShadowPTE* i_pte); + void castOutPages(uint64_t i_type); /** * @brief Removes a range of pages within a block of virtual memory diff --git a/src/include/kernel/pagemgr.H b/src/include/kernel/pagemgr.H index 3ed2c1b34..41fb1e493 100644 --- a/src/include/kernel/pagemgr.H +++ b/src/include/kernel/pagemgr.H @@ -39,6 +39,7 @@ class PageManager { public: + static void init(); static void* allocatePage(size_t n = 1); @@ -57,53 +58,63 @@ class PageManager */ static void coalesce( void ); - enum - { - MEMLEN = VmmManager::HTABORG, + /** + * Retrieve the number of available pages + * @returns Number of free pages + */ + static uint64_t availPages(); - BUCKETS = 16, - }; + enum + { + MEMLEN = VmmManager::HTABORG, + BUCKETS = 16, + }; protected: - PageManager(); - ~PageManager() {}; + + PageManager(); + ~PageManager() {}; private: - void* _allocatePage(size_t); - void _freePage(void*, size_t); + + void* _allocatePage(size_t); + void _freePage(void*, size_t); void _coalesce( void ); //!< see coalesce() /** see queryAvail() */ - ALWAYS_INLINE - uint64_t _queryAvail() const + ALWAYS_INLINE uint64_t _queryAvail() const { return (100*iv_pagesAvail)/iv_pagesTotal; } - ALWAYS_INLINE - uint64_t firstPageAddr( void ) + ALWAYS_INLINE uint64_t firstPageAddr( void ) { return ALIGN_PAGE(VFS_LAST_ADDRESS); } - - /** Statistics on number of free pages (for debug) */ + /** see availPages() */ + ALWAYS_INLINE uint64_t _availPages() const + { + return iv_pagesAvail; + } + + /** Statistics on number of free pages (for debug) */ uint64_t iv_pagesAvail; - /** Total number of pages */ + /** Total number of pages */ uint64_t iv_pagesTotal; - struct page_t - { - page_t* next; //!< Next block of pages + static size_t cv_coalesce_count; //!< running coalesced counter + + struct page_t + { + page_t* next; //!< Next block of pages page_t* prev; //!< Prev block of pages page_t* key; //!< Key for pqueue - }; - Util::Lockfree::Stack<page_t> first_page[BUCKETS]; + }; + Util::Lockfree::Stack<page_t> first_page[BUCKETS]; - page_t* pop_bucket(size_t); - void push_bucket(page_t*, size_t); - - static size_t cv_coalesce_count; //!< running coalesced counter + page_t* pop_bucket(size_t); + void push_bucket(page_t*, size_t); }; #endif diff --git a/src/kernel/basesegment.C b/src/kernel/basesegment.C index dee18600a..3e45b72ef 100644 --- a/src/kernel/basesegment.C +++ b/src/kernel/basesegment.C @@ -201,10 +201,7 @@ int BaseSegment::_mmSetPermission(void* i_va, uint64_t i_size, uint64_t i_access void BaseSegment::castOutPages(uint64_t i_type) { - size_t cast_out = 0; - cast_out = iv_block->castOutPages(i_type); - // Could try again with a more agressive constraint if cast_out == 0 ???? - if(cast_out) printkd("Cast out %ld pages,Type=%ld\n",cast_out,i_type); + iv_block->castOutPages(i_type); } /** * STATIC diff --git a/src/kernel/block.C b/src/kernel/block.C index 5b1520b1b..bdec164de 100644 --- a/src/kernel/block.C +++ b/src/kernel/block.C @@ -117,15 +117,6 @@ bool Block::handlePageFault(task_t* i_task, uint64_t i_addr) } else { - // Test code @TODO remove - SET up ro pages to test cast out pages - //if(pte->getPage() == 0) - //{ - // void* l_page = PageManager::allocatePage(); - // memset(l_page,'U',PAGESIZE); - // pte->setPageAddr(reinterpret_cast<uint64_t>(l_page)); - // pte->setPresent(true); - // pte->setWritable(false); - //} return false; //TODO - Swap kernel base block pages for user pages } } @@ -319,50 +310,25 @@ void Block::updateRefCount( uint64_t i_vaddr, } // track the changed/dirty bit - spte->setDirty( i_stats.C ); - -} - - -bool Block::evictPage(ShadowPTE* i_pte) -{ - ShadowPTE* pte = i_pte; - bool do_cast_out = false; - - if(!pte->isWritable()) // ro, executable - { - do_cast_out = true; - } - else // is writable... + if (i_stats.C) { - // if pte->isWriteTracked() flush then cast out + spte->setDirty( i_stats.C ); } - - if(do_cast_out) - { - PageTableManager::delEntry(pte->getPageAddr()); - PageManager::freePage(reinterpret_cast<void*>(pte->getPageAddr())); - pte->setPresent(false); - pte->setPageAddr(NULL); - } - - return do_cast_out; } -size_t Block::castOutPages(uint64_t i_type) +void Block::castOutPages(uint64_t i_type) { - size_t cast_out = 0; + void* l_vaddr = NULL; // drill down if(iv_nextBlock) { - cast_out += iv_nextBlock->castOutPages(i_type); + iv_nextBlock->castOutPages(i_type); } // TODO We will eventually need to skip other blocks as well, such as // when the memory space grows. if(iv_baseAddr != 0) // Skip base area { - bool is_cast_out = false; size_t rw_constraint = 5; size_t ro_constraint = 3; @@ -386,9 +352,12 @@ size_t Block::castOutPages(uint64_t i_type) if(pte->isWritable()) { - if((pte->getLRU() > rw_constraint) && pte->isWriteTracked()) + if(pte->getLRU() > rw_constraint && pte->isWriteTracked()) { - is_cast_out = evictPage(pte); + //'EVICT' single page + l_vaddr = reinterpret_cast<void*>(page); + this->removePages(VmmManager::EVICT,l_vaddr, + PAGESIZE,NULL); //printk("+"); } } @@ -396,22 +365,15 @@ size_t Block::castOutPages(uint64_t i_type) { if(pte->getLRU() > ro_constraint) { - is_cast_out = evictPage(pte); + //'EVICT' single page + l_vaddr = reinterpret_cast<void*>(page); + this->removePages(VmmManager::EVICT,l_vaddr, + PAGESIZE,NULL); } } - - if(is_cast_out) - { - //printk("-"); - ++cast_out; - is_cast_out = false; - } } } - //printk("\n"); } - - return cast_out; } int Block::mmSetPermission(uint64_t i_va, uint64_t i_size,uint64_t i_access_type) @@ -566,10 +528,7 @@ int Block::removePages(VmmManager::PAGE_REMOVAL_OPS i_op, void* i_vaddr, else if (pte->isDirty() && !pte->isWriteTracked() && i_op == VmmManager::EVICT) { - //Leave as 'printk' to note page was skipped - printk("Block::removePages >> Unable to EVICT "); - printk("dirty page thats not write tracked: "); - printk("va: 0x%.16lX, pa: 0x%.16lX \n",l_vaddr, pageAddr); + //Skip page } else if (i_op != VmmManager::FLUSH) { @@ -584,6 +543,7 @@ int Block::removePages(VmmManager::PAGE_REMOVAL_OPS i_op, void* i_vaddr, void Block::releasePTE(ShadowPTE* i_pte) { + i_pte->setDirty(false); i_pte->setPresent(false); i_pte->setPageAddr(NULL); } diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C index 82e743ef1..ca5dca055 100644 --- a/src/kernel/pagemgr.C +++ b/src/kernel/pagemgr.C @@ -51,6 +51,11 @@ uint64_t PageManager::queryAvail() return Singleton<PageManager>::instance()._queryAvail(); } +uint64_t PageManager::availPages() +{ + return Singleton<PageManager>::instance()._availPages(); +} + PageManager::PageManager() : iv_pagesAvail(0), iv_pagesTotal(0) { // Determine first page of un-allocated memory diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 87cfba6bd..ca32657cf 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -61,7 +61,7 @@ void kernel_execute_decrementer() #endif KernelMisc::shutdown(); } - + CpuManager::executePeriodics(c); s->setNextRunnable(); } diff --git a/src/usr/testcore/kernel/vmmbasetest.H b/src/usr/testcore/kernel/vmmbasetest.H index 3e1e2fdcd..cd2f20ff1 100644 --- a/src/usr/testcore/kernel/vmmbasetest.H +++ b/src/usr/testcore/kernel/vmmbasetest.H @@ -29,13 +29,16 @@ #include <cxxtest/TestSuite.H> #include <sys/task.h> #include <kernel/console.H> +#include <kernel/pagemgr.H> #include <arch/ppc.H> #include <sys/mm.h> +#include <usr/vmmconst.h> class VmmBaseTest : public CxxTest::TestSuite { public: static volatile int rc; + static msg_q_t iv_mq; void testNullAccess() { @@ -90,21 +93,35 @@ class VmmBaseTest : public CxxTest::TestSuite void testCastOutPages() { - //uint64_t vmemaddr = (1ul * 1024 * 1024 * 1024)/2; - //uint64_t vmsize = 4ul * 1024 * 500; - //printk("Test case: cast out pages\n"); - //printk("Set up virtual block at %p\n",(void*)vmemaddr); - //size_t rc = mm_alloc_block(NULL, // need a msgq? - // (void*)vmemaddr, - // vmsize); - //if(rc) printk("RC=%ld\n",rc); - // touch something on every page - //for(uint64_t i = vmemaddr; i < (vmemaddr + vmsize); i += PAGESIZE) - //{ - // if(*((char *)i) != 'U') printk("Yiks %p is %c\n",(void*)i,*((char *)i)); - //} - - // see printk buffer for cast out pages + uint64_t l_testAddr = VMM_VADDR_RMVPAGE_TEST; + uint64_t l_testSize = VMM_SIZE_RMVPAGE_TEST; + uint64_t vaddr = l_testAddr+l_testSize; + uint64_t vsize = PageManager::availPages()*PAGESIZE; + rc = mm_alloc_block(iv_mq,reinterpret_cast<void*>(vaddr),vsize); + if (rc != 0) + { + TS_FAIL("Unable to allocate block.\n"); + } + //TODO - Mix READ_ONLY and WRITE_TRACKED pages to cast out test + rc = mm_set_permission(reinterpret_cast<void*>(vaddr),vsize, + (uint64_t)(READ_ONLY)); + if (rc != 0) + { + TS_FAIL("Failed to set block permissions to READ_ONLY.\n"); + } + task_create(msgDaemon, NULL); + //Touch each page until less than 10% free pages remain + //printk("Page Percent Avail: 0x%lX\n",PageManager::queryAvail()); + for(uint64_t i = vaddr; i < (vaddr + vsize); i += PAGESIZE) + { + if (PageManager::queryAvail() < 10) + { + printkd("Less than 10 percent pages remain\n"); + break; + } + (*(volatile uint64_t *)i); sync(); + } + nanosleep(1,0); } private: @@ -133,7 +150,26 @@ class VmmBaseTest : public CxxTest::TestSuite task_end(); } + static void msgDaemon(void* unused) + { + msg_t* message = NULL; + uint64_t ea = 0; + while (1) + { + message = msg_wait(iv_mq); + if (message) + { + ea = message->data[0]; + /*printkd("Effective Addr: 0x%lX, %s\n",ea, + message->type==MSG_MM_RP_READ?"READ":"WRITE");*/ + message->data[1] = 0; + rc = msg_respond(iv_mq, message); + } + } + } + }; volatile int VmmBaseTest::rc = 0; +msg_q_t VmmBaseTest::iv_mq = msg_q_create(); #endif |