[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
This commit is contained in:
Sir Richard 2010-02-19 00:46:35 +00:00
parent 1337cbf945
commit 37aa114310
3 changed files with 55 additions and 48 deletions

View file

@ -188,11 +188,6 @@ MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
Target--; Target--;
(*NrFreedPages)++; (*NrFreedPages)++;
} }
else if (Status == STATUS_PAGEFILE_QUOTA)
{
MmRemoveLRUUserPage(CurrentPage);
MmInsertLRULastUserPage(CurrentPage);
}
CurrentPage = NextPage; CurrentPage = NextPage;
} }

View file

@ -74,71 +74,81 @@ static ULONG UnzeroedPageCount = 0;
/* FUNCTIONS *************************************************************/ /* 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 PFN_TYPE
NTAPI NTAPI
MmGetLRUFirstUserPage(VOID) MmGetLRUFirstUserPage(VOID)
{ {
PLIST_ENTRY NextListEntry; ULONG Position;
PHYSICAL_PAGE* PageDescriptor; KIRQL OldIrql;
KIRQL oldIrql;
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); /* Find the first user page */
NextListEntry = UserPageListHead.Flink; OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
if (NextListEntry == &UserPageListHead) Position = RtlFindSetBits(&MiUserPfnBitMap, 1, 0);
{ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql); if (Position == 0xFFFFFFFF) return 0;
return 0;
} /* Return it */
PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry); return Position;
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
return PageDescriptor - MmPfnDatabase[0];
} }
VOID VOID
NTAPI NTAPI
MmInsertLRULastUserPage(PFN_TYPE Pfn) MmInsertLRULastUserPage(PFN_TYPE Pfn)
{ {
KIRQL oldIrql; KIRQL OldIrql;
PPHYSICAL_PAGE Page;
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); /* Set the page as a user page */
Page = MiGetPfnEntry(Pfn); OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
// if (!Page->Consumer != MC_USER) DPRINT1("Page Consumer: %d\n", Page->Consumer); RtlSetBit(&MiUserPfnBitMap, Pfn);
ASSERT(Page->Consumer == MC_USER); KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
ASSERT(Page->u3.e1.PageLocation = ActiveAndValid);
InsertTailList(&UserPageListHead, &Page->ListEntry);
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
} }
PFN_TYPE PFN_TYPE
NTAPI NTAPI
MmGetLRUNextUserPage(PFN_TYPE PreviousPfn) MmGetLRUNextUserPage(PFN_TYPE PreviousPfn)
{ {
PLIST_ENTRY NextListEntry; ULONG Position;
PHYSICAL_PAGE* PageDescriptor; KIRQL OldIrql;
KIRQL oldIrql;
PPHYSICAL_PAGE Page;
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); /* Find the next user page */
Page = MiGetPfnEntry(PreviousPfn); OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
ASSERT(Page->Consumer == MC_USER); Position = RtlFindSetBits(&MiUserPfnBitMap, 1, PreviousPfn + 1);
ASSERT(Page->u3.e1.PageLocation = ActiveAndValid); KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
NextListEntry = (PLIST_ENTRY)Page->ListEntry.Flink; if (Position == 0xFFFFFFFF) return 0;
if (NextListEntry == &UserPageListHead)
{ /* Return it */
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql); return Position;
return 0;
}
PageDescriptor = CONTAINING_RECORD(NextListEntry, PHYSICAL_PAGE, ListEntry);
KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql);
return PageDescriptor - MmPfnDatabase[0];
} }
VOID VOID
NTAPI NTAPI
MmRemoveLRUUserPage(PFN_TYPE Page) MmRemoveLRUUserPage(PFN_TYPE Page)
{ {
RemoveEntryList(&MiGetPfnEntry(Page)->ListEntry); /* Unset the page as a user page */
RtlClearBit(&MiUserPfnBitMap, Page);
} }
BOOLEAN BOOLEAN
@ -907,7 +917,6 @@ MmDereferencePage(PFN_TYPE Pfn)
if (Page->u3.e2.ReferenceCount == 0) if (Page->u3.e2.ReferenceCount == 0)
{ {
MmAvailablePages++; MmAvailablePages++;
if (Page->Consumer == MC_USER) RemoveEntryList(&Page->ListEntry);
Page->u3.e1.PageLocation = FreePageList; Page->u3.e1.PageLocation = FreePageList;
InsertTailList(&FreeUnzeroedPageListHead, InsertTailList(&FreeUnzeroedPageListHead,
&Page->ListEntry); &Page->ListEntry);

View file

@ -349,6 +349,8 @@ MiDbgDumpMemoryDescriptors(VOID)
DPRINT1("Total: %08lX (%d MB)\n", TotalPages, (TotalPages * PAGE_SIZE) / 1024 / 1024); DPRINT1("Total: %08lX (%d MB)\n", TotalPages, (TotalPages * PAGE_SIZE) / 1024 / 1024);
} }
VOID NTAPI MiInitializeUserPfnBitmap(VOID);
BOOLEAN BOOLEAN
NTAPI NTAPI
MmInitSystem(IN ULONG Phase, MmInitSystem(IN ULONG Phase,
@ -397,6 +399,7 @@ MmInitSystem(IN ULONG Phase,
MmInitializePagedPool(); MmInitializePagedPool();
/* Initialize working sets */ /* Initialize working sets */
MiInitializeUserPfnBitmap();
MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory); MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
/* Initialize the user mode image list */ /* Initialize the user mode image list */