VMLaundryImpl.mesa
last edited by Levin on December 16, 1983 1:38 pm
DIRECTORY
Process USING [Detach, MsecToTicks, priorityFaultHandlers, SetPriority, Ticks],
VM USING [AddressFault, Clean, Interval, PageCount, PageNumberForAddress],
VMInternal USING [GetCleaningCandidate, HasBackingStorage, swapBufferSize],
VMSideDoor USING [rmPages],
VMStatistics USING [rmNewClean, rmOldClean];
VMLaundryImpl:
MONITOR
IMPORTS Process, VM, VMInternal, VMSideDoor, VMStatistics
EXPORTS VMInternal, VMStatistics =
BEGIN
OPEN VMInternal;
Performance parameters
highMark: NAT = MIN[VMSideDoor.rmPages/10, 200];
lowMark: NAT = highMark/4;
samplingInterval: Process.Ticks = Process.MsecToTicks[250];
Global variables protected by the monitor lock
dirtyVictims: BOOL;
laundry: CONDITION ← [timeout: samplingInterval];
Exports to VMStatistics
laundryWakeups, panicLaundryWakeups, uselessLaundryWakeups: PUBLIC INT ← 0;
pagesCleaned, pagesCleanedPanic: PUBLIC INT ← 0;
laundryCleanCalls: PUBLIC INT ← 0;
Exports to VMInternal
NoteDirtyVictim:
PUBLIC
ENTRY
PROC = {
dirtyVictims ← TRUE;
NOTIFY laundry;
};
Laundry Process
LaundryProcess:
PROC = {
The following initialization ensures that, on the first pass through the main loop, we will actually try to clean things.
prevCleanUsed:
INT ←
VMStatistics.rmOldClean + VMStatistics.rmNewClean - (highMark - lowMark);
Wait:
ENTRY
PROC
RETURNS [badlyBehind:
BOOL] = {
dirtyVictims ← FALSE;
DO
WAIT laundry;
IF HasBackingStorage[0] THEN EXIT;
ENDLOOP;
RETURN[dirtyVictims]
};
We want to run above the client foreground processes. Perhaps we should multiplex with the guys at priorityClient3? No reserved state vector is required, since this process is a vanilla client of Clean. However, it would be nice to include one anyway, since it is potentially possible for a fault in this process to prohibit anyone else from getting into SwapIn.
Process.SetPriority[Process.priorityFaultHandlers];
DO
badlyBehind: BOOL ← Wait[];
cleanUsed: INT = VMStatistics.rmOldClean + VMStatistics.rmNewClean;
cleanedThisTime: INT ← 0;
--*stats*--
laundryWakeups ← laundryWakeups.SUCC;
IF badlyBehind THEN panicLaundryWakeups ← panicLaundryWakeups.SUCC;
IF badlyBehind
OR (cleanUsed - prevCleanUsed) >= (highMark - lowMark)
THEN {
UNTIL cleanedThisTime >= highMark
DO
interval:
VM.Interval ← GetCleaningCandidate[
desired: swapBufferSize, -- larger run than this means multiple transfers in Clean
comfortLevel: lowMark + cleanedThisTime,
tryHard: badlyBehind
];
IF interval.count = 0
THEN
There is nothing to clean, either because no appropriate dirty, unpinned pages could be found or because there were sufficient clean, unreferenced pages aleady available for reclamation.
EXIT;
VM.Clean[interval
!
VM.AddressFault => {
interval.count ← VM.PageNumberForAddress[address] - interval.page;
CONTINUE
}
];
cleanedThisTime ← cleanedThisTime + interval.count;
*stats*--
laundryCleanCalls ← laundryCleanCalls.SUCC;
ENDLOOP;
prevCleanUsed ← VMStatistics.rmOldClean + VMStatistics.rmNewClean;
};
*stats*--
IF cleanedThisTime = 0 THEN uselessLaundryWakeups ← uselessLaundryWakeups.SUCC
ELSE {
pagesCleaned ← pagesCleaned + cleanedThisTime;
IF badlyBehind THEN pagesCleanedPanic ← pagesCleanedPanic + cleanedThisTime;
};
ENDLOOP;
};
Process.Detach[FORK LaundryProcess[]];
END.