-- ReadAheadTestFilePageMgrImpl.mesa Last edit: Kolling December 13, 1983 1:33 pm

DIRECTORY

AlpineEnvironment
USING[FileID, PageCount, PageNumber, PageRun, VolumeID, wordsPerPage],
AlpineInternal
USING[FileHandle],
BasicTime
USING[GetClockPulses, MicrosecondsToPulses, Pulses],
File
USING[FP, NullVolumeRep],
FileMap
USING[Handle, Initialize, Register],
FilePageMgr
USING[FileExists, ForceOutEverything, GetSize,
InitializeFilePageMgr, ForceOutFile, ReadAheadPages, ReadLeaderPages,
ReadPages, ReleaseState, ReleaseVMPageSet, RestoreCacheToCleanState,
UsePages, VMPageSet],
FS
USING[StreamOpen],
IO
USING[card, Close, GetCard, GetInt, int, PutF, PutRope, rope, STREAM],
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],
SystemVersion
USING[machineType];


ReadAheadTestFilePageMgrImpl: PROGRAM
IMPORTS BasicTime, FileMap, FPM: FilePageMgr, FS, IO, MyPerfStats, Process, RandomCard,
SafeStorage, SystemVersion
SHARES File =


BEGIN OPEN AI: AlpineInternal, AE: AlpineEnvironment;


GetParams: PROCEDURE =
BEGIN
paramStreamHandle: IO.STREAMFS.StreamOpen["AnomaliesReadAhead.Params", $read];
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.STREAMFS.StreamOpen["ContiguousFilesFiles.IDs", $read];
IF myFilesIDsStreamHandle.GetCard[] < NFiles THEN ERROR;
files ← NEW[Files[NFiles]];
volumeID ← GetVolumeID[myFilesIDsStreamHandle];
FOR index: CARDINAL IN [0..NFiles)
DO fileHandle: FileMap.Handle;
files[index] ← [fileID: GetFileID[myFilesIDsStreamHandle], inUse: FALSE,
exists: TRUE, size: 0];
fileHandle ← FileMap.Register[volumeID, files[index].fileID];
files[index].size ← FPM.GetSize[fileHandle];
fileHandle ← NIL;
ENDLOOP;
myFilesIDsStreamHandle.Close[];
END;


GetFileID: PROCEDURE[stream: IO.STREAM] RETURNS[AE.FileID] =
BEGIN
fileID: File.FP;
id: INT ← stream.GetInt[];
da: INT ← stream.GetInt[];
fileID ← [id: LOOPHOLE[id], da: LOOPHOLE[da]];
RETURN[LOOPHOLE[fileID, AE.FileID]];
END;


GetVolumeID: PROCEDURE[stream: IO.STREAM] RETURNS[AE.VolumeID] =
BEGIN
volumeID: File.NullVolumeRep;
a: CARDINAL ← stream.GetCard[];
b: CARDINAL ← stream.GetCard[];
c: CARDINAL ← stream.GetCard[];
d: CARDINAL ← stream.GetCard[];
e: CARDINAL ← stream.GetCard[];
volumeID ← [a: a, b: b, c: c, d: d, e: e];
RETURN[LOOPHOLE[volumeID, AE.VolumeID]];
END;


CleanCache: PROCEDURE =
BEGIN
FPM.ForceOutEverything[];
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: BOOLEANFALSE, fileInterval: FileInterval ←
[someRandom[]]] =
BEGIN
fileID: AE.FileID ← files[fileIndex].fileID;
fileHandle: FileMap.Handle ← FileMap.Register[volumeID, 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
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 => "read+ReadAhead", 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
IF FPM.GetSize[fileHandle] # files[fileIndex].size THEN ERROR;
IF NOT FPM.FileExists[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["\n\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: BasicTime.Pulses;
--newPulseLimit ← BasicTime.GetClockPulses[] +
--BasicTime.MicrosecondsToPulses[delayConst*LONG[nPages]];
--Process.SetPriority[Process.priorityBackground];
--DO
--Process.Yield[];
--IF BasicTime.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 ← 4;
expectedSize: CARDINAL ← 499;
BEGIN
ENABLE ANY => foo ← foo + 1; -- protect us from the tempcedarexec.
MyPerfStats.Initialize[];
resultsStreamHandle ← FS.StreamOpen["AnomaliesReadAhead.Results", $append];
resultsStreamHandle.PutF["\nMachine type: %g\n\n", IO.rope[SELECT
SystemVersion.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];
SetUpFileData[];

--check expected file:
IF ((NFiles < 5) OR (files[fileIndex].size # expectedSize)) THEN ERROR;
THROUGH [0..10)
DO
Shell[SequentialIO, fileIndex, write, writeBatchedNoWait,
--keep--FALSE, --leader--TRUE, [allFixed[files[fileIndex].size]]];
resultsStreamHandle.PutRope["

"];

CleanCache[];
ENDLOOP;

THROUGH [0..0)
DO
Shell[SequentialIO, fileIndex, read, clean, --keep--FALSE, --leader--FALSE,
[allFixed[5]]];
CleanCache[];
Shell[SequentialIO, fileIndex, readWithReadAhead, clean, --keep--FALSE,
--leader--FALSE,
[allFixed[5]]];
CleanCache[];
ENDLOOP;

THROUGH [0..0)
DO
Shell[SequentialIO, fileIndex, read, clean, --keep--FALSE, --leader--FALSE,
[allFixed[4]]];
CleanCache[];
Shell[SequentialIO, fileIndex, readWithReadAhead, clean, --keep--FALSE,
--leader--FALSE,
[allFixed[4]]];
CleanCache[];
ENDLOOP;

THROUGH [0..0)
DO
Shell[SequentialIO, fileIndex, read, clean, --keep--FALSE, --leader--FALSE,
[allFixed[20]]];
CleanCache[];
Shell[SequentialIO, fileIndex, readWithReadAhead, clean, --keep--FALSE,
--leader--FALSE,
[allFixed[20]]];

CleanCache[];
ENDLOOP;
resultsStreamHandle.Close[];
END;
END;




-- main line code:

resultsStreamHandle: IO.STREAM;

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;
volumeID: AE.VolumeID;


END.

Edit Log

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