File: FileStreamOneTestImpl.mesa
Last edited by MBrown on July 11, 1983 11:05 pm
Last Edited by: Hagmann, November 22, 1983 4:31 pm
Last Edited by: Taft, December 1, 1983 4:00 pm
DIRECTORY
FileStreamTestInterface,
FS,
IO,
Basics USING [LongNumber, LowByte, LowHalf, BITAND, UnsafeBlock],
PrincOpsUtils USING [LongZero],
Process USING [Pause],
RandomCard USING [Init, Next, Choose],
Rope USING [ROPE],
VM;
FileStreamOneTestImpl: PROGRAM
IMPORTS
FileStreamTestInterface,
IO,
I: Basics,
PrincOpsUtils,
Process,
RAN: RandomCard,
VM
EXPORTS
FileStreamTestInterface
= BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
StopChase: BOOLFALSE ;
realStream: STREAM;
randomDataBlockSize: CARDINAL = 1000;
dataBlockForRandomPutGetBlock: REF TEXT;
dataBlockForRandomUnsafePutGetBlock: I.UnsafeBlock ;
UnsafeBlockInterval: VM.Interval;
maxFileBytes: LONG CARDINALVM.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: BOOLFALSE;
GoSlow: BOOLFALSE;
Alarm: SIGNAL = CODE;
TickStop: SIGNAL = CODE;
specific test code
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]];
[] ← RAN.Init[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]
};
random actions
RandomPutChar: PROC [] RETURNS [BOOL] = {
c: CHAR;
IF simStreamCharPointer >= maxSimFileCharLength THEN RETURN[FALSE];
SimPutChar[c ← LOOPHOLE[I.LowByte[RAN.Next[]]]];
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: NATIF longBytesLeft >= randomDataBlockSize THEN randomDataBlockSize
ELSE I.LowHalf[longBytesLeft];
bytesToXfer: NATRAN.Choose[0, maxBytesToXfer];
FOR I: NAT IN [0..bytesToXfer) DO
dataBlockForRandomPutGetBlock[I] ← LOOPHOLE[RAN.Next[],CHAR]
ENDLOOP;
dataBlockForRandomPutGetBlock.length ← bytesToXfer;
SimPutBlock[dataBlockForRandomPutGetBlock];
RETURN[TRUE] };
RandomUnsafePutBlock: PROC [] RETURNS [BOOL] = {
longBytesLeft: LONG CARDINAL ← maxSimFileCharLength - simStreamCharPointer;
maxBytesToXfer: NATIF longBytesLeft >= randomDataBlockSize THEN randomDataBlockSize
ELSE I.LowHalf[longBytesLeft];
bytesToXfer: NATRAN.Choose[0, maxBytesToXfer];
FOR I: NAT IN [0..bytesToXfer) DO
dataBlockForRandomUnsafePutGetBlock.base[I] ← LOOPHOLE[RAN.Next[],CHAR]
ENDLOOP;
dataBlockForRandomUnsafePutGetBlock.count ← bytesToXfer;
SimUnsafePutBlock[dataBlockForRandomUnsafePutGetBlock];
RETURN[TRUE] };
RandomGetBlock: PROC [] RETURNS [BOOL] = {
longBytesLeft: LONG CARDINAL ← simFileCharLength - simStreamCharPointer;
maxBytesToXfer: NATIF longBytesLeft >= randomDataBlockSize THEN randomDataBlockSize
ELSE I.LowHalf[longBytesLeft];
bytesToXfer: NATRAN.Choose[0, maxBytesToXfer];
SimGetBlock[dataBlockForRandomPutGetBlock, bytesToXfer];
RETURN[TRUE] };
RandomUnsafeGetBlock: PROC [] RETURNS [BOOL] = {
longBytesLeft: LONG CARDINAL ← simFileCharLength - simStreamCharPointer;
maxBytesToXfer: NATIF longBytesLeft >= randomDataBlockSize THEN randomDataBlockSize
ELSE I.LowHalf[longBytesLeft];
bytesToXfer: NATRAN.Choose[0, maxBytesToXfer];
dataBlockForRandomUnsafePutGetBlock.count ← bytesToXfer ;
SimUnsafeGetBlock[dataBlockForRandomUnsafePutGetBlock, bytesToXfer];
RETURN[TRUE] };
RandomSetPosition: PROC [] RETURNS [BOOL] = {
pos: LONG CARDINAL
LOOPHOLE[I.LongNumber[num[lowbits: RAN.Next[], highbits: RAN.Next[]]],
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: RAN.Next[], highbits: RAN.Next[]]],
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: RAN.Next[], highbits: RAN.Next[]]],
LONG CARDINAL] MOD simFileCharLength;
SimSetLength[newSize];
RETURN[TRUE] };
RandomGetLength: PROC [] RETURNS [BOOL] = {
len: LONG CARDINAL ← SimGetLength[];
RETURN[TRUE] };
basic model code
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];
};
following procedures affect model and also real stream
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;
Debug["PutChar"];
realStream.PutChar[c] };
SimGetChar: PROC RETURNS [c: CHAR] = {
fetchedC: CHAR;
IF simStreamCharPointer >= simFileCharLength THEN Alarm[];
c ← FetchFromSimFile[simStreamCharPointer];
simStreamCharPointer ← simStreamCharPointer + 1;
fetchedC ← realStream.GetChar[];
Debug["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] = 0C THEN unsafeBlock.base[I] ← 1C;
AssignToSimFile[simStreamCharPointer, 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];
Debug["GetBlock, nChars = "];
DebugD[nChars];
charsXferred ← realStream.GetBlock[block, 0, nChars];
IF charsXferred # 0 AND charsXferred # block.length THEN Alarm[];
IF charsXferred # nCharsToBeXferred THEN Alarm[];
FOR I: CARDINAL IN [0..charsXferred) DO
c ← FetchFromSimFile[simStreamCharPointer];
IF c # 0C AND c # block[I] THEN Alarm[];
simStreamCharPointer ← simStreamCharPointer + 1;
ENDLOOP };
SimUnsafeGetBlock: PROC [unsafeBlock: I.UnsafeBlock, nChars: NAT] = {
c: CHAR;
charsLeft: LONG CARDINAL = simFileCharLength - simStreamCharPointer;
charsXferred: NAT;
nCharsToBeXferred: NAT =
MIN[IF charsLeft>=nChars THEN nChars ELSE I.LowHalf[charsLeft], randomDataBlockSize];
Debug["UnsafeGetBlock, nChars = "];
DebugD[nChars];
charsXferred ← realStream.UnsafeGetBlock[block: unsafeBlock];
IF charsXferred # 0 AND charsXferred # unsafeBlock.count THEN Alarm[];
IF charsXferred # nCharsToBeXferred THEN Alarm[];
FOR I: CARDINAL IN [0..charsXferred) DO
c ← FetchFromSimFile[simStreamCharPointer];
IF c # 0C AND c # unsafeBlock.base[I] THEN Alarm[];
simStreamCharPointer ← simStreamCharPointer + 1;
ENDLOOP };
SimSetPosition: PROC [position: LONG CARDINAL] = {
IF position > simFileCharLength THEN Alarm[];
simStreamCharPointer ← position;
Debug["SetPosition to "];
DebugLD[position];
realStream.SetIndex[position] };
SimGetPosition: PROC RETURNS [LONG CARDINAL] = {
pos: LONG CARDINAL;
Debug["GetPosition, it should be "];
DebugLD[simStreamCharPointer];
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;
Debug["GetLength, it should be "];
DebugLD[simFileCharLength];
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]] };
testing support
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: CARDINALRAN.Choose[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] = {
for debugger invocation
RETURN[h.GetLength[]] };
SetInd: PROC [h: STREAM, i: LONG CARDINAL] = {
for debugger invocation
h.SetIndex[i] };
GetInd: PROC [h: STREAM] RETURNS [LONG CARDINAL] = {
for debugger invocation
RETURN[h.GetIndex[]] };
GetCha: PROC [h: STREAM] RETURNS [CARDINAL] = {
for debugger invocation
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.