From 37aa114310280abc7dd5f2267cfcd8e87f0911ec Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Fri, 19 Feb 2010 00:46:35 +0000 Subject: [PATCH] [NTOS]: Instead of having an LRU linked list of working set pages, we instead have a bitmap. Advantage: Pages are only in a linked list when they are NOT active (free/zeroed, for now). This makes the LIST_ENTRY fields usable when a page is active, so we can store data in there. This will make it easier to sync our PFN format with Windows. Advantage: It's a lot faster to set/clear bits than to do list operations (both still O1 though). Scanning for the bit is a bit slower than parsing a list, on the other hand, so it's a toss. Disadvantage: We lose LRU, which in theory makes us cannibalize working sets randomly instead of by-usage. However, considering the speed of ReactOS paging, and the effects of canabalizing the WS in the first place, I doubt this is really a problem. The main point of this is advantage #1 -- making used pages not be on any lists. This will allow us to almost 100% sync the PFN layouts, which will lead to the eventual negation of any temporary disavantages. svn path=/trunk/; revision=45616 --- reactos/ntoskrnl/mm/balance.c | 5 -- reactos/ntoskrnl/mm/freelist.c | 95 +++++++++++++++++++--------------- reactos/ntoskrnl/mm/mminit.c | 3 ++ 3 files changed, 55 insertions(+), 48 deletions(-) diff --git a/reactos/ntoskrnl/mm/balance.c b/reactos/ntoskrnl/mm/balance.c index eae79ccf8ab..9c30ae425e8 100644 --- a/reactos/ntoskrnl/mm/balance.c +++ b/reactos/ntoskrnl/mm/balance.c @@ -188,11 +188,6 @@ MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages) Target--; (*NrFreedPages)++; } - else if (Status == STATUS_PAGEFILE_QUOTA) - { - MmRemoveLRUUserPage(CurrentPage); - MmInsertLRULastUserPage(CurrentPage); - } CurrentPage = NextPage; } diff --git a/reactos/ntoskrnl/mm/freelist.c b/reactos/ntoskrnl/mm/freelist.c index c13b8b21693..63f47408313 100644 --- a/reactos/ntoskrnl/mm/freelist.c +++ b/reactos/ntoskrnl/mm/freelist.c @@ -74,71 +74,81 @@ static ULONG UnzeroedPageCount = 0; /* FUNCTIONS *************************************************************/ +static RTL_BITMAP MiUserPfnBitMap; + +/* FUNCTIONS *************************************************************/ + +VOID +NTAPI +MiInitializeUserPfnBitmap(VOID) +{ + PVOID Bitmap; + + /* Allocate enough buffer for the PFN bitmap and align it on 32-bits */ + Bitmap = ExAllocatePoolWithTag(NonPagedPool, + (((MmHighestPhysicalPage + 1) + 31) / 32) * 4, + ' mM'); + ASSERT(Bitmap); + + /* Initialize it and clear all the bits to begin with */ + RtlInitializeBitMap(&MiUserPfnBitMap, + Bitmap, + MmHighestPhysicalPage + 1); + RtlClearAllBits(&MiUserPfnBitMap); +} + PFN_TYPE NTAPI MmGetLRUFirstUserPage(VOID) { - PLIST_ENTRY NextListEntry; - PHYSICAL_PAGE* PageDescriptor; - KIRQL oldIrql; - - oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); - NextListEntry = UserPageListHead.Flink; - if (NextListEntry == &UserPageListHead) - { - KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql); - return 0; - } - PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry); - KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql); - return PageDescriptor - MmPfnDatabase[0]; + ULONG Position; + KIRQL OldIrql; + + /* Find the first user page */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + Position = RtlFindSetBits(&MiUserPfnBitMap, 1, 0); + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + if (Position == 0xFFFFFFFF) return 0; + + /* Return it */ + return Position; } VOID NTAPI MmInsertLRULastUserPage(PFN_TYPE Pfn) { - KIRQL oldIrql; - PPHYSICAL_PAGE Page; + KIRQL OldIrql; - oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); - Page = MiGetPfnEntry(Pfn); -// if (!Page->Consumer != MC_USER) DPRINT1("Page Consumer: %d\n", Page->Consumer); - ASSERT(Page->Consumer == MC_USER); - ASSERT(Page->u3.e1.PageLocation = ActiveAndValid); - InsertTailList(&UserPageListHead, &Page->ListEntry); - KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql); + /* Set the page as a user page */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + RtlSetBit(&MiUserPfnBitMap, Pfn); + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); } PFN_TYPE NTAPI MmGetLRUNextUserPage(PFN_TYPE PreviousPfn) { - PLIST_ENTRY NextListEntry; - PHYSICAL_PAGE* PageDescriptor; - KIRQL oldIrql; - PPHYSICAL_PAGE Page; - - oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); - Page = MiGetPfnEntry(PreviousPfn); - ASSERT(Page->Consumer == MC_USER); - ASSERT(Page->u3.e1.PageLocation = ActiveAndValid); - NextListEntry = (PLIST_ENTRY)Page->ListEntry.Flink; - if (NextListEntry == &UserPageListHead) - { - KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql); - return 0; - } - PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry); - KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql); - return PageDescriptor - MmPfnDatabase[0]; + ULONG Position; + KIRQL OldIrql; + + /* Find the next user page */ + OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + Position = RtlFindSetBits(&MiUserPfnBitMap, 1, PreviousPfn + 1); + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + if (Position == 0xFFFFFFFF) return 0; + + /* Return it */ + return Position; } VOID NTAPI MmRemoveLRUUserPage(PFN_TYPE Page) { - RemoveEntryList(&MiGetPfnEntry(Page)->ListEntry); + /* Unset the page as a user page */ + RtlClearBit(&MiUserPfnBitMap, Page); } BOOLEAN @@ -907,7 +917,6 @@ MmDereferencePage(PFN_TYPE Pfn) if (Page->u3.e2.ReferenceCount == 0) { MmAvailablePages++; - if (Page->Consumer == MC_USER) RemoveEntryList(&Page->ListEntry); Page->u3.e1.PageLocation = FreePageList; InsertTailList(&FreeUnzeroedPageListHead, &Page->ListEntry); diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index dd0dd6ddb13..cdaec0aa11b 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -349,6 +349,8 @@ MiDbgDumpMemoryDescriptors(VOID) DPRINT1("Total: %08lX (%d MB)\n", TotalPages, (TotalPages * PAGE_SIZE) / 1024 / 1024); } +VOID NTAPI MiInitializeUserPfnBitmap(VOID); + BOOLEAN NTAPI MmInitSystem(IN ULONG Phase, @@ -397,6 +399,7 @@ MmInitSystem(IN ULONG Phase, MmInitializePagedPool(); /* Initialize working sets */ + MiInitializeUserPfnBitmap(); MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory); /* Initialize the user mode image list */