From 8d12bd1370b89bd29d6b306f5875ec08ce5f4a74 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 6 Aug 2008 00:28:28 +0000 Subject: [PATCH] * Moved the incrementing/decrementing of vm_page::wired_count into dedicated functions. * Introduced gMappedPagesCount variable which counts the total number of physical pages that are mapped. * Added vm_page_get_stats() which fills in the memory related part of the system_info structure. Used and cached pages are computed differently, now. The "available" (== not committed) memory is no longer used for the computation as it doesn't say anything about the actually used/free pages (with swap support enabled it is even less meaningful, since we first commit swap space when possible). We do also consider the memory used by the block cache as cached pages, now. All in all these changes should fix the memory statistics reported by get_system_info(), IOW bug #2574. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26837 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/vm_page.h | 2 ++ src/system/kernel/system_info.cpp | 5 +-- src/system/kernel/vm/vm.cpp | 57 +++++++++++++++++++++++-------- src/system/kernel/vm/vm_page.cpp | 28 +++++++++++++++ 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/headers/private/kernel/vm_page.h b/headers/private/kernel/vm_page.h index bedd21c650..7b4a16019b 100644 --- a/headers/private/kernel/vm_page.h +++ b/headers/private/kernel/vm_page.h @@ -14,6 +14,7 @@ struct kernel_args; +extern int32 gMappedPagesCount; #ifdef __cplusplus extern "C" { @@ -34,6 +35,7 @@ void vm_page_requeue(struct vm_page *page, bool tail); size_t vm_page_num_pages(void); size_t vm_page_num_free_pages(void); size_t vm_page_num_available_pages(void); +void vm_page_get_stats(system_info *info); status_t vm_page_write_modified_page_range(struct VMCache *cache, uint32 firstPage, uint32 endPage); diff --git a/src/system/kernel/system_info.cpp b/src/system/kernel/system_info.cpp index b5d566b499..2470bc82f2 100644 --- a/src/system/kernel/system_info.cpp +++ b/src/system/kernel/system_info.cpp @@ -77,11 +77,8 @@ _get_system_info(system_info *info, size_t size) for (int32 i = 0; i < info->cpu_count; i++) info->cpu_infos[i].active_time = cpu_get_active_time(i); + vm_page_get_stats(info); // TODO: Add page_faults - info->max_pages = vm_page_num_pages(); - info->used_pages = info->max_pages - vm_page_num_available_pages(); - info->cached_pages = info->max_pages - vm_page_num_free_pages() - - info->used_pages; info->used_threads = thread_used_threads(); info->max_threads = thread_max_threads(); diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index d71fdf8fd8..5a5db48c1a 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -1329,6 +1329,32 @@ cut_area(vm_address_space* addressSpace, vm_area* area, addr_t address, } +static inline void +increment_page_wired_count(vm_page* page) +{ + // TODO: needs to be atomic on all platforms! + // ... but at least the check isn't. Consequently we should hold + // sMappingLock, which would allows us to even avoid atomic_add() on + // gMappedPagesCount. + if (page->wired_count++ == 0) { + if (page->mappings.IsEmpty()) + atomic_add(&gMappedPagesCount, 1); + } +} + + +static inline void +decrement_page_wired_count(vm_page* page) +{ + if (--page->wired_count == 0) { + // TODO: needs to be atomic on all platforms! + // See above! + if (page->mappings.IsEmpty()) + atomic_add(&gMappedPagesCount, -1); + } +} + + /*! Deletes all areas in the given address range. The address space must be write-locked. */ @@ -1802,8 +1828,7 @@ vm_create_anonymous_area(team_id team, const char *name, void **address, physicalAddress); } - page->wired_count++; - // TODO: needs to be atomic on all platforms! + increment_page_wired_count(page); vm_page_set_state(page, PAGE_STATE_WIRED); cache->InsertPage(page, offset); } @@ -1835,8 +1860,7 @@ vm_create_anonymous_area(team_id team, const char *name, void **address, if (status < B_OK) panic("couldn't map physical page in page run\n"); - page->wired_count++; - // TODO: needs to be atomic on all platforms! + increment_page_wired_count(page); vm_page_set_state(page, PAGE_STATE_WIRED); cache->InsertPage(page, offset); } @@ -2740,6 +2764,9 @@ vm_remove_all_page_mappings(vm_page *page, uint32 *_flags) accumulatedFlags |= flags; } + if (page->wired_count == 0) + atomic_add(&gMappedPagesCount, -1); + locker.Unlock(); // free now unused mappings @@ -2778,8 +2805,7 @@ vm_unmap_pages(vm_area *area, addr_t base, size_t size, bool preserveModified) physicalAddress); } - page->wired_count--; - // TODO: needs to be atomic on all platforms! + decrement_page_wired_count(page); } } @@ -2828,9 +2854,12 @@ vm_unmap_pages(vm_area *area, addr_t base, size_t size, bool preserveModified) || page->cache_offset >= endOffset) continue; - mapping->page->mappings.Remove(mapping); + page->mappings.Remove(mapping); iterator.Remove(); + if (page->mappings.IsEmpty() && page->wired_count == 0) + atomic_add(&gMappedPagesCount, -1); + queue.Add(mapping); } @@ -2868,12 +2897,14 @@ vm_map_page(vm_area *area, vm_page *page, addr_t address, uint32 protection) map->ops->unlock(map); if (area->wiring != B_NO_LOCK) { - page->wired_count++; - // TODO: needs to be atomic on all platforms! + increment_page_wired_count(page); } else { // insert mapping into lists MutexLocker locker(sMappingLock); + if (page->mappings.IsEmpty() && page->wired_count == 0) + atomic_add(&gMappedPagesCount, 1); + page->mappings.Add(mapping); area->mappings.Add(mapping); } @@ -5063,8 +5094,7 @@ lock_memory_etc(team_id team, void *address, size_t numBytes, uint32 flags) if (page == NULL) panic("couldn't lookup physical page just allocated\n"); - page->wired_count++; - // TODO: needs to be atomic on all platforms! + increment_page_wired_count(page); continue; } } @@ -5098,7 +5128,7 @@ lock_memory_etc(team_id team, void *address, size_t numBytes, uint32 flags) if (page == NULL) panic("couldn't lookup physical page"); - page->wired_count++; + increment_page_wired_count(page); // TODO: needs to be atomic on all platforms! } @@ -5163,8 +5193,7 @@ unlock_memory_etc(team_id team, void *address, size_t numBytes, uint32 flags) if (page == NULL) panic("couldn't lookup physical page"); - page->wired_count--; - // TODO: needs to be atomic on all platforms! + decrement_page_wired_count(page); } out: diff --git a/src/system/kernel/vm/vm_page.cpp b/src/system/kernel/vm/vm_page.cpp index b456003327..06a320533a 100644 --- a/src/system/kernel/vm/vm_page.cpp +++ b/src/system/kernel/vm/vm_page.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,8 @@ typedef struct page_queue { uint32 count; } page_queue; +int32 gMappedPagesCount; + static page_queue sFreePageQueue; static page_queue sClearPageQueue; static page_queue sModifiedPageQueue; @@ -1916,3 +1919,28 @@ vm_page_num_free_pages(void) return count - reservedPages; } + +void +vm_page_get_stats(system_info *info) +{ + // Get free pages count -- not really exact, since we don't know how many + // of the reserved pages have already been allocated, but good citizens + // unreserve chunk-wise as they are allocating the pages, if they have + // reserved a larger quantity. + page_num_t reserved = sReservedPages; + page_num_t free = free_page_queue_count(); + free = free > reserved ? free - reserved : 0; + + // The pages used for the block cache buffers. Those should not be counted + // as used but as cached pages. + // TODO: We should subtract the blocks that are in use ATM, since those + // can't really be freed in a low memory situation. + page_num_t blockCachePages = block_cache_used_memory() / B_PAGE_SIZE; + + info->max_pages = sNumPages; + info->used_pages = gMappedPagesCount - blockCachePages; + info->cached_pages = sNumPages >= free + info->used_pages + ? sNumPages - free - info->used_pages : 0; + + // TODO: We don't consider pages used for page directories/tables yet. +}