<> <> <> <> <> DIRECTORY BasicTime USING [GetClockPulses, GMT, Now, Pulses], Convert USING [Error, IntFromRope], IO USING [card, GetLineRope, int, PutChar, PutF, PutFR, PutRope, rope, STREAM, time], Loader USING [BCDBuildTime], LupineExerciser USING [ Counter, Exercise, ExerciseIndex, ExerciseList, StandardPasses, StandardTrialsPerPass, StandardTestsPerTrial, String ], LupineExerciserPrivate USING [ ExerciseHandle, ExerciseObject, FinishPrecisionTimings, InitPrecisionTimings, InitTestParameters, SpyOperation ], <> Process USING[ CheckForAbort], Random USING [ChooseInt, Create], Rope USING [InlineLength, InlineFetch, ROPE, Substr], ViewerIO USING [CreateViewerStreams]; LupineExerciserManagerImpl: PROGRAM IMPORTS BasicTime, Convert, IO, LupineExerciserPrivate, Loader, Process, RandomInt, Rope, ViewerIO EXPORTS LupineExerciser, LupineExerciserPrivate = BEGIN OPEN LupineExerciser; <> Handle: PUBLIC TYPE = LupineExerciserPrivate.ExerciseHandle; <> BadExercise: PUBLIC SIGNAL = CODE; <> PerformExercises: PUBLIC PROCEDURE [ nameOfExercisedInterface: String, exercises: ExerciseList ] = BEGIN ENABLE ABORTED => CONTINUE; logFileName: Rope.ROPE = UniqueName [ root: nameOfExercisedInterface, extension: "log" ]; inLogStream, outLogStream: IO.STREAM; LogStreamPutChar: PROC [char: CHARACTER] = {IO.PutChar[outLogStream, char]}; exerciseObject: LupineExerciserPrivate.ExerciseObject; [inLogStream, outLogStream] _ ViewerIO.CreateViewerStreams["Lupine Exerciser Manager"]; exerciseObject _ [inLogStream: inLogStream, outLogStream: outLogStream]; DoExercises[ self: @exerciseObject, exerciseName: nameOfExercisedInterface, logFileName: logFileName, exercises: exercises ! ABORTED => CONTINUE ]; END; DoExercises: PROCEDURE [ self: Handle, exerciseName, logFileName: String, exercises: ExerciseList ] = BEGIN DO OPEN tp: self.tp; ENABLE { QuitExercises => EXIT; AbortExercises => CONTINUE }; pass: Counter; numExercises: ExerciseIndex = LENGTH[exercises]; EstablishTestParameters[self, exerciseName, logFileName]; IF tp.spying THEN CallSpy[self, IF tp.spyOnProcs THEN startAndWatchProcs ELSE startAndWatchModules ]; FOR pass IN [1..tp.passes] DO self.outLogStream.PutF["\n\nStarting pass %g of %g...\n", IO.int[pass], IO.int[tp.passes]]; FOR exerciseMarch: ExerciseIndex IN [0..numExercises) DO exercise: ExerciseIndex; IF tp.testRandomly THEN BEGIN OPEN Random; exercise _ ChooseInt[min: 0, max: numExercises-1]; tp.trialsPerPass _ ChooseInt[min: 1, max: MAX[1,tp.maxTrialsPerPass] ]; tp.testsPerTrial _ ChooseInt[min: 0, max: tp.maxTestsPerTrial]; END ELSE BEGIN exercise _ exerciseMarch; tp.trialsPerPass _ tp.maxTrialsPerPass; tp.testsPerTrial _ tp.maxTestsPerTrial; END; LupineExerciserPrivate.InitPrecisionTimings[self]; exercises[exercise].routine[ exerciser: self, name: exercises[exercise].name, trials: tp.trialsPerPass, testsPerTrial: tp.testsPerTrial, checkResults: tp.checkResults ! UNWIND => LupineExerciserPrivate.FinishPrecisionTimings[self] ]; LupineExerciserPrivate.FinishPrecisionTimings[self]; ENDLOOP; ENDLOOP; IF tp.spying THEN CallSpy[self, (SELECT tp.showSpyData FROM afterEachTest => stop, afterAllTests => stopAndDisplayStats, ENDCASE => ERROR) ]; ENDLOOP; END; <> QuitExercises: PRIVATE ERROR = CODE; EstablishTestParameters: PROCEDURE [ self: Handle, exerciseName, logFileName: String ] = BEGIN now: BasicTime.GMT _ BasicTime.Now[]; built: BasicTime.GMT _ Loader.BCDBuildTime[]; self.tp _ LupineExerciserPrivate.InitTestParameters; self.outLogStream.PutF["\nLupine RPC Exerciser of %g on %g.\nStarting %g exercise; the log is %g.\n\n", IO.time[built], IO.time[now], IO.rope[exerciseName], IO.rope[logFileName]]; DO OPEN tp: self.tp; BEGIN ENABLE Convert.Error => GOTO TryAgain; GetCount: PROC RETURNS [Counter] = INLINE {RETURN[Convert.IntFromRope[reply.Substr[start: 1]]]}; reply: Rope.ROPE _ NIL; self.outLogStream.PutRope[">>"]; CheckAbort[self]; reply _ self.inLogStream.GetLineRope[]; CheckAbort[self]; IF reply.InlineLength[] > 0 THEN SELECT reply.InlineFetch[0] FROM 'd, 'D => {tp.checkResults _ FALSE}; 'e, 'E => {tp.useDoradoClock _ tp.countOnlyEmulatorCycles _ TRUE}; 'f, 'F => {tp _ LupineExerciserPrivate.InitTestParameters}; 'g, 'G => {EXIT}; 'h, 'H => {tp.useDoradoClock _ TRUE}; 'm, 'M => {tp.spying _ TRUE; tp.spyOnProcs _ FALSE}; 'p, 'P => {tp.passes _ GetCount[]}; 'o, 'O => {tp.maxTrialsPerPass _ GetCount[]}; 't, 'T => {tp.maxTestsPerTrial _ GetCount[]}; 'r, 'R => {tp.testRandomly _ TRUE}; 's, 'S => {tp.spying _ TRUE; tp.showSpyData _ afterAllTests}; 'x, 'x => {tp.spying _ TRUE; tp.showSpyData _ afterEachTest}; 'q, 'Q => {ERROR QuitExercises}; '- => {NULL}; '? => {TypeHelp[self]}; ENDCASE => GOTO TryAgain; EXITS TryAgain => self.outLogStream.PutRope["???\n"] END; ENDLOOP; END; TypeHelp: PROCEDURE [self: Handle] = BEGIN self.outLogStream.PutRope[" The exerciser options are: D Don't check results of remote calls for correctness. E Exclude nonemulator cycles in timings (Dorados only). F Flush and start over. G Go (type this last). H High precision timings (Dorados only). M Module-level (coarse) spying. Pn Number of passes of entire exercise. On Number of trials of each pass. Tn Number of tests (eg, calls) per trial. R Choose trials, tests, and exercises randomly. S Spy after all passes are over. X Spy at the exit of each trial. Q Quit this program immediately. ? Type this explanation. ^DEL To abort at any time. The default options are P1 Q1 R2000 G.\n\n" ]; END; AbortExercises: PRIVATE ERROR = CODE; <> CheckAbort: PUBLIC PROC [self: Handle] = BEGIN Process.CheckForAbort[! ABORTED => { self.outLogStream.PutRope["\nTest aborted...\n\n"]; ERROR AbortExercises; }; ]; END; UniqueName: PROCEDURE [root, extension: String] RETURNS [rootSuffix: String] = INLINE BEGIN pulses: BasicTime.Pulses _ BasicTime.GetClockPulses[]; rootSuffix _ IO.PutFR["%g.%g.%g", IO.rope[root], IO.card[pulses], IO.rope[extension]]; END; <> CallSpy: PUBLIC PROCEDURE [ self: Handle, operation: LupineExerciserPrivate.SpyOperation ] = --TEMP, until spy converts to 3.2-- {}; <> <