VMLaundryImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Levin on December 16, 1983 1:38 pm
Bob Hagmann on January 30, 1985 11:05:32 am PST
Russ Atkinson on January 30, 1985 10:22:11 pm PST
DIRECTORY
Process USING [Detach, MsecToTicks, priorityFaultHandlers, SetPriority, Ticks, Yield],
VM USING [AddressFault, CantDoIO, Clean, Interval, IOErrorType, LaundryError, PageCount, PageNumber, PageNumberForAddress, Pin],
VMInternal USING [freePages, LaundryMode, GetCleaningCandidate, HasBackingStorage, PageCount, RealPageNumber, swapBufferSize],
VMSideDoor USING [rmPages],
VMStatistics USING [rmNewClean, rmOldClean];
VMLaundryImpl: MONITOR
IMPORTS Process, VM, VMInternal, VMSideDoor, VMStatistics
EXPORTS VM, VMInternal, VMStatistics
= BEGIN OPEN VMInternal;
Performance parameters
normalHighMark: NAT = MIN[VMSideDoor.rmPages/10, 150];
bigHighMark: NATMIN[VMSideDoor.rmPages/5, 400];
lowMark: NAT = normalHighMark/3;
highMark: NAT ← bigHighMark;
samplingInterval: Process.Ticks = Process.MsecToTicks[250];
Global variables protected by the monitor lock
dirtyVictims: BOOL;
newVictims: BOOL;
laundry: CONDITION ← [timeout: samplingInterval];
LastLaundryErrorRecord: VM.LaundryError ← [software, 0];
errorsNoted: INT ← 0;
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;
};
NoteNewVictim: PUBLIC ENTRY PROC = {
newVictims ← TRUE;
NOTIFY laundry;
};
Exports to VM
ForceCleaning: PUBLIC ENTRY SAFE PROC = CHECKED {
newVictims ← 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 ← uselessLaundryWakeups ;
oldRMNewClean: INT ← VMStatistics.rmNewClean;
wake up with attitude aggressive to try to force some cleaning to avoid a frame fault with no unpinned clean memory
attitude: LaundryMode ← aggressive ;
prevAttitude: LaundryMode ← casual ;
prevMin: PageCount ← 1 ;
Wait: ENTRY PROC RETURNS [LaundryMode] = {
WaitReturn: PROC [mode: LaundryMode] RETURNS [LaundryMode]= {
dirtyVictims ← FALSE;
newVictims ← FALSE ;
oldRMNewClean ← VMStatistics.rmNewClean;
RETURN[mode];
};
IF dirtyVictims THEN RETURN[WaitReturn[panic]];
IF oldRMNewClean # VMStatistics.rmNewClean OR newVictims THEN RETURN[WaitReturn[aggressive]];
dirtyVictims ← FALSE;
DO
WAIT laundry;
IF HasBackingStorage[0] THEN EXIT;
ENDLOOP;
IF dirtyVictims THEN RETURN[WaitReturn[panic]];
IF oldRMNewClean # VMStatistics.rmNewClean OR newVictims THEN RETURN[WaitReturn[aggressive]];
RETURN[casual];
};
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
cleanUsed: INT = VMStatistics.rmOldClean + VMStatistics.rmNewClean ;
cleanedThisTime: INT ← 0;
totalCleanSkipped: PageCount ;
startPasses: INT ← -1 ;
startRover: RealPageNumber ← 0;
minCleaning: PageCount ← 1;
knownFreeOrClean: INT ← lowMark; -- best start guess
--*stats*--
laundryWakeups ← laundryWakeups.SUCC;
IF attitude = panic THEN panicLaundryWakeups ← panicLaundryWakeups.SUCC;
totalCleanSkipped ← 0 ;
IF attitude # casual THEN {
highMark 𡤋igHighMark ;
minCleaning ← IF prevAttitude = casual THEN 10
ELSE IF prevMin = 10 THEN 4 ELSE 1 ;
};
IF attitude # casual OR (cleanUsed - prevCleanUsed) >= (highMark - lowMark) THEN {
UNTIL cleanedThisTime >= highMark DO
interval: VM.Interval;
cleanSkipped: PageCount ;
passes: INT ;
rover: RealPageNumber ;
[interval: interval, cleanSkipped: cleanSkipped, passes: passes, rover: rover] ← GetCleaningCandidate[
desired: swapBufferSize, -- larger run than this means multiple transfers in Clean
comfortLevel: lowMark + cleanedThisTime,
tryHard: attitude
];
IF startPasses < 0 THEN { startPasses ← passes; startRover ← rover;};
totalCleanSkipped ← totalCleanSkipped + cleanSkipped ;
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;
IF interval.count >= minCleaning THEN {
VM.Clean[interval
! VM.AddressFault => {
interval.count ← VM.PageNumberForAddress[address] - interval.page;
CONTINUE
};
VM.CantDoIO => {
error writing a page; shrink interval to written pages and pin bad page
interval.count ← page - interval.page;
VM.Pin[ [page,1] ];
ReportError[reason, page];
CONTINUE
};
];
cleanedThisTime ← cleanedThisTime + interval.count;
*stats*--
laundryCleanCalls ← laundryCleanCalls.SUCC;
};
knownFreeOrClean ← freePages + cleanedThisTime + totalCleanSkipped - (VMStatistics.rmOldClean + VMStatistics.rmNewClean - cleanUsed) ;
Stop loop if we are not in panic, and there appears to be enough clean pages or we have done a pass through memory in this loop (note that memory is scanned in decreasing order)
IF ((attitude = casual) AND (knownFreeOrClean >= highMark)) THEN EXIT;
IF (passes > startPasses + 1) OR (passes > startPasses AND rover <= startRover) THEN EXIT;
Give up the processor to avoid hogging priority 5
Process.Yield[];
ENDLOOP;
prevCleanUsed ← VMStatistics.rmOldClean + VMStatistics.rmNewClean;
};
*stats*--
IF cleanedThisTime = 0 THEN uselessLaundryWakeups ← uselessLaundryWakeups.SUCC
ELSE {
pagesCleaned ← pagesCleaned + cleanedThisTime;
IF attitude = panic THEN pagesCleanedPanic ← pagesCleanedPanic + cleanedThisTime;
};
prevAttitude ← attitude;
prevMin ← minCleaning ;
IF knownFreeOrClean < lowMark AND cleanedThisTime >= highMark
THEN attitude ← aggressive
ELSE attitude ← Wait[];
highMark ← normalHighMark ;
ENDLOOP;
};
ReportError: ENTRY PROC [ errorType: VM.IOErrorType, page: VM.PageNumber ] = {
LastLaundryErrorRecord ← [errorType,page] ;
errorsNoted ← errorsNoted + 1;
};
LastLaundryError: PUBLIC ENTRY SAFE PROC RETURNS [VM.LaundryError] = CHECKED {
RETURN[LastLaundryErrorRecord];
};
Process.Detach[FORK LaundryProcess[]];
END.
Bob Hagmann January 30, 1985 10:22:11 pm PST
eliminate VMExtras for 6.0
changes to: DIRECTORY, LastLaundryErrorRecord, VMLaundryImpl, normalHighMark, bigHighMark, lowMark, highMark, samplingInterval, dirtyVictims, newVictims, laundry, LastLaundryErrorRecord, errorsNoted, laundryWakeups, pagesCleaned, laundryCleanCalls, NoteDirtyVictim, NoteNewVictim, ForceCleaning, LaundryProcess, Wait (local of LaundryProcess), WaitReturn (local of Wait, local of LaundryProcess), ReportError, LastLaundryError, Process, END, LastLaundryErrorRecord, LastLaundryError, VMLaundryImpl