-- 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.