- Implemented Harmutt Birr's suggestion of a seperate thread

to do balancing.
- Move pages that can't be paged out because the pagefile is
full to the end of the LRU list so we don't waste time checking
them again.

svn path=/trunk/; revision=5092
This commit is contained in:
David Welch 2003-07-12 01:52:10 +00:00
parent e41f7f3329
commit 4ae404aaa8
6 changed files with 97 additions and 51 deletions

View file

@ -632,5 +632,13 @@ BOOLEAN
MmIsAvailableSwapPage(VOID);
VOID
MmShowOutOfSpaceMessagePagingFile(VOID);
VOID
MmRebalanceMemoryConsumers(VOID);
BOOLEAN
MiIsPagerThread(VOID);
VOID
MiStartPagerThread(VOID);
VOID
MmSetLRULastPage(PHYSICAL_ADDRESS PhysicalAddress);
#endif

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: anonmem.c,v 1.17 2003/07/11 01:23:15 royce Exp $
/* $Id: anonmem.c,v 1.18 2003/07/12 01:52:10 dwelch Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/anonmem.c
@ -193,7 +193,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
PageOp->Status = STATUS_UNSUCCESSFUL;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp);
return(STATUS_UNSUCCESSFUL);
return(STATUS_PAGEFILE_QUOTA);
}
}

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: balance.c,v 1.17 2003/07/10 21:05:03 royce Exp $
/* $Id: balance.c,v 1.18 2003/07/12 01:52:10 dwelch Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/balance.c
@ -59,8 +59,6 @@ static ULONG MiNrAvailablePages;
static ULONG MiNrTotalPages;
static LIST_ENTRY AllocationListHead;
static KSPIN_LOCK AllocationListLock;
static ULONG NrWorkingThreads = 0;
static HANDLE WorkerThreadId;
static ULONG MiPagesRequired = 0;
static ULONG MiMinimumPagesPerRun = 10;
@ -161,7 +159,7 @@ MiTrimMemoryConsumer(ULONG Consumer)
}
VOID
MiRebalanceMemoryConsumers(VOID)
MmRebalanceMemoryConsumers(VOID)
{
LONG Target;
ULONG i;
@ -203,7 +201,7 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
*/
OldUsed = InterlockedIncrement((LONG *)&MiMemoryConsumers[Consumer].PagesUsed);
if (OldUsed >= (MiMemoryConsumers[Consumer].PagesTarget - 1) &&
WorkerThreadId != PsGetCurrentThreadId())
!MiIsPagerThread())
{
if (!CanWait)
{
@ -234,41 +232,30 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
InterlockedIncrement((LONG *)&MiPagesRequired);
KeAcquireSpinLock(&AllocationListLock, &oldIrql);
if (NrWorkingThreads == 0)
/* Always let the pager thread itself allocate memory. */
if (MiIsPagerThread())
{
InsertTailList(&AllocationListHead, &Request.ListEntry);
NrWorkingThreads++;
Page = MmAllocPage(Consumer, 0);
KeReleaseSpinLock(&AllocationListLock, oldIrql);
WorkerThreadId = PsGetCurrentThreadId();
MiRebalanceMemoryConsumers();
KeAcquireSpinLock(&AllocationListLock, &oldIrql);
NrWorkingThreads--;
WorkerThreadId = 0;
KeReleaseSpinLock(&AllocationListLock, oldIrql);
}
else
{
if (WorkerThreadId == PsGetCurrentThreadId())
if (Page.QuadPart == 0LL)
{
Page = MmAllocPage(Consumer, 0);
KeReleaseSpinLock(&AllocationListLock, oldIrql);
if (Page.QuadPart == 0LL)
{
KeBugCheck(0);
}
*AllocatedPage = Page;
InterlockedDecrement((LONG *)&MiPagesRequired);
return(STATUS_SUCCESS);
KeBugCheck(0);
}
InsertTailList(&AllocationListHead, &Request.ListEntry);
KeReleaseSpinLock(&AllocationListLock, oldIrql);
*AllocatedPage = Page;
InterlockedDecrement((LONG *)&MiPagesRequired);
return(STATUS_SUCCESS);
}
/* Otherwise start the pager thread if it isn't already working. */
MiStartPagerThread();
InsertTailList(&AllocationListHead, &Request.ListEntry);
KeReleaseSpinLock(&AllocationListLock, oldIrql);
KeWaitForSingleObject(&Request.Event,
0,
KernelMode,
FALSE,
NULL);
Page = Request.Page;
if (Page.QuadPart == 0LL)
{
@ -279,7 +266,7 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
InterlockedDecrement((LONG *)&MiPagesRequired);
return(STATUS_SUCCESS);
}
/*
* Actually allocate the page.
*/

View file

@ -70,6 +70,11 @@ MmTransferOwnershipPage(PHYSICAL_ADDRESS PhysicalAddress, ULONG NewConsumer)
KIRQL oldIrql;
KeAcquireSpinLock(&PageListLock, &oldIrql);
if (MmPageArray[Start].MapCount != 0)
{
DbgPrint("Transfering mapped page.\n");
KeBugCheck(0);
}
RemoveEntryList(&MmPageArray[Start].ListEntry);
InsertTailList(&UsedPageListHeads[NewConsumer],
&MmPageArray[Start].ListEntry);
@ -100,6 +105,23 @@ MmGetLRUFirstUserPage(VOID)
return(Next);
}
VOID
MmSetLRULastPage(PHYSICAL_ADDRESS PhysicalAddress)
{
ULONG Start = PhysicalAddress.u.LowPart / PAGE_SIZE;
KIRQL oldIrql;
KeAcquireSpinLock(&PageListLock, &oldIrql);
if (MmPageArray[Start].Flags.Type == MM_PHYSICAL_PAGE_USED &&
MmPageArray[Start].Flags.Consumer == MC_USER)
{
RemoveEntryList(&MmPageArray[Start].ListEntry);
InsertTailList(&UsedPageListHeads[MC_USER],
&MmPageArray[Start].ListEntry);
}
KeReleaseSpinLock(&PageListLock, oldIrql);
}
PHYSICAL_ADDRESS
MmGetLRUNextUserPage(PHYSICAL_ADDRESS PreviousPhysicalAddress)
{

View file

@ -1,4 +1,4 @@
/* $Id: pager.c,v 1.11 2002/09/08 10:23:36 chorns Exp $
/* $Id: pager.c,v 1.12 2003/07/12 01:52:10 dwelch Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -25,31 +25,55 @@ static HANDLE PagerThreadHandle;
static CLIENT_ID PagerThreadId;
static KEVENT PagerThreadEvent;
static BOOLEAN PagerThreadShouldTerminate;
static ULONG PagerThreadWorking;
/* FUNCTIONS *****************************************************************/
BOOLEAN
MiIsPagerThread(VOID)
{
return(PsGetCurrentThreadId() == PagerThreadId.UniqueThread);
}
VOID
MiStartPagerThread(VOID)
{
ULONG WasWorking;
WasWorking = InterlockedExchange(&PagerThreadWorking, 1);
if (WasWorking == 0)
{
KeSetEvent(&PagerThreadEvent, IO_NO_INCREMENT, FALSE);
}
}
static NTSTATUS STDCALL
MmPagerThreadMain(PVOID Ignored)
{
NTSTATUS Status;
for(;;)
{
Status = KeWaitForSingleObject(&PagerThreadEvent,
0,
KernelMode,
FALSE,
NULL);
if (!NT_SUCCESS(Status))
{
DbgPrint("PagerThread: Wait failed\n");
KeBugCheck(0);
}
if (PagerThreadShouldTerminate)
{
DbgPrint("PagerThread: Terminating\n");
return(STATUS_SUCCESS);
}
/* Wake for a low memory situation or a terminate request. */
Status = KeWaitForSingleObject(&PagerThreadEvent,
0,
KernelMode,
FALSE,
NULL);
if (!NT_SUCCESS(Status))
{
DbgPrint("PagerThread: Wait failed\n");
KeBugCheck(0);
}
if (PagerThreadShouldTerminate)
{
DbgPrint("PagerThread: Terminating\n");
return(STATUS_SUCCESS);
}
/* Try and make some memory available to the system. */
MmRebalanceMemoryConsumers();
/* Let the rest of the system know we finished this run. */
(VOID)InterlockedExchange(&PagerThreadWorking, 0);
}
}
@ -58,6 +82,7 @@ NTSTATUS MmInitPagerThread(VOID)
NTSTATUS Status;
PagerThreadShouldTerminate = FALSE;
PagerThreadWorking = 0;
KeInitializeEvent(&PagerThreadEvent,
SynchronizationEvent,
FALSE);

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: wset.c,v 1.16 2002/09/08 10:23:37 chorns Exp $
/* $Id: wset.c,v 1.17 2003/07/12 01:52:10 dwelch Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/wset.c
@ -59,6 +59,10 @@ MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
Target--;
(*NrFreedPages)++;
}
else if (Status == STATUS_PAGEFILE_QUOTA)
{
MmSetLRULastPage(CurrentPhysicalAddress);
}
CurrentPhysicalAddress = NextPhysicalAddress;
}