-- WriteBehindTestFilePageMgrImpl.mesa Last edit: KK November 9, 1983 4:35 pm

DIRECTORY

AlpineEnvironment
USING[FileID, PageCount, PageNumber, PageRun, VolumeID, wordsPerPage],
AlpineInternal
USING[FileHandle],
CedarVersion
USING[machineType],
File
USING[Type],
FileIO
USING[Open],
FileTypes
USING[tUntypedFile],
FileMap
USING[GetVolumeID, Handle, Initialize, Register],
FilePageMgr
USING[GetAttributes, GetSize,
InitializeFilePageMgr, ForceOutFile, ReadAheadPages, ReadLeaderPages,
ReadPages, ReleaseState, ReleaseVMPageSet, RestoreCacheToCleanState,
UsePages, VMPageSet],
IO
USING[card, Close, GetCard, Handle, int, PutF, PutRope,
rope],
MyPerfStats
USING[CreateTimer, DestroyTimer, Initialize, InitializeTimer, Print,
Start, Stop, Timer],
Process
USING[priorityBackground, priorityNormal, SetPriority, Yield],
RandomCard
USING[Choose, Init],
Rope
USING[ROPE],
SafeStorage
USING[IsCollectorActive, WaitForCollectorDone],
System
USING[GetClockPulses, MicrosecondsToPulses, Pulses],
SystemInternal
USING[UniversalID],
Volume
USING[SystemID];


WriteBehindTestFilePageMgrImpl: PROGRAM
IMPORTS AI: AlpineInternal, AE: AlpineEnvironment, CedarVersion, FileIO, FileMap, FPM:
FilePageMgr, IO, MyPerfStats, Process, RandomCard, SafeStorage, System, Volume =


BEGIN


GetParams: PROCEDURE =
BEGIN
paramStreamHandle: IO.Handle ←
FileIO.Open["AnomaliesWriteBehind.Params", read, oldOnly];
IF (NFiles ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF NFiles > 999 THEN ERROR;
IF (NNormalChunksInCache ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (NLogChunksInCache ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
IF (NLeaderChunksInCache ← paramStreamHandle.GetCard[]) = 0 THEN ERROR;
paramStreamHandle.Close[];
resultsStreamHandle.PutF["*nNFiles: %g*n*nNNormalChunksInCache: %g NLogChunksInCache: %g NLeaderChunksInCache: %g*n*n", IO.card[NFiles],
IO.card[NNormalChunksInCache], IO.card[NLogChunksInCache],
IO.card[NLeaderChunksInCache]];
END;


SetUpFileData: PROCEDURE[] =
BEGIN
myFilesIDsStreamHandle: IO.Handle ←
FileIO.Open["ContiguousFilesFiles.IDs", write, none];
volID: AE.VolumeID ← LOOPHOLE[Volume.SystemID[]];
IF myFilesIDsStreamHandle.GetCard[] < NFiles THEN ERROR;
files ← NEW[Files[NFiles]];
FOR index: CARDINAL IN [0..NFiles)
DO fileHandle: FileMap.Handle;
files[index] ← [fileID: GetFileID[myFilesIDsStreamHandle], inUse: FALSE,
exists: TRUE, size: 0];
fileHandle ← FileMap.Register[volID, files[index].fileID];
files[index].size ← FPM.GetSize[fileHandle];
fileHandle ← NIL;
ENDLOOP;
myFilesIDsStreamHandle.Close[];
END;


GetFileID: PROCEDURE[stream: IO.Handle] RETURNS[fileID: AE.FileID] =
BEGIN
uid: SystemInternal.UniversalID;
a: CARDINAL ← stream.GetCard[];
b: CARDINAL ← stream.GetCard[];
c: CARDINAL ← stream.GetCard[];
uid ← [processor: [physical[a: a, b: b, c: c]], sequence: stream.GetCard[]];
RETURN[LOOPHOLE[uid, AE.FileID]];
END;


CleanCache: PROCEDURE =
BEGIN
FPM.RestoreCacheToCleanState[];
resultsStreamHandle.PutRope["Cache cleaned.
"];
END;


Shell: PROCEDURE[proc: PROCEDURE[fileHandle: FileMap.Handle, fileIndex: CARDINAL,
timer: MyPerfStats.Timer, ioMode: IOMode, releaseState: FPM.ReleaseState, keep:
BOOLEAN, includeLeader: BOOLEAN, fileInterval: FileInterval], fileIndex: CARDINAL,
ioMode: IOMode ← read, releaseState: FPM.ReleaseState ← clean, keep: BOOLEAN ←
FALSE, includeLeader: BOOLEAN ← FALSE, fileInterval: FileInterval ←
[someRandom[]]] =
BEGIN
fileID: AE.FileID ← files[fileIndex].fileID;
volID: AE.VolumeID ← LOOPHOLE[Volume.SystemID[]];
fileHandle: FileMap.Handle ← FileMap.Register[volID, fileID];
timer: MyPerfStats.Timer ← MyPerfStats.CreateTimer[""];
proc[fileHandle, fileIndex, timer, ioMode, releaseState, keep, includeLeader,
fileInterval];
MyPerfStats.Print[ , resultsStreamHandle, FALSE];
MyPerfStats.DestroyTimer[timer];
fileHandle ← NIL;
END;



-- varies

AllSomeOrSomeRandom: TYPE = {allFixed, allRandom, someFixed, someRandom};

FileInterval: TYPE = RECORD[SELECT allOrSomeRandom: AllSomeOrSomeRandom FROM
allFixed => [nPagesEachTime: CARDINAL],
allRandom => NULL,
someFixed => [firstPage, lastPage, nPagesEachTime: CARDINAL],
someRandom => NULL,
ENDCASE];

SequentialIO: PROCEDURE[fileHandle: FileMap.Handle, fileIndex: CARDINAL,
timer: MyPerfStats.Timer, ioMode: IOMode, releaseState: FPM.ReleaseState, keep:
BOOLEAN, includeLeader: BOOLEAN, fileInterval: FileInterval] =
BEGIN
firstPage, lastPage, nPagesEachTime: CARDINAL;
active: BOOLEAN;
prevCollectorIncarnation, endingPrevCollectorIncarnation: CARDINAL;
attempts: CARDINAL ← 5;
DO
[active, prevCollectorIncarnation] ← SafeStorage.IsCollectorActive[];
IF active THEN [prevCollectorIncarnation, , , ] ←
SafeStorage.WaitForCollectorDone[];
MyPerfStats.Start[timer];
IF includeLeader
THEN BEGIN vMPageSet: FPM.VMPageSet ← FPM.ReadLeaderPages[fileHandle];
(IF ioMode = write THEN WriteLeaderPage ELSE
ReadLeaderPage)[vMPageSet.pages];
FPM.ReleaseVMPageSet[vMPageSet, releaseState, keep];
END;
[firstPage, lastPage, nPagesEachTime] ←
SubrReadOrWriteSequentialInterval[fileHandle, fileIndex,
ioMode, releaseState, keep, fileInterval];
MyPerfStats.Stop[timer];
IF ioMode = write THEN FPM.ForceOutFile[fileHandle];
[active, endingPrevCollectorIncarnation] ← SafeStorage.IsCollectorActive[];
IF active OR endingPrevCollectorIncarnation # prevCollectorIncarnation
THEN BEGIN
volID: AE.VolumeID ← LOOPHOLE[Volume.SystemID[]];
resultsStreamHandle.PutRope["
SequentialIO interrupted by garbage collection"];
IF (attempts ← attempts - 1) > 0
THEN BEGIN resultsStreamHandle.PutRope[" retrying"];
CleanCache[];
MyPerfStats.InitializeTimer[timer];
[] ← SafeStorage.WaitForCollectorDone[];
LOOP;
END
ELSE resultsStreamHandle.PutF[" giving up"];
EXIT;
END;
EXIT;
ENDLOOP;
IF ioMode IN IOReadMode THEN SubrCheckFile[fileHandle, fileIndex];
resultsStreamHandle.PutF["SeqIO file %g*n size: %g ",
IO.card[fileIndex], IO.int[files[fileIndex].size]];
resultsStreamHandle.PutF["pgRange: [%g,%g] nPagesEachTime: %g",
IO.card[firstPage], IO.card[lastPage], IO.card[nPagesEachTime]];
IF includeLeader THEN resultsStreamHandle.PutRope[" including LeaderPage"];
resultsStreamHandle.PutF[" %g", IO.rope[(SELECT ioMode FROM read => "read",
readWithReadAhead => "readWithReadAhead", write => "write", ENDCASE =>
"ERROR")]];
resultsStreamHandle.PutF[" %g", IO.rope[(SELECT releaseState FROM
writeIndividualWait => "writeIndividualWait", writeBatchedWait =>
"writeBatchedWait", writeIndividualNoWait => "writeIndividualNoWait",
writeBatchedNoWait => "writeBatchedNoWait",
clean => "clean", ENDCASE => "ERROR")]];
resultsStreamHandle.PutF[" %g ", IO.rope[(IF keep THEN "keep" ELSE
"NOT keep")]];
END;



SubrCheckFile: PROCEDURE[fileHandle: FileMap.Handle, fileIndex: CARDINAL] =
BEGIN
checkType: File.Type;
checkVolID: AE.VolumeID;
IF FPM.GetSize[fileHandle] # files[fileIndex].size THEN ERROR;
[checkType, checkVolID] ← FPM.GetAttributes[fileHandle];
IF ((checkType # FileTypes.tUntypedFile) OR (checkVolID #
FileMap.GetVolumeID[fileHandle])) THEN ERROR;
END;


ReadLeaderPage: PROCEDURE[pages: LONG POINTER] =
BEGIN
wordCount: CARDINAL ← RandomCard.Choose[min: 0, max: AE.wordsPerPage - 1];
IF LOOPHOLE[(pages + wordCount)^, CARDINAL] # wordCount THEN ERROR;
END;


WriteLeaderPage: PROCEDURE[pages: LONG POINTER] =
BEGIN
FOR wordCount: CARDINAL IN [0..AE.wordsPerPage)
DO (pages + wordCount)^ ← wordCount; ENDLOOP;
END;


ReadDataPage: PROCEDURE[pages: LONG POINTER, pageNumber: CARDINAL] =
BEGIN
IF LOOPHOLE[(pages + RandomCard.Choose[min: 0, max: AE.wordsPerPage - 1])^, CARDINAL] # pageNumber THEN ERROR;
END;


WriteDataPage: PROCEDURE[pages: LONG POINTER, pageNumber: CARDINAL] =
BEGIN
FOR wordCount: CARDINAL IN [0..AE.wordsPerPage)
DO (pages + wordCount)^ ← pageNumber; ENDLOOP;
END;


IOMode: TYPE = {read, readWithReadAhead, write};
IOReadMode: TYPE = IOMode[read..readWithReadAhead];

SubrReadOrWriteSequentialInterval: PROCEDURE[fileHandle: FileMap.Handle,
fileIndex: CARDINAL, ioMode: IOMode, release: FPM.ReleaseState, keep: BOOLEAN,
fileInterval: FileInterval] RETURNS [firstPage, lastPage, nPagesEachTime:
CARDINAL] =
BEGIN
RandomFirstPage: PROCEDURE RETURNS[CARDINAL] = INLINE
BEGIN RETURN[RandomCard.Choose[min: 0, max: files[fileIndex].size - 1]];
END;
RandomLastPage: PROCEDURE RETURNS[CARDINAL] = INLINE
BEGIN RETURN[RandomCard.Choose[min: firstPage, max: files[fileIndex].size
- 1]];
END;
RandomNPagesEachTime: PROCEDURE RETURNS[CARDINAL] = INLINE
BEGIN RETURN[MIN[RandomCard.Choose[min: 1, max: 25], totalPages]];
END;
totalPages: CARDINAL;
times: CARDINAL;
startPage, nPages: CARDINAL;
IF files[fileIndex].size = 0 THEN RETURN[0, 0, 0];
WITH fileInt: fileInterval SELECT FROM
allFixed => BEGIN firstPage ← 0; lastPage ← files[fileIndex].size - 1; END;
allRandom => BEGIN firstPage ← 0; lastPage ← files[fileIndex].size - 1; END;
someFixed => BEGIN firstPage ← fileInt.firstPage; lastPage ←
fileInt.lastPage; END;
someRandom => BEGIN firstPage ← RandomFirstPage[]; lastPage ←
RandomLastPage[]; END;
ENDCASE => ERROR;
totalPages ← lastPage - firstPage + 1;
nPagesEachTime ← (WITH fileInt: fileInterval SELECT FROM
allFixed => fileInt.nPagesEachTime,
allRandom => RandomNPagesEachTime[],
someFixed => fileInt.nPagesEachTime,
someRandom => RandomNPagesEachTime[],
ENDCASE => ERROR);
times ← (totalPages + (nPagesEachTime - 1))/nPagesEachTime;
startPage ← firstPage;
nPages ← nPagesEachTime;
FOR index: CARDINAL IN [0..times)
DO IF index = times - 1 THEN nPages ← lastPage - startPage + 1;
HandleNPages[fileHandle, fileIndex, ioMode, release, keep, startPage,
nPages];
DelayForNPages[nPages];
startPage ← startPage + nPages;
ENDLOOP;
END;


HandleNPages: PROCEDURE[fileHandle: FileMap.Handle, fileIndex: CARDINAL, ioMode:
IOMode, release: FPM.ReleaseState, keep: BOOLEAN, firstPage, nPages: CARDINAL] =
BEGIN
pageRun: AE.PageRun ← [firstPage: firstPage, count: nPages];
vMPageSet: FPM.VMPageSet;
pages: LONG POINTER;
pageNumber: CARDINAL ← firstPage;
DO
vMPageSet ← (IF ioMode IN IOReadMode THEN FPM.ReadPages ELSE
FPM.UsePages)[fileHandle, pageRun];
pages ← vMPageSet.pages;
IF vMPageSet.pageRun.count > pageRun.count THEN ERROR;
FOR index: CARDINAL IN [0..vMPageSet.pageRun.count)
DO
(IF ioMode IN IOReadMode THEN ReadDataPage ELSE WriteDataPage)[pages,
pageNumber];
pageNumber ← pageNumber + 1;
pages ← pages + AE.wordsPerPage;
ENDLOOP;
FPM.ReleaseVMPageSet[vMPageSet, release, keep];
pageRun.firstPage ← pageRun.firstPage + vMPageSet.pageRun.count;
pageRun.count ← pageRun.count - vMPageSet.pageRun.count;
IF pageRun.count = 0 THEN EXIT;
ENDLOOP;
IF ((ioMode = readWithReadAhead) AND (pageRun.firstPage <
files[fileIndex].size))
THEN BEGIN
pageRun.count ← MIN[nPages + nPages, files[fileIndex].size - (firstPage
+ nPages)];
FPM.ReadAheadPages[fileHandle, pageRun];
END;
END;


SetDelayConst: PROCEDURE[const: LONG CARDINAL] =
BEGIN
resultsStreamHandle.PutF["*nDelay set to %g ms per page, each transfer.*n*n", IO.card[const]];
delayConst ← const*LONG[1000];
END;


delayConst: LONG CARDINAL ← 4000;

DelayForNPages: PROCEDURE[nPages: CARDINAL] =
BEGIN
newPulseLimit: System.Pulses;
newPulseLimit ← [System.GetClockPulses[] +
System.MicrosecondsToPulses[delayConst*LONG[nPages]]];
Process.SetPriority[Process.priorityBackground];
DO
Process.Yield[];
IF System.GetClockPulses[] >= newPulseLimit THEN EXIT;
ENDLOOP;
Process.SetPriority[Process.priorityNormal];
END;


MaxFiles: CARDINAL = 6;

Main: PROCEDURE =
BEGIN -- set up to call from CoPilot for debugging.
foo: CARDINAL ← 0;
fileIndex: CARDINAL;
expectedSize: CARDINAL ← 999;
BEGIN
ENABLE ANY => foo ← foo + 1; -- protect us from the tempcedarexec.
MyPerfStats.Initialize[];
resultsStreamHandle ← FileIO.Open["AnomaliesWriteBehind.Results",
append, none];
resultsStreamHandle.PutF["*nMachine type: %g*n*n", IO.rope[SELECT
CedarVersion.machineType FROM dolphin => "Dolphin", dorado => "Dorado",
dandelion => "Dandelion", dicentra => "Dicentra", ENDCASE => "unknown"]];
[] ← RandomCard.Init[0];
GetParams[];
FileMap.Initialize[numHashSlotsDesired: 43, fQLength: 60];
FPM.InitializeFilePageMgr[nNormalChunksInCache: NNormalChunksInCache,
nLogChunksInCache: NLogChunksInCache, nLeaderChunksInCache:
NLeaderChunksInCache];
resultsStreamHandle.PutRope["
Delay used is 4 milliseconds per page, after each transfer, unless superceeded.

"];
SetUpFileData[];
fileIndex ← 5;

IF files[fileIndex].size # expectedSize THEN ERROR;

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeBatchedNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[4]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeBatchedNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[4]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeIndividualNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[4]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeIndividualNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[4]]];

resultsStreamHandle.PutRope["
"];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeBatchedNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[5]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeBatchedNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[5]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeIndividualNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[5]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeIndividualNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[5]]];

resultsStreamHandle.PutRope["
"];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeBatchedNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[22]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeBatchedNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[22]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeIndividualNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[22]]];

CleanCache[];
Shell[SequentialIO, fileIndex, write, writeIndividualNoWait, --keep--FALSE,
--leader--FALSE, [allFixed[22]]];

resultsStreamHandle.Close[];
END;
END;




-- main line code:

resultsStreamHandle: IO.Handle;

NFiles: CARDINAL;
files: REF Files;
Files: TYPE = RECORD[SEQUENCE nFiles: [0..LAST[CARDINAL]] OF FileModel];
FileModel: TYPE = RECORD[fileID: AE.FileID, inUse: BOOLEAN, exists: BOOLEAN, size: CARDINAL];
NNormalChunksInCache: CARDINAL;
NLogChunksInCache: CARDINAL;
NLeaderChunksInCache: CARDINAL;



END.

Edit Log

Initial: Kolling: 19-Apr-82 12:22:00: test for FilePageManager.