- 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); MmIsAvailableSwapPage(VOID);
VOID VOID
MmShowOutOfSpaceMessagePagingFile(VOID); MmShowOutOfSpaceMessagePagingFile(VOID);
VOID
MmRebalanceMemoryConsumers(VOID);
BOOLEAN
MiIsPagerThread(VOID);
VOID
MiStartPagerThread(VOID);
VOID
MmSetLRULastPage(PHYSICAL_ADDRESS PhysicalAddress);
#endif #endif

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/anonmem.c * FILE: ntoskrnl/mm/anonmem.c
@ -193,7 +193,7 @@ MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
PageOp->Status = STATUS_UNSUCCESSFUL; PageOp->Status = STATUS_UNSUCCESSFUL;
KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE); KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
MmReleasePageOp(PageOp); 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 * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/balance.c * FILE: ntoskrnl/mm/balance.c
@ -59,8 +59,6 @@ static ULONG MiNrAvailablePages;
static ULONG MiNrTotalPages; static ULONG MiNrTotalPages;
static LIST_ENTRY AllocationListHead; static LIST_ENTRY AllocationListHead;
static KSPIN_LOCK AllocationListLock; static KSPIN_LOCK AllocationListLock;
static ULONG NrWorkingThreads = 0;
static HANDLE WorkerThreadId;
static ULONG MiPagesRequired = 0; static ULONG MiPagesRequired = 0;
static ULONG MiMinimumPagesPerRun = 10; static ULONG MiMinimumPagesPerRun = 10;
@ -161,7 +159,7 @@ MiTrimMemoryConsumer(ULONG Consumer)
} }
VOID VOID
MiRebalanceMemoryConsumers(VOID) MmRebalanceMemoryConsumers(VOID)
{ {
LONG Target; LONG Target;
ULONG i; ULONG i;
@ -203,7 +201,7 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
*/ */
OldUsed = InterlockedIncrement((LONG *)&MiMemoryConsumers[Consumer].PagesUsed); OldUsed = InterlockedIncrement((LONG *)&MiMemoryConsumers[Consumer].PagesUsed);
if (OldUsed >= (MiMemoryConsumers[Consumer].PagesTarget - 1) && if (OldUsed >= (MiMemoryConsumers[Consumer].PagesTarget - 1) &&
WorkerThreadId != PsGetCurrentThreadId()) !MiIsPagerThread())
{ {
if (!CanWait) if (!CanWait)
{ {
@ -234,41 +232,30 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
InterlockedIncrement((LONG *)&MiPagesRequired); InterlockedIncrement((LONG *)&MiPagesRequired);
KeAcquireSpinLock(&AllocationListLock, &oldIrql); KeAcquireSpinLock(&AllocationListLock, &oldIrql);
if (NrWorkingThreads == 0) /* Always let the pager thread itself allocate memory. */
if (MiIsPagerThread())
{ {
InsertTailList(&AllocationListHead, &Request.ListEntry); Page = MmAllocPage(Consumer, 0);
NrWorkingThreads++;
KeReleaseSpinLock(&AllocationListLock, oldIrql); KeReleaseSpinLock(&AllocationListLock, oldIrql);
WorkerThreadId = PsGetCurrentThreadId(); if (Page.QuadPart == 0LL)
MiRebalanceMemoryConsumers();
KeAcquireSpinLock(&AllocationListLock, &oldIrql);
NrWorkingThreads--;
WorkerThreadId = 0;
KeReleaseSpinLock(&AllocationListLock, oldIrql);
}
else
{
if (WorkerThreadId == PsGetCurrentThreadId())
{ {
Page = MmAllocPage(Consumer, 0); KeBugCheck(0);
KeReleaseSpinLock(&AllocationListLock, oldIrql);
if (Page.QuadPart == 0LL)
{
KeBugCheck(0);
}
*AllocatedPage = Page;
InterlockedDecrement((LONG *)&MiPagesRequired);
return(STATUS_SUCCESS);
} }
InsertTailList(&AllocationListHead, &Request.ListEntry); *AllocatedPage = Page;
KeReleaseSpinLock(&AllocationListLock, oldIrql); 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, KeWaitForSingleObject(&Request.Event,
0, 0,
KernelMode, KernelMode,
FALSE, FALSE,
NULL); NULL);
Page = Request.Page; Page = Request.Page;
if (Page.QuadPart == 0LL) if (Page.QuadPart == 0LL)
{ {
@ -279,7 +266,7 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
InterlockedDecrement((LONG *)&MiPagesRequired); InterlockedDecrement((LONG *)&MiPagesRequired);
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
/* /*
* Actually allocate the page. * Actually allocate the page.
*/ */

View file

@ -70,6 +70,11 @@ MmTransferOwnershipPage(PHYSICAL_ADDRESS PhysicalAddress, ULONG NewConsumer)
KIRQL oldIrql; KIRQL oldIrql;
KeAcquireSpinLock(&PageListLock, &oldIrql); KeAcquireSpinLock(&PageListLock, &oldIrql);
if (MmPageArray[Start].MapCount != 0)
{
DbgPrint("Transfering mapped page.\n");
KeBugCheck(0);
}
RemoveEntryList(&MmPageArray[Start].ListEntry); RemoveEntryList(&MmPageArray[Start].ListEntry);
InsertTailList(&UsedPageListHeads[NewConsumer], InsertTailList(&UsedPageListHeads[NewConsumer],
&MmPageArray[Start].ListEntry); &MmPageArray[Start].ListEntry);
@ -100,6 +105,23 @@ MmGetLRUFirstUserPage(VOID)
return(Next); 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 PHYSICAL_ADDRESS
MmGetLRUNextUserPage(PHYSICAL_ADDRESS PreviousPhysicalAddress) 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 * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -25,31 +25,55 @@ static HANDLE PagerThreadHandle;
static CLIENT_ID PagerThreadId; static CLIENT_ID PagerThreadId;
static KEVENT PagerThreadEvent; static KEVENT PagerThreadEvent;
static BOOLEAN PagerThreadShouldTerminate; static BOOLEAN PagerThreadShouldTerminate;
static ULONG PagerThreadWorking;
/* FUNCTIONS *****************************************************************/ /* 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 static NTSTATUS STDCALL
MmPagerThreadMain(PVOID Ignored) MmPagerThreadMain(PVOID Ignored)
{ {
NTSTATUS Status; NTSTATUS Status;
for(;;) for(;;)
{ {
Status = KeWaitForSingleObject(&PagerThreadEvent, /* Wake for a low memory situation or a terminate request. */
0, Status = KeWaitForSingleObject(&PagerThreadEvent,
KernelMode, 0,
FALSE, KernelMode,
NULL); FALSE,
if (!NT_SUCCESS(Status)) NULL);
{ if (!NT_SUCCESS(Status))
DbgPrint("PagerThread: Wait failed\n"); {
KeBugCheck(0); DbgPrint("PagerThread: Wait failed\n");
} KeBugCheck(0);
if (PagerThreadShouldTerminate) }
{ if (PagerThreadShouldTerminate)
DbgPrint("PagerThread: Terminating\n"); {
return(STATUS_SUCCESS); 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; NTSTATUS Status;
PagerThreadShouldTerminate = FALSE; PagerThreadShouldTerminate = FALSE;
PagerThreadWorking = 0;
KeInitializeEvent(&PagerThreadEvent, KeInitializeEvent(&PagerThreadEvent,
SynchronizationEvent, SynchronizationEvent,
FALSE); FALSE);

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 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 * PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/wset.c * FILE: ntoskrnl/mm/wset.c
@ -59,6 +59,10 @@ MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
Target--; Target--;
(*NrFreedPages)++; (*NrFreedPages)++;
} }
else if (Status == STATUS_PAGEFILE_QUOTA)
{
MmSetLRULastPage(CurrentPhysicalAddress);
}
CurrentPhysicalAddress = NextPhysicalAddress; CurrentPhysicalAddress = NextPhysicalAddress;
} }