From be1cc9c8909d172e8339e955d8d31b7725094cf7 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Sat, 20 Jun 2020 17:07:03 -0400 Subject: [PATCH] kernel/vm: Make the page_scrubber wait on a condition. On an idle system with 1GB RAM and the 100ms timeout, it takes multiple minutes for all the pages in the system to get cleared after boot, but once they do, the page scrubber will then remain idle for seconds to even minutes at a time, so this is clearly worth it. The "free pages condition" was unused before this commit, so I have repurposed it (and unpublished it.) Change-Id: I7034677a1e51c97c2baf11b772db3a31c0e1adfa Reviewed-on: https://review.haiku-os.org/c/haiku/+/1699 Reviewed-by: waddlesplash --- src/system/kernel/vm/vm_page.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/system/kernel/vm/vm_page.cpp b/src/system/kernel/vm/vm_page.cpp index 45feb38028..2b52b4ac6a 100644 --- a/src/system/kernel/vm/vm_page.cpp +++ b/src/system/kernel/vm/vm_page.cpp @@ -63,7 +63,7 @@ #define PAGE_ASSERT(page, condition) \ ASSERT_PRINT((condition), "page: %p", (page)) -#define SCRUB_SIZE 16 +#define SCRUB_SIZE 32 // this many pages will be cleared at once in the page scrubber thread #define MAX_PAGE_WRITER_IO_PRIORITY B_URGENT_DISPLAY_PRIORITY @@ -1521,6 +1521,7 @@ free_page(vm_page* page, bool clear) } else { page->SetState(PAGE_STATE_FREE); sFreePageQueue.PrependUnlocked(page); + sFreePageCondition.NotifyAll(); } locker.Unlock(); @@ -1726,7 +1727,7 @@ mark_page_range_in_use(page_num_t startPage, page_num_t length, bool wired) /*! - This is a background thread that wakes up every now and then (every 100ms) + This is a background thread that wakes up when its condition is notified and moves some pages from the free queue over to the clear queue. Given enough time, it will clear out all pages from the free queue - we could probably slow it down after having reached a certain threshold. @@ -1738,13 +1739,13 @@ page_scrubber(void *unused) TRACE(("page_scrubber starting...\n")); + ConditionVariableEntry entry; for (;;) { - snooze(100000); // 100ms - - if (sFreePageQueue.Count() == 0 + while (sFreePageQueue.Count() == 0 || atomic_get(&sUnreservedFreePages) < (int32)sFreePagesTarget) { - continue; + sFreePageCondition.Add(&entry); + entry.Wait(); } // Since we temporarily remove pages from the free pages reserve, @@ -1802,6 +1803,9 @@ page_scrubber(void *unused) unreserve_pages(reserved); TA(ScrubbedPages(scrubCount)); + + // wait at least 100ms between runs + snooze(100 * 1000); } return 0; @@ -2584,6 +2588,8 @@ free_cached_pages(uint32 pagesToFree, bool dontWait) remove_page_marker(marker); + sFreePageCondition.NotifyAll(); + return pagesFreed; } @@ -3401,7 +3407,6 @@ status_t vm_page_init_post_thread(kernel_args *args) { new (&sFreePageCondition) ConditionVariable; - sFreePageCondition.Publish(&sFreePageQueue, "free page"); // create a kernel thread to clear out pages @@ -3603,6 +3608,8 @@ allocate_page_run_cleanup(VMPageQueue::PageList& freePages, DEBUG_PAGE_ACCESS_END(page); sClearPageQueue.PrependUnlocked(page); } + + sFreePageCondition.NotifyAll(); }