-- LupineTimeTestDriver.mesa.
-- Copyright (C) 1985 by Xerox Corporation. All rights reserved.
-- Last edited by BZM on 2-Mar-82 21:12:38.
-- Last edited by Andrew Birrell on January 26, 1983 6:08 pm
-- Bob Hagmann February 8, 1985 5:11:04 pm PST
-- This program is derived from Liaison's Mesa6 ParamTestDriver.
DIRECTORY
Heap USING [systemZone],
LupineTimeTest, --USING [ALL]
String USING [AppendLongNumber, AppendString, InvalidNumber, StringToDecimal],
Mopcodes USING [zMISC],
Process USING [Detach, Yield],
Runtime USING [CallDebugger],
SpyClient USING [StartSpy, StopSpy],
System USING [GetClockPulses, Microseconds, Pulses, PulsesToMicroseconds],
Time USING [Append, Current, Unpack],
TTY USING [
Create, Destroy, GetLine, Handle, LineOverflow,
NumberFormat, PutChar, PutCR, PutDecimal, PutLine,
PutLongDecimal, PutLongNumber, PutString, Rubout,
ResetUserAbort, UserAbort ];
LupineTimeTestDriver: PROGRAM
IMPORTS
TimeTest: LupineTimeTest, Heap, Process, Runtime,
SpyClient, ShortString: String, System, Time, TTY
= BEGIN
-- Compiletime parameters:
StandardNumberOfTrials: INTEGER = 1;
StandardIterationsPerTrial: INTEGER = 3000;
-- Runtime parameters:
TestParameters: TYPE = MACHINE DEPENDENT RECORD [
useDoradoClock (0): BOOLEAN ← FALSE,
countOnlyEmulatorCycles (1): BOOLEAN ← FALSE,
checkResults (2): BOOLEAN ← TRUE,
trials (3): INTEGER ← StandardNumberOfTrials,
iterationsPerTrial (4): INTEGER ← StandardIterationsPerTrial,
spying (5:0..0): BOOLEAN ← FALSE,
spyOnProcs (5:1..1): BOOLEAN ← FALSE,
showSpyData (5:2..2): {afterEachTest, afterAllTests} ← afterAllTests,
filler (5:3..15): BOOLEAN ← NULL ];
DefaultTestParameters: TestParameters = [];
-- Runtime inconsistency found:
ParamsDisagree: SIGNAL = CODE; -- An echo test failed.
-- This top-level driver routine is run in a separate process.
user: TTY.Handle;
String: TYPE = STRING;
TestProcess: PROCEDURE =
BEGIN
logFileString: STRING = [100];
logFile: String ← UniqueName[
root: "LupineTimeTest"L, suffix: ".log"L,
nameString: logFileString ];
user ← TTY.Create[name: logFile];
TestRoutine[logFile: logFile ! ABORTED => CONTINUE ];
TTY.Destroy[user];
END;
UniqueName: PROCEDURE [root, suffix, nameString: String]
RETURNS [rootSuffix: String] =
BEGIN
rootSuffix ← nameString;
rootSuffix.length ← 0;
ShortString.AppendString[to: rootSuffix, from: root];
ShortString.AppendLongNumber [
s: rootSuffix, n: System.GetClockPulses[], radix: 10 ];
ShortString.AppendString[to: rootSuffix, from: suffix];
END;
-- For periodically causing glitches (eg, NIL) that Lupine claims to handle.
Periodically: PROC [testNumber: INTEGER] RETURNS [--yes:-- BOOLEAN] =
--INLINE-- {RETURN[ (testNumber MOD 31) = 0 ]};
-- Main Timing Test.
tp: TestParameters; -- Global values.
TestRoutine: PROCEDURE[logFile: String] =
BEGIN -- The entire test is in a loop.
InitPrecisionTimings;
DO ENABLE BEGIN
AbortTest => CONTINUE;
UNWIND => FinishPrecisionTimings;
END;
-- Get Test Parameters.
tp ← DefaultTestParameters;
TTY.PutCR[user];
TTY.PutLine[user, "Lupine RPC Timing Test of 24 February 1982."L];
TTY.PutString[user, "Results appear in file "L];
TTY.PutString[user, logFile]; TimeStamp[" of "L];
TTY.PutCR[user];
TTY.PutString[user, "Your options are:
D Don't check results of remote calls for correctness.
E Exclude nonemulator cycles in timings (Dorados only).
G Go (type this last).
H High precision timings (Dorados only).
P Procedure-level spying (via Copilot).
R Reset test parameters to default values.
S Spy after all tests are over.
T Spy at the conclusion of each test.
Q Quit this program immediately.
-- This line is a comment.
1-9 Perform # trials of each test.
^DEL To abort at any time."L ];
TTY.PutCR[user]; TTY.PutCR[user];
DO OPEN tp, TTY;
BEGIN
reply: STRING = [100];
PutString[user, "Type one of D,E,G,H,P,R,S,T,Q,--,1-9 [R1]: "L];
reply[0] ← 0C;
CheckAbort;
GetLine[user, reply ! Rubout, LineOverflow => GOTO TryAgain];
CheckAbort;
SELECT reply[0] FROM
'd, 'D => {checkResults ← FALSE};
'e, 'E => {useDoradoClock ← countOnlyEmulatorCycles ← TRUE};
'g, 'G => {EXIT};
'h, 'H => {useDoradoClock ← TRUE};
'p, 'P => {spying ← spyOnProcs ← TRUE};
'r, 'R => {tp ← DefaultTestParameters};
's, 'S => {spying ← TRUE; showSpyData ← afterAllTests};
't, 'T => {spying ← TRUE; showSpyData ← afterEachTest};
'q, 'Q => {GOTO QuitTestProgram};
'- => {NULL};
IN ['1..'9] => {trials ← ShortString.StringToDecimal[
reply ! ShortString.InvalidNumber => GOTO TryAgain ]};
ENDCASE => GOTO TryAgain;
EXITS
TryAgain => PutLine[user, " ???"L];
END;
ENDLOOP;
-- Call debugger as needed for spying.
IF tp.spying THEN CallSpy[
IF tp.spyOnProcs THEN startAndWatchDetails ELSE start ];
-- Eliminating timing transients before timings start.
TimeTest.Null[]; TimeTest.Null[]; TimeTest.Null[];
-- Perform testing.
NullTests;
SimpleParameterTests;
SignalTests;
SmallArrayTests;
--BigArrayTests;
-- Call debugger as needed for spying.
IF tp.spying THEN CallSpy[
(SELECT tp.showSpyData FROM
afterEachTest => stop,
afterAllTests => stopAndDisplayStats,
ENDCASE => ERROR) ];
REPEAT
QuitTestProgram => NULL;
ENDLOOP; -- Test Loop.
FinishPrecisionTimings;
END; -- TestRoutine.
NullTests: PROC =
BEGIN
-- Timing overhead.
StartTest[testName: "per call timing overhead"L, skipSpy: TRUE];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
--DelayTest;
StartPrecisionTiming;
NULL;
StopPrecisionTiming;
ENDLOOP;
ENDLOOP;
StopTest[skipSpy: TRUE];
-- Null Procedure
StartTest["the null procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
TimeTest.Null[];
StopPrecisionTiming;
ENDLOOP;
ENDLOOP;
StopTest;
END; -- NullTests.
SimpleParameterTests: PROC =
BEGIN
a,b,c,d,e,f,g,h,i,j: INTEGER;
StartTest["a 1 parameter procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
a ← TimeTest.One[test];
StopPrecisionTiming;
IF tp.checkResults AND a#test THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["a 2 parameter procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
[a,b] ← TimeTest.Two[test+0,test+1];
StopPrecisionTiming;
IF tp.checkResults AND (a#test+0 OR b#test+1) THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["a 4 parameter procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
[a,b,c,d] ← TimeTest.Four[test+0,test+1,test+2,test+3];
StopPrecisionTiming;
IF tp.checkResults AND (a#test+0 OR b#test+1 OR c#test+2 OR d#test+3)
THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["a 10 parameter procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
[a,b,c,d,e,f,g,h,i,j] ← TimeTest.Ten[
test+0,test+1,test+2,test+3,test+4,
test+5,test+6,test+7,test+8,test+9 ];
StopPrecisionTiming;
IF tp.checkResults AND
(a#test+0 OR b#test+1 OR c#test+2 OR d#test+3 OR e#test+4
OR f#test+5 OR g#test+6 OR h#test+7 OR i#test+8 OR j#test+9)
THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
END; -- SimpleParameterTests.
SignalTests: PROC =
BEGIN
out: INTEGER;
StartTest["signal test (no signalling)"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
out ← TimeTest.SignalTest[ in: test, action: neither
! TimeTest.Signal => {SIGNAL ParamsDisagree; CONTINUE} ];
StopPrecisionTiming;
IF tp.checkResults AND out#test THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["signal test (SIGNAL & RESUME)"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
out ← TimeTest.SignalTest[ in: test, action: signal
! TimeTest.Signal => {
IF tp.checkResults AND in#test THEN SIGNAL ParamsDisagree;
RESUME[out: 2*in] } ];
StopPrecisionTiming;
IF tp.checkResults AND out#2*test THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["signal test (ERROR & UNWIND)"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
out ← TimeTest.SignalTest[ in: test, action: error
! TimeTest.Signal => {
IF tp.checkResults AND in#test THEN SIGNAL ParamsDisagree;
CONTINUE } ];
StopPrecisionTiming;
--Checking is never valid after an ERROR since out is undefined.
ENDLOOP;
ENDLOOP;
StopTest;
END; -- SignalTests.
SmallArrayTests: PROC =
BEGIN
one: TimeTest.Array1 = ALL[1];
four: TimeTest.Array4 = ALL[4];
ten: TimeTest.Array10 = ALL[10];
forty: TimeTest.Array40 = ALL [40];
hundred: TimeTest.Array100 = ALL[100];
array1: TimeTest.Array1;
array4: TimeTest.Array4;
array10: TimeTest.Array10;
array40: TimeTest.Array40;
array100: TimeTest.Array100;
StartTest["1 word array procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
array1 ← TimeTest.OneArray[one];
StopPrecisionTiming;
IF tp.checkResults AND one#array1 THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["4 word array procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
array4 ← TimeTest.FourArray[four];
StopPrecisionTiming;
IF tp.checkResults AND four#array4 THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["10 word array procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
array10 ← TimeTest.TenArray[ten];
StopPrecisionTiming;
IF tp.checkResults AND ten#array10 THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["40 word array procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
array40 ← TimeTest.FortyArray[forty];
StopPrecisionTiming;
IF tp.checkResults AND forty#array40 THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["100 word array procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
array100 ← TimeTest.HundredArray[hundred];
StopPrecisionTiming;
IF tp.checkResults AND hundred#array100 THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
END; -- SmallArrayTests.
-- Primary time logging routines that use Pilot's timer.
StartTest: PROC [testName: String, skipSpy: BOOLEANLSE] =
BEGIN OPEN TTY;
CheckAbort;
PutCR[user]; PutCR[user];
PutString[user, "Timing "L]; PutDecimal[user, tp.trials];
PutString[user, " trials of "L];
PutString[user, testName]; TimeStamp[" at "L];
PreparePrecisionTimings;
IF ~skipSpy AND tp.spying THEN CallSpy[startSpy];
StartTimer[reset:TRUE];
END;
StampTest: PROC = INLINE {StopTimer; DoStampTest; StartTimer};
DoStampTest: PROC =
BEGIN OPEN TTY;
PutString[user, "Doing "L];
PutLongDecimal[user, tp.iterationsPerTrial];
TimeStamp[" calls at "L];
END;
DelayTest: PROC =
INLINE BEGIN
StopTimer;
CheckAbort;
Delay[1000];
StartTimer;
END;
StopTest: PROC [skipSpy: BOOLEANLSE] =
BEGIN OPEN TTY;
ms, tenths: LONG INTEGER;
StopTimer[];
IF ~skipSpy AND tp.spying THEN CallSpy[stopSpy];
CheckAbort;
[ms, tenths] ←
ConvertTimer[ReadTimer[].elapsed/(tp.trials*LONG[tp.iterationsPerTrial])];
PutString[user, "The average call time (any checking included) was "L];
PutLongDecimal[user, ms]; PutChar[user, '.];
PutLongDecimal[user, tenths]; TimeStamp[" ms at "L];
PrintPrecisionTimings;
IF ~skipSpy AND tp.spying AND tp.showSpyData=afterEachTest
THEN CallSpy[displayStats];
END;
TimeStamp: PROC [herald: String] =
BEGIN OPEN TTY;
timeString: STRING = [100];
CheckAbort;
Time.Append[timeString, Time.Unpack[Time.Current[]]];
PutString[user, herald];
PutString[user, timeString];
PutLine[user, "."L];
END;
AbortTest: PRIVATE ERROR = CODE;
-- Raised by CheckAbort and caught in TestRoutine.
CheckAbort: PROC =
BEGIN OPEN TTY;
IF ~UserAbort[] THEN RETURN;
ResetUserAbort;
PutCR[user];
PutLine[user, "Test aborted..."L];
ERROR AbortTest;
END;
-- Pilot Timing Routines.
SystemTime: TYPE = LONG CARDINAL; -- Same as System.Pulses.
Microseconds: TYPE = LONG CARDINAL;
ReadPilotClock: PROC RETURNS [SystemTime] =
INLINE {RETURN[ LOOPHOLE[System.GetClockPulses[]] ]};
PilotPrecisionRead: PROC RETURNS [--SystemTime-- PrecisionTime] =
INLINE { RETURN[ ReadPilotClock[] ] };
PilotPrecisionConvert: PROC [pt: --SystemTime-- PrecisionTime]
RETURNS [--microseconds:-- Microseconds] =
----INLINE---- {RETURN[ SystemTimeToUsec[pt] ]};
hrStartTime, hrEventTime, hrElapsedTime: SystemTime ← 0;
StartTimer: PROC [reset: BOOLEANLSE] =
INLINE BEGIN
IF reset THEN hrElapsedTime ← 0;
hrStartTime ← ReadPilotClock[];
END;
StopTimer: PROC =
INLINE BEGIN
hrEventTime ← ReadPilotClock[] - hrStartTime;
hrElapsedTime ← hrElapsedTime + hrEventTime;
END;
ReadTimer: PROC RETURNS [event, elapsed: SystemTime] =
----INLINE---- BEGIN
RETURN[hrEventTime, hrElapsedTime]
END;
ConvertTimer: PROC [time: SystemTime] RETURNS [ms,tenthsOfMs: LONG INTEGER] =
BEGIN
time ← (SystemTimeToUsec[time]+50)/100;
ms ← time/10;
tenthsOfMs ← time MOD 10;
END;
SystemTimeToUsec: PROC [time: SystemTime] RETURNS [Microseconds] =
INLINE BEGIN
RETURN[ System.PulsesToMicroseconds[System.Pulses[time]] ]
END;
lastDelayFinished: SystemTime ← 0;
Delay: PROC [interval: --Microseconds-- LONG INTEGER] =
-- Spin at least "interval" between executions. There is a startup glitch.
BEGIN
LastIntegerTime: SystemTime = LAST[LONG INTEGER];
DO
grossWait: SystemTime =
SystemTimeToUsec[ReadPilotClock[]-lastDelayFinished];
waitTime: LONG INTEGER =
IF grossWait < LastIntegerTime THEN grossWait ELSE LastIntegerTime;
SELECT interval-waitTime FROM
< 0 => EXIT;
< 50 => NULL;
ENDCASE => Process.Yield;
ENDLOOP;
lastDelayFinished ← ReadPilotClock[];
END;
-- Individual call high precision timing routines.
PrecisionTime: TYPE = LONG CARDINAL;
RingBufferIndex: TYPE = INTEGER[0..StandardIterationsPerTrial);
SortBufferIndex: TYPE = INTEGER[0..LAST[RingBufferIndex]+2);
RingBuffer: TYPE = ARRAY RingBufferIndex OF PrecisionTime;
SortBuffer: TYPE = ARRAY SortBufferIndex OF PrecisionTime;
ptRingIndex: RingBufferIndex ← LAST[RingBufferIndex];
ptRingBuffer: LONG DESCRIPTOR FOR RingBuffer ← DESCRIPTOR [NIL, 0];
ptSortBuffer: LONG DESCRIPTOR FOR SortBuffer ← DESCRIPTOR [NIL, 0];
ptStartTime: PrecisionTime;
StartPrecisionTiming: PROC =
INLINE BEGIN
ptStartTime ← PrecisionRead[];
END;
StopPrecisionTiming: PROC =
INLINE BEGIN
ptStopTime: PrecisionTime = PrecisionRead[];
ptRingBuffer[(ptRingIndex ← (ptRingIndex+1) MOD (LAST[RingBufferIndex]+1))]
← (ptStopTime - ptStartTime);
END;
PrecisionRead: PROC RETURNS [--pt:-- PrecisionTime] =
INLINE BEGIN
RETURN[IF tp.useDoradoClock
THEN DoradoPrecisionRead[] ELSE PilotPrecisionRead[] ];
END;
PrecisionConvert: PROC [pt: PrecisionTime]
RETURNS [--microseconds:-- Microseconds] =
----INLINE---- BEGIN
RETURN[IF tp.useDoradoClock
THEN DoradoPrecisionConvert[pt] ELSE PilotPrecisionConvert[pt] ];
END;
-- Precision timing routines.
InitPrecisionTimings: PROC =
BEGIN
-- A compiler LENGTH computation bug makes this ugly:
bufferPtr: LONG POINTER TO SortBuffer ← Heap.systemZone.NEW[SortBuffer];
ptSortBuffer ← DESCRIPTOR[bufferPtr, LENGTH[bufferPtr^]];
ptRingBuffer ← DESCRIPTOR [
@ptSortBuffer[FIRST[SortBufferIndex]+1],
LENGTH[LOOPHOLE[NIL, POINTER TO RingBuffer]^] ];
END;
FinishPrecisionTimings: PROC =
BEGIN
bufferPtr: LONG POINTER TO SortBuffer ← BASE[ptSortBuffer];
Heap.systemZone.FREE[@bufferPtr];
ptSortBuffer ← NIL;
ptRingBuffer ← NIL;
END;
PreparePrecisionTimings: PROC =
BEGIN
IF BASE[ptRingBuffer] = NIL THEN ERROR;
ptRingIndex ← LAST[RingBufferIndex];
FOR i: RingBufferIndex IN RingBufferIndex DO ptRingBuffer[i] ← 0 ENDLOOP;
IF tp.useDoradoClock THEN StartDoradoCounters[EmuCycles];
END;
PrintPrecisionTimings: PROC =
BEGIN OPEN TTY;
Range: INTEGER = 10;
PrintRange: PROC [herald: String, startIndex: RingBufferIndex] =
BEGIN
PutString[user, herald];
FOR i: RingBufferIndex IN [startIndex..startIndex+Range) DO
IF ptRingBuffer[i] > 99999
THEN PutString[user, " *****"L]
ELSE PutLongNumber[ h: user, n: ptRingBuffer[i],
format: [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 6] ];
ENDLOOP;
PutCR[user];
END; -- PrintRange.
FOR i: RingBufferIndex IN RingBufferIndex DO
ptRingBuffer[i] ← PrecisionConvert[ptRingBuffer[i]];
ENDLOOP;
QuickSort[ptSortBuffer];
PutString[user, "Some instantaneous call times (microseconds) from a "L];
PutDecimal[user, LAST[RingBufferIndex]-FIRST[RingBufferIndex]+1];
PutLine[user, " element ring buffer:"L];
PrintRange[" Fastest times:"L, FIRST[RingBufferIndex]];
PrintRange[" Median times: "L,
(LAST[RingBufferIndex]-FIRST[RingBufferIndex]-Range)/2];
PrintRange[" Slowest times:"L, LAST[RingBufferIndex]-Range];
END;
-- Dorado 64ns precision counter routines.
-- Modified from [Ivy]<McDaniel>Measurements>Measure.mesa.
doradoCounters: CounterVector ← ZeroCounterVector;
DoradoPrecisionRead: PROC RETURNS [PrecisionTime] =
INLINE BEGIN
ReadDoradoCounters[@doradoCounters];
RETURN[IF tp.countOnlyEmulatorCycles
THEN doradoCounters.A.low ELSE doradoCounters.B.low ];
END;
DoradoPrecisionConvert: PROC [pt: PrecisionTime]
RETURNS [--microseconds:-- Microseconds] =
----INLINE---- BEGIN
-- Measured clock time was 2*32.2 ns => 644/10000 = 161/2500 usec/cycle
-- Compute slowly to avoid overflow and do rounding.
RETURN[
(LONG[161]*(pt/LONG[2500]))
+ ( LONG[161]*(pt MOD LONG[2500])+LONG[2500/2] )/LONG[2500] ];
END;
StartDoradoCounters: PROCEDURE [CounterDescriptor] =
MACHINE CODE BEGIN Mopcodes.zMISC, 240B END;
ReadDoradoCounters: PROCEDURE [CounterVectorPtr] =
MACHINE CODE BEGIN Mopcodes.zMISC, 241B END;
StopDoradoCounters: PROCEDURE =
MACHINE CODE BEGIN Mopcodes.zMISC, 242B END;
CounterVector: TYPE = MACHINE DEPENDENT RECORD [
A(0): MACHINE DEPENDENT RECORD [low(0): LONG CARDINAL, high(2): CARDINAL],
B(3): MACHINE DEPENDENT RECORD [low(0): LONG CARDINAL, high(2): CARDINAL] ];
ZeroCounterVector: CounterVector = [[0,0],[0,0]];
CounterVectorPtr: TYPE = LONG POINTER TO CounterVector;
ASelection: TYPE = MACHINE DEPENDENT {
true, hold, procRef, ifuJump, miss, bpa, bpc, bpe };
BSelection: TYPE = MACHINE DEPENDENT {
true, hold, ifuRef, ifuNrdy, miss, bpb, bpc, bpd };
allA, allB, doA, doB: BOOLEAN = TRUE;
emuOnlyA, emuOnlyB, notIS: BOOLEAN = FALSE;
CounterDescriptor: TYPE = MACHINE DEPENDENT RECORD [
instrSet: BOOLEAN,
ignoreBits123: [0..7],
enableA, enableB: BOOLEAN,
ignoreBits67: [0..3],
aSelects: ASelection,
allTasksA: BOOLEAN,
bSelects: BSelection,
allTasksB: BOOLEAN ];
EmuCycles: CounterDescriptor = [notIS,0,doA,doB,0,true,emuOnlyA,true,allB];
-- This Quicksort routine is from Sedgewick's thesis.
-- It is a transliteration of [Maxc2]<Guibas>STSRT.SAI.
QuickSort: PROC [table: LONG DESCRIPTOR FOR ARRAY OF PrecisionTime] =
BEGIN
first: INTEGER = 0;
last: INTEGER = LENGTH[table]-1;
M: INTEGER = 9;
PP, L, R, I, J: INTEGER;
V, TK: PrecisionTime;
STACK: ARRAY [0..50) OF INTEGER;
--Originally: STACK: ARRAY [0:2*(LOG(256/(M+2)) DIV 1)+1] OF INTEGER;
table[first] ← FIRST[PrecisionTime]; table[last] ← LAST[PrecisionTime];
PP ← 0; L ← first+1; R ← last-1;
WHILE PP >=0 DO
I ← L; J ← R+1; V ← table[L];
WHILE I < J DO
I←I+1; WHILE table[I]<V DO I ← I+1 ENDLOOP;
J←J-1; WHILE table[J]>V DO J ← J-1 ENDLOOP;
TK←table[J]; table[J]←table[I]; table[I]←TK;
ENDLOOP;
table[I]←table[J]; table[J]←table[L]; table[L]←TK;
SELECT TRUE FROM
R-J > J-L =>
SELECT TRUE FROM
R-J <= M => NULL;
J-L <= M => {L←J+1; LOOP};
ENDCASE => BEGIN
PP←PP+2; STACK[PP]←J+1; STACK[PP+1]←R; R←J-1;
LOOP;
END;
J-L <= M => NULL;
R-J <= M => {R←J-1; LOOP};
ENDCASE => BEGIN
PP ← PP+2; STACK[PP]←L; STACK[PP+1]←J-1; L←J+1;
LOOP;
END;
L←STACK[PP];
R←STACK[PP+1];
PP←PP-2;
REPEAT
FINISHED =>
FOR I IN [2..last) DO
V←table[I]; J←I-1;
WHILE table[J]>V DO table[J+1]←table[J]; J←J-1 ENDLOOP;
table[J+1]←V;
ENDLOOP;
ENDLOOP;
END;
-- General spy routine, in the hope that the real procedural interface improves.
CallSpy: PROCEDURE[operation: {
start, startAndWatchDetails,
startSpy, stopSpy, displayStats,
stop, stopAndDisplayStats } ] =
BEGIN
SELECT operation FROM
start =>
Runtime.CallDebugger["Start Spy..."L];
startAndWatchDetails =>
Runtime.CallDebugger["Start Spy and finger specific procs..."L];
startSpy =>
SpyClient.StartSpy;
stopSpy =>
SpyClient.StopSpy;
displayStats =>
Runtime.CallDebugger["Examine Spy statistics..."L];
stop =>
Runtime.CallDebugger["Stop Spy..."L];
stopAndDisplayStats =>
Runtime.CallDebugger["Stop Spy and examine statistics..."L];
ENDCASE => ERROR;
END;
-- Module Initialization.
Process.Detach[FORK TestProcess[]];
END. -- LupineTimeTestDriver.
BigArrayTests: PROC =
BEGIN
fourHundred: TimeTest.Array400 = ALL[400];
thousand: TimeTest.Array1000 = ALL[1000];
array400: TimeTest.Array400;
array1000: TimeTest.Array1000;
StartTest["400 word array procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
array400 ← TimeTest.FourHundredArray[fourHundred];
StopPrecisionTiming;
IF tp.checkResults AND fourHundred#array400 THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
StartTest["1000 word array procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
DelayTest;
StartPrecisionTiming;
array1000 ← TimeTest.ThousandArray[thousand];
StopPrecisionTiming;
IF tp.checkResults AND thousand#array1000 THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
END; -- BigArrayTests.
-- String and array descriptor test.
Alphabet: TYPE = PACKED ARRAY [0..26) OF CHARACTER;
string1: String = "AbCdEfGhIjKlMnOpQrStUvWxYz"L;
string2: String = "12345678901234567890123456"L;
text: Alphabet;
textDescriptor: TimeTest.RESULTTextDescriptor = DESCRIPTOR[text];
StartTest["26 character string to sequence procedure"L];
THROUGH [0..tp.trials) DO
StampTest;
FOR test: INTEGER IN [0..tp.iterationsPerTrial) DO
string: String = IF test MOD 2 = 0 THEN string1 ELSE string2;
DelayTest;
StartPrecisionTiming;
TimeTest.StringDescriptor[string, textDescriptor];
StopPrecisionTiming;
IF tp.checkResults AND
LOOPHOLE[@string.text, LONG POINTER TO Alphabet]^
# LOOPHOLE[BASE[textDescriptor], LONG POINTER TO Alphabet]^
THEN SIGNAL ParamsDisagree;
ENDLOOP;
ENDLOOP;
StopTest;
Bob Hagmann February 8, 1985 5:11:08 pm PST
changes to: DIRECTORY