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-- {}; [] _ Random.Create[seed: -1]; END. -- LupineExerciserManagerImpl. CallSpy: PROCEDURE[operation: LupineExerciserPrivate.SpyOperation] = BEGIN SELECT operation FROM start => Runtime.CallDebugger["Start Spy..."L]; startAndWatchDetails => Runtime.CallDebugger["Start Spy and finger specific procs..."L]; startSpying => SpyClient.StartCounting; stopSpying => SpyClient.StopCounting; 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; InterruptControl: TYPE = RECORD [ state: {started, stopping, finished} _ finished, maxInterval, maxBusy: Process.Milliseconds ]; StartInterruptions: PROCEDURE [self: Handle] = BEGIN Interrupt: PROC [busyPulses: BasicTime.Pulses, idleTicks: Process.Ticks] = BEGIN self.interrupt.state _ started; Process.SetPriority[Process.priorityForeground]; WHILE self.interrupt.state = started DO stopSpinning: BasicTime.Pulses = GetClockPulses[] + Random.ChooseInt[min: 0, max: busyPulses]; UNTIL BasicTime.GetClockPulses[] >= stopSpinning DO ENDLOOP; Process.Pause[Random.ChooseInt[min: idleTicks/2, max: idleTicks]]; ENDLOOP; self.interrupt.state _ finished; END; Process.Detach[FORK Interrupt [ busyPulses: System.MicrosecondsToPulses[self.interruption.maxBusy], idleTicks: Process.MsecToTicks[ self.interruption.maxInterval-self.interruption.maxBusy] ]; END; StopInterruptions: PROCEDURE [self: Handle] = BEGIN self.interrupt.state _ stopping; UNTIL self.interrupt.state = finished DO Process.Pause[Process.MsecToTicks[100]]; ENDLOOP; END; φLupineExerciserManagerImpl.mesa. Copyright c 1985 by Xerox Corporation. All rights reserved. Last edited by BZM on 18-Mar-82 13:25:29. Last edited by Andrew Birrell on July 7, 1982 6:35 pm Last edited by Bob Hagmann on February 11, 1985 8:41:06 am PST SpyClient USING [DisplayData, StandardSpy, StartSpy, StopSpy, ZeroData], Exerciser instance data. Runtime inconsistency found; a parameter check failed. PerformExercises MUST be forked as a separate process!!! User interface routines. Raised by CheckAbort and caught in DoExercises. Procedural access to the spy. BEGIN OPEN SpyClient; SELECT operation FROM startAndWatchProcs, startAndWatchModules => {StandardSpy; ZeroData}; startSpying => StartSpy; stopSpying => StopSpy; displayStats, stopAndDisplayStats => {StopSpy; DisplayData[herald: "Called by LupineExerciser.", stream: NIL]}; stop => StopSpy; ENDCASE => ERROR; END; Module Initialization. Pilot/CoPilot spying interface: Cause random interruptions in RPC processes to test concurrency behavior. Κͺ˜headšœ ™ Icodešœ Οmœ1™™>—J˜J˜šΟk ˜ Jšœ žœžœ˜3Jšœžœ˜#Jšžœžœ=žœ˜UJšœžœ˜šœžœ˜J˜/J˜=J˜ —šœžœ˜J˜7J˜9—JšœH™HJšœžœ˜Jšœžœ˜!Jšœžœžœ žœ˜5šœ žœ˜%J˜J˜——šœž˜#šž˜Jšœžœ-˜AJšœ˜—Jšžœ(˜/Jšœžœžœ˜J˜J˜—Jšœ™˜Jšœžœžœ)˜