-- 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. J}>?