<> <> <> <> <> DIRECTORY FileStreamTestInterface, FS, IO, Basics USING [BYTE, LongNumber, LowByte, LowHalf, BITAND, UnsafeBlock], PrincOpsUtils USING [LongZero], Process USING [Pause], Random USING [Create, NextInt, ChooseInt, RandomStream], Rope USING [ROPE], VM; FileStreamOneTestImpl: PROGRAM IMPORTS FileStreamTestInterface, IO, I: Basics, PrincOpsUtils, Process, RAN: Random, VM EXPORTS FileStreamTestInterface = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; StopChase: BOOL _ FALSE ; realStream: STREAM; randomDataBlockSize: CARDINAL = 1000; dataBlockForRandomPutGetBlock: REF TEXT; dataBlockForRandomUnsafePutGetBlock: I.UnsafeBlock ; UnsafeBlockInterval: VM.Interval; maxFileBytes: LONG CARDINAL _ VM.BytesForPages[140] + 1; simFileInterval: VM.Interval; simFileData: LONG POINTER; --TO PACKED ARRAY OF CHAR simFileCharLength: LONG CARDINAL; maxSimFileCharLength: LONG CARDINAL; simStreamCharPointer: LONG CARDINAL; MainTestCases: DESCRIPTOR FOR ARRAY OF ActionCase = DESCRIPTOR[MainTestCasesBody]; MainTestCasesBody: ARRAY [0..11) OF ActionCase _ [ [170, RandomPutChar, "RandomPutChar", 0], [140, RandomGetChar, "RandomGetChar", 0], [70, RandomPutBlock, "RandomPutBlock", 0], [70, RandomGetBlock, "RandomGetBlock", 0], [90, RandomUnsafePutBlock, "RandomUnsafePutBlock", 0], [90, RandomUnsafeGetBlock, "RandomUnsafeGetBlock", 0], [70, RandomSetPosition, "RandomSetPosition", 0], [70, RandomGetPosition, "RandomGetPosition", 0], [90, RandomLengthen, "RandomLengthen", 0], [70, RandomShorten, "RandomShorten", 0], [70, RandomGetLength, "RandomGetLength", 0]]; tick: LONG CARDINAL _ 37777777777B; --we begin with a Tick[] to make this 0 tickTarget: LONG CARDINAL _ 37777777777B; ticksPerTest: LONG CARDINAL _ 4000; tickLimit: LONG CARDINAL; randomSeed: CARDINAL _ 12314B; chaseCount: INT = 800000 ; backupChaseCount: INT = 30000 ; debugTrace: BOOL _ FALSE; GoSlow: BOOL _ FALSE; Alarm: SIGNAL = CODE; TickStop: SIGNAL = CODE; RandomStream: RAN.RandomStream; <> OneTest: PUBLIC SAFE PROC [file: ROPE] = TRUSTED { s: STREAM; FileStreamTestInterface.dpy.PutF["\n\n\nOneTest: ticks will start at %gD\n\n", IO.card[tick]]; tickLimit _ tick + ticksPerTest; FileStreamTestInterface.dpy.PutF["\ninitializing random numbers with %bB\n", IO.card[randomSeed]]; RandomStream _ RAN.Create[seed: randomSeed]; s _ FileStreamTestInterface.StreamOpen[fileName: file, accessOptions: create, createByteCount: maxFileBytes]; InitStreamModel[s, maxFileBytes]; Tick[]; WHILE tick < tickLimit DO IF GoSlow THEN Process.Pause[6]; IF TryOneRandomAction[MainTestCases] THEN --did something-- Tick[]; ENDLOOP; s.Close[]; s _ NIL ; FileStreamTestInterface.dpy.PutF["\n\n\nOneTest: test completed\n\n\n"]; }; PrintStatistics: PROC = { PrintCaseArrayStatistics[MainTestCases] }; <> RandomPutChar: PROC [] RETURNS [BOOL] = { c: CHAR; IF simStreamCharPointer >= maxSimFileCharLength THEN RETURN[FALSE]; SimPutChar[c _ LOOPHOLE[I.LowByte[RandomStream.NextInt[]]]]; RETURN[TRUE] }; RandomGetChar: PROC [] RETURNS [BOOL] = { c: CHAR; IF simStreamCharPointer >= simFileCharLength THEN RETURN[FALSE]; c _ SimGetChar[]; RETURN[TRUE] }; RandomPutBlock: PROC [] RETURNS [BOOL] = { longBytesLeft: LONG CARDINAL _ maxSimFileCharLength - simStreamCharPointer; maxBytesToXfer: NAT _ IF longBytesLeft >= randomDataBlockSize THEN randomDataBlockSize ELSE I.LowHalf[longBytesLeft]; bytesToXfer: NAT _ RandomStream.ChooseInt[0, maxBytesToXfer]; FOR index: NAT IN [0..bytesToXfer) DO bitbit: I.BYTE = RandomStream.ChooseInt[0, 377B]; dataBlockForRandomPutGetBlock[index] _ LOOPHOLE[bitbit, CHAR] ENDLOOP; dataBlockForRandomPutGetBlock.length _ bytesToXfer; SimPutBlock[dataBlockForRandomPutGetBlock]; RETURN[TRUE] }; RandomUnsafePutBlock: PROC [] RETURNS [BOOL] = { longBytesLeft: LONG CARDINAL _ maxSimFileCharLength - simStreamCharPointer; maxBytesToXfer: NAT _ IF longBytesLeft >= randomDataBlockSize THEN randomDataBlockSize ELSE I.LowHalf[longBytesLeft]; bytesToXfer: NAT _ RandomStream.ChooseInt[0, maxBytesToXfer]; FOR index: NAT IN [0..bytesToXfer) DO bitbit: I.BYTE = RandomStream.ChooseInt[0, 377B]; dataBlockForRandomUnsafePutGetBlock.base[index] _ bitbit; ENDLOOP; dataBlockForRandomUnsafePutGetBlock.count _ bytesToXfer; SimUnsafePutBlock[dataBlockForRandomUnsafePutGetBlock]; RETURN[TRUE] }; RandomGetBlock: PROC [] RETURNS [BOOL] = { longBytesLeft: LONG CARDINAL _ simFileCharLength - simStreamCharPointer; maxBytesToXfer: NAT _ IF longBytesLeft >= randomDataBlockSize THEN randomDataBlockSize ELSE I.LowHalf[longBytesLeft]; bytesToXfer: NAT _ RandomStream.ChooseInt[0, maxBytesToXfer]; SimGetBlock[dataBlockForRandomPutGetBlock, bytesToXfer]; RETURN[TRUE] }; RandomUnsafeGetBlock: PROC [] RETURNS [BOOL] = { longBytesLeft: LONG CARDINAL _ simFileCharLength - simStreamCharPointer; maxBytesToXfer: NAT _ IF longBytesLeft >= randomDataBlockSize THEN randomDataBlockSize ELSE I.LowHalf[longBytesLeft]; bytesToXfer: NAT _ RandomStream.ChooseInt[0, maxBytesToXfer]; dataBlockForRandomUnsafePutGetBlock.count _ bytesToXfer ; SimUnsafeGetBlock[dataBlockForRandomUnsafePutGetBlock, bytesToXfer]; RETURN[TRUE] }; RandomSetPosition: PROC [] RETURNS [BOOL] = { pos: LONG CARDINAL _ LOOPHOLE[I.LongNumber[num[lowbits: RandomStream.NextInt[], highbits: RandomStream.NextInt[]]], LONG CARDINAL] MOD (simFileCharLength + 1); SimSetPosition[pos]; RETURN[TRUE] }; RandomGetPosition: PROC [] RETURNS [BOOL] = { pos: LONG CARDINAL _ SimGetPosition[]; RETURN[TRUE] }; RandomLengthen: PROC [] RETURNS [BOOL] = { increase: LONG CARDINAL; maxIncrease: LONG CARDINAL _ maxSimFileCharLength - simFileCharLength; IF maxIncrease = 0 THEN RETURN[FALSE]; increase _ LOOPHOLE[I.LongNumber[num[lowbits: RandomStream.NextInt[], highbits: RandomStream.NextInt[]]], LONG CARDINAL] MOD maxIncrease; SimSetLength[simFileCharLength + increase]; RETURN[TRUE] }; RandomShorten: PROC [] RETURNS [BOOL] = { newSize: LONG CARDINAL; IF simFileCharLength = 0 THEN RETURN[FALSE]; newSize _ LOOPHOLE[I.LongNumber[num[lowbits: RandomStream.NextInt[], highbits: RandomStream.NextInt[]]], LONG CARDINAL] MOD simFileCharLength; SimSetLength[newSize]; RETURN[TRUE] }; RandomGetLength: PROC [] RETURNS [BOOL] = { len: LONG CARDINAL _ SimGetLength[]; RETURN[TRUE] }; <> InitStreamModel: PROC [s: STREAM, maxFileBytes: LONG CARDINAL] = { simFilePages: VM.PageCount = VM.PagesForBytes[maxFileBytes]; unsafePages: VM.PageCount = VM.PagesForBytes[randomDataBlockSize]; simFileInterval _ VM.Allocate[count: simFilePages]; simFileData _ VM.AddressForPageNumber[simFileInterval.page]; PrincOpsUtils.LongZero[where: simFileData, nwords: VM.WordsForPages[simFilePages]]; simFileCharLength _ 0; simStreamCharPointer _ 0; maxSimFileCharLength _ maxFileBytes; realStream _ s; dataBlockForRandomPutGetBlock _ NEW[TEXT[randomDataBlockSize] _ [ length: 0, text: NULL]]; UnsafeBlockInterval _ VM.Allocate[count: unsafePages]; dataBlockForRandomUnsafePutGetBlock.base _ VM.AddressForPageNumber[UnsafeBlockInterval.page]; }; <> Pair: TYPE = MACHINE DEPENDENT RECORD [highHalf(0: 0..7): CHAR, lowHalf(0: 8..15): CHAR]; AssignToSimFile: PROC [i: LONG CARDINAL, c: CHAR] = INLINE { ptr: LONG POINTER TO Pair _ LOOPHOLE[simFileData + i/2]; IF I.BITAND[LOOPHOLE[i, I.LongNumber[num]].lowbits,1] = 0 THEN --high char ptr.highHalf _ c ELSE ptr.lowHalf _ c }; FetchFromSimFile: PROC [i: LONG CARDINAL] RETURNS [CHAR] = INLINE { ptr: LONG POINTER TO Pair _ LOOPHOLE[simFileData + i/2]; IF I.BITAND[LOOPHOLE[i, I.LongNumber[num]].lowbits,1] = 0 THEN --high char RETURN[ptr.highHalf] ELSE RETURN[ptr.lowHalf] }; SimPutChar: PROC [c: CHAR] = { IF c = 0C THEN c _ 1C; IF simStreamCharPointer > simFileCharLength THEN Alarm[]; IF simStreamCharPointer = maxSimFileCharLength THEN Alarm[]; AssignToSimFile[simStreamCharPointer, c]; simStreamCharPointer _ simStreamCharPointer + 1; IF simStreamCharPointer > simFileCharLength THEN simFileCharLength _ simStreamCharPointer; <> realStream.PutChar[c] }; SimGetChar: PROC RETURNS [c: CHAR] = { fetchedC: CHAR; IF simStreamCharPointer >= simFileCharLength THEN Alarm[]; c _ FetchFromSimFile[simStreamCharPointer]; simStreamCharPointer _ simStreamCharPointer + 1; fetchedC _ realStream.GetChar[]; <> IF c # 0C AND c # fetchedC THEN Alarm[] }; SimPutBlock: PROC [block: REF TEXT] = { IF simStreamCharPointer + block.length > maxSimFileCharLength THEN Alarm[]; FOR I: NAT IN [0..block.length) DO IF block[I] = 0C THEN block[I] _ 1C; AssignToSimFile[simStreamCharPointer, block[I]]; simStreamCharPointer _ simStreamCharPointer + 1; ENDLOOP; IF simStreamCharPointer > simFileCharLength THEN simFileCharLength _ simStreamCharPointer; Debug["PutBlock, nBytes = "]; DebugD[block.length]; realStream.PutBlock[block, 0, block.length]; }; SimUnsafePutBlock: PROC [unsafeBlock: I.UnsafeBlock] = { count: LONG CARDINAL _ unsafeBlock.count ; IF simStreamCharPointer + count > maxSimFileCharLength THEN Alarm[]; FOR I: INT IN [0..unsafeBlock.count) DO IF unsafeBlock.base[I] = 0 THEN unsafeBlock.base[I] _ 1; AssignToSimFile[simStreamCharPointer, LOOPHOLE[unsafeBlock.base[I]]]; simStreamCharPointer _ simStreamCharPointer + 1; ENDLOOP; IF simStreamCharPointer > simFileCharLength THEN simFileCharLength _ simStreamCharPointer; Debug["UnsafePutBlock, nBytes = "]; DebugD[unsafeBlock.count]; realStream.UnsafePutBlock[block: unsafeBlock]; }; SimGetBlock: PROC [block: REF TEXT, nChars: NAT] = { c: CHAR; charsLeft: LONG CARDINAL = simFileCharLength - simStreamCharPointer; charsXferred: NAT; nCharsToBeXferred: NAT = MIN[IF charsLeft>=nChars THEN nChars ELSE I.LowHalf[charsLeft], block.maxLength]; <> <> IF simStreamCharPointer # (pos _ realStream.GetIndex[]) THEN Alarm[]; RETURN[simStreamCharPointer] }; SimSetLength: PROC [length: LONG CARDINAL] = { IF length > maxSimFileCharLength THEN Alarm[]; Debug["SetLength to "]; DebugLD[length]; realStream.SetLength[length]; FOR i: LONG CARDINAL IN [simFileCharLength..length) DO AssignToSimFile[i, 0C]; -- make value undefined in new region ENDLOOP; simFileCharLength _ length; simStreamCharPointer _ MIN[simStreamCharPointer, length] }; SimGetLength: PROC RETURNS [LONG CARDINAL] = { len: LONG CARDINAL; <> <> IF simFileCharLength # (len _ realStream.GetLength[]) THEN Alarm[]; RETURN[simFileCharLength] }; Debug: PROC [r: ROPE] = { IF debugTrace THEN FileStreamTestInterface.dpy.PutF["\nduring tick %g, %g", IO.card[tick], IO.rope[r]] }; DebugD: PROC [d: CARDINAL] = { IF debugTrace THEN FileStreamTestInterface.dpy.PutF["%g", IO.card[d]] }; DebugLD: PROC [d: LONG CARDINAL] = { IF debugTrace THEN FileStreamTestInterface.dpy.PutF["%g", IO.card[d]] }; <> ActionArray: TYPE = DESCRIPTOR FOR ARRAY OF ActionCase; ActionCase: TYPE = RECORD [ prob: CARDINAL, -- probs must sum to 1000 action: PROC [] RETURNS [BOOL], printName: ROPE, count: LONG CARDINAL]; TryOneRandomAction: PUBLIC PROC [T: ActionArray] RETURNS [didSomething: BOOL] = { r: CARDINAL _ RandomStream.ChooseInt[0, 999]; FOR I: CARDINAL IN [0..LENGTH[T]) DO IF r < T[I].prob THEN { IF T[I].action[] THEN { T[I].count _ T[I].count + 1; RETURN[TRUE] } ELSE RETURN[FALSE] }; r _ r - T[I].prob; ENDLOOP; Alarm[] }; GetLen: PROC [h: STREAM] RETURNS [LONG CARDINAL] = { <> RETURN[h.GetLength[]] }; SetInd: PROC [h: STREAM, i: LONG CARDINAL] = { <> h.SetIndex[i] }; GetInd: PROC [h: STREAM] RETURNS [LONG CARDINAL] = { <> RETURN[h.GetIndex[]] }; GetCha: PROC [h: STREAM] RETURNS [CARDINAL] = { <> RETURN[LOOPHOLE[h.GetChar[]]] }; Tick: PUBLIC PROC = { tick _ tick + 1; IF (tick MOD 50 = 0) THEN { FileStreamTestInterface.dpy.PutF["\ntick becomes: %gD \n", IO.card[tick]]; IF GoSlow THEN Process.Pause[15]; }; IF tick = tickTarget THEN SIGNAL TickStop; IF tick MOD 500 = 0 THEN PrintStatistics[] }; PrintCaseArrayStatistics: PROC [A: ActionArray] = { FileStreamTestInterface.dpy.PutF["\nstatistics at tick = %g\n", IO.card[tick]]; FOR I: CARDINAL IN [0..LENGTH[A]) DO FileStreamTestInterface.dpy.PutF["%g: prob(**1000): %g, nTimes: %g\n", IO.rope[A[I].printName], IO.card[A[I].prob], IO.card[A[I].count]]; ENDLOOP }; END. <> <> <<>>