-- ReadAheadTestFilePageMgrImpl.mesa Last edit: KK December 13, 1983 12:49 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]; ReadAheadTestFilePageMgrImpl: 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["AnomaliesReadAhead.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 => "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 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["\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: 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 ← 4; expectedSize: CARDINAL ← 499; BEGIN ENABLE ANY => foo ← foo + 1; -- protect us from the tempcedarexec. MyPerfStats.Initialize[]; resultsStreamHandle ← FileIO.Open["AnomaliesReadAhead.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]; SetUpFileData[]; --check expected file: IF ((NFiles < 5) OR (files[fileIndex].size # expectedSize)) THEN ERROR; Shell[SequentialIO, fileIndex, write, writeBatchedNoWait, --keep--FALSE, --leader--TRUE, [allFixed[files[fileIndex].size]]]; resultsStreamHandle.PutRope[" "]; --FOR delay: CARDINAL IN [0..6] --DO SetDelayConst[delay]; CleanCache[]; Shell[SequentialIO, fileIndex, read, clean, --keep--FALSE, --leader--FALSE, [allFixed[5]]]; CleanCache[]; Shell[SequentialIO, fileIndex, readWithReadAhead, clean, --keep--FALSE, --leader--FALSE, [allFixed[5]]]; --ENDLOOP; --FOR delay: CARDINAL IN [0..6] --DO SetDelayConst[delay]; CleanCache[]; Shell[SequentialIO, fileIndex, read, clean, --keep--FALSE, --leader--FALSE, [allFixed[4]]]; CleanCache[]; Shell[SequentialIO, fileIndex, readWithReadAhead, clean, --keep--FALSE, --leader--FALSE, [allFixed[4]]]; --ENDLOOP; --FOR delay: CARDINAL IN [0..6] --DO SetDelayConst[delay]; CleanCache[]; Shell[SequentialIO, fileIndex, read, clean, --keep--FALSE, --leader--FALSE, [allFixed[20]]]; CleanCache[]; Shell[SequentialIO, fileIndex, readWithReadAhead, clean, --keep--FALSE, --leader--FALSE, [allFixed[20]]]; --ENDLOOP; CleanCache[]; 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.