<> <> <> DIRECTORY Basics, BasicTime USING [GetClockPulses, GMT, Now, Pulses, PulsesToMicroseconds], CedarProcess USING [SetPriority], Commander USING [CommandProc, Register], FS USING [StreamOpen], IO USING [Close, Flush, PutChar, Put, PutF, PutRope, STREAM], PrincOps, PrincOpsUtils, Process USING [Detach, MsecToTicks, Pause, Yield], Random, Real USING [FixI], Rope, SafeStorage USING [ReclaimCollectibleObjects, SetCollectionInterval, WaitForCollectorDone], ViewerIO USING [CreateViewerStreams], VMStatistics USING [pageFaults]; GoodTimes: CEDAR MONITOR IMPORTS BasicTime, Commander, CedarProcess, FS, IO, PrincOpsUtils, Process, Random, Real, Rope, SafeStorage, ViewerIO, VMStatistics SHARES Rope = BEGIN CARD: TYPE = LONG CARDINAL; Microseconds: TYPE = LONG CARDINAL; PTR: TYPE = LONG POINTER; Pulses: TYPE = BasicTime.Pulses; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; NewInlineFetch: PROC [base: ROPE, index: INT] RETURNS [c: CHAR] = TRUSTED INLINE { IF base # NIL THEN { first: CARDINAL _ LOOPHOLE[base, LONG POINTER TO CARDINAL]^; IF first <= 100000B THEN RETURN [QFX[base, index, first]]}; RETURN [Rope.Fetch[base, index]]; }; QFX: PROC [base: ROPE, index: CARDINAL, bound: CARDINAL] RETURNS [CHAR] = TRUSTED MACHINE CODE { PrincOps.zBNDCK; PrincOps.zRSTRL, 4; }; pause: INTEGER _ 0; faults: INT _ 0; pi: REAL _ 3.14159; int: INT _ 31416; card: CARD _ 31416; cardinal: CARDINAL _ 31416; stream: IO.STREAM _ NIL; WritePageMark: PROC = TRUSTED { WriteChar[14C]; WriteChar[15C]; IO.Flush[stream]; }; WriteChar: PROC [c: CHAR] = TRUSTED { IO.PutChar[stream, c]; IF abort THEN {IO.Flush[stream]; ERROR ABORTED}; }; WriteRope: PROC [r: ROPE] = TRUSTED { IF r # NIL THEN { IO.PutRope[stream, r]; }; IF abort THEN {IO.Flush[stream]; ERROR ABORTED}; }; WriteDecimal: PROC [x: INT] = { IO.Put[stream, [integer[x]]]; }; WriteReal: PROC [x: REAL] = { IO.Put[stream, [real[x]]]; }; WriteLine: PROC [s: ROPE] = TRUSTED { WriteRope[s]; WriteChar[15C]; }; Put: PROC [c: CHAR] RETURNS [BOOL] = TRUSTED { IF c = '" THEN WriteChar['\\]; WriteChar[c]; RETURN [FALSE]; }; WriteRopeLit: PROC [r: ROPE] = TRUSTED { WriteChar['"]; WriteRope[r]; WriteChar['"]; }; FillData: TYPE = RECORD [c: CHAR]; FetchProc: Rope.FetchType = { WITH data SELECT FROM rf: REF FillData => RETURN [rf.c]; ENDCASE => ERROR}; MakeFill: PROC [fill: CHAR, size: INT] RETURNS [ROPE] = { RETURN [Rope.MakeRope[NEW[FillData _ [fill]], size, FetchProc]]; }; NullOuterProc: PROC = {}; Pong: ENTRY PROC = { CedarProcess.SetPriority[excited]; DO SELECT pingPong FROM ping => {pingPong _ pong; BROADCAST Paddle}; pong => WAIT Paddle; ENDCASE; ENDLOOP; }; Ping: ENTRY PROC = { pingPong _ ping; WHILE pingPong = ping DO BROADCAST Paddle; WAIT Paddle; ENDLOOP; }; PingPong: TYPE = {ping, pong}; pingPong: PingPong _ pong; Paddle: CONDITION; PongProcess: PROCESS _ NIL; WaitForDetachedDone: PROC [p: PROCESS] = TRUSTED { ProcState: PROC [psbh: PrincOps.PsbHandle] RETURNS [PrincOps.ProcessState] = TRUSTED INLINE { RETURN[PrincOps.PDA[psbh].flags.processState]; }; psbh: PrincOps.PsbHandle = PrincOpsUtils.PsbIndexToHandle[PrincOpsUtils.ProcessToPsbIndex[p]]; THROUGH [0..100) DO SELECT ProcState[psbh].state FROM frameTaken, dead => RETURN; ENDCASE => Process.Yield[] ENDLOOP; }; ItsShowTime: PROC [lastMark: Microseconds, msg: ROPE, lead: ROPE _ NIL, useCR: BOOL _ TRUE] = TRUSTED { delta: Microseconds _ GetMark[] - lastMark; places: CARDINAL _ SELECT delta FROM < 100 => 6, < 1000 => 5, < 10000 => 4, < 100000 => 3, < 1000000 => 2, ENDCASE => 1; IF lead # NIL THEN WriteRope[lead]; WriteReal[delta / 1E6]; WriteRope[" secs "]; faults _ VMStatistics.pageFaults - faults; IF faults # 0 THEN { WriteRope["("]; WriteDecimal[faults]; IF faults = 1 THEN WriteRope[" fault) "] ELSE WriteRope[" faults) "]}; WriteRope[msg]; IF useCR THEN WriteChar[15C]; faults _ VMStatistics.pageFaults; }; offset: Microseconds _ 0; lastDelta: Microseconds _ 0; RandomRange: PROC [r: ROPE] RETURNS [start,len: INT] = { size: INT _ r.Size[]; start _ Random.ChooseInt[rs, 0, size]; len _ Random.ChooseInt[rs, 0, size]; }; ShowNumber: PROC [str: ROPE, number: INT] = { WriteRope[str]; WriteDecimal[number]; }; ShowGC: PROC = { gcMark: Microseconds _ 0; delta: Microseconds _ 0; afterObjs,afterWords: LONG INTEGER _ 0; gcMark _ GetMark[]; IF useTraceAndSweep THEN { [] _ SafeStorage.ReclaimCollectibleObjects[FALSE, TRUE]; [incarnation: , reason: , wordsReclaimed: afterWords, objectsReclaimed: afterObjs] _ SafeStorage.WaitForCollectorDone[]; delta _ GetMark[] - gcMark; ItsShowTime[gcMark, "to collect (trace and sweep)", " "]} ELSE { [] _ SafeStorage.ReclaimCollectibleObjects[FALSE, FALSE]; [incarnation: , reason: , wordsReclaimed: afterWords, objectsReclaimed: afterObjs] _ SafeStorage.WaitForCollectorDone[]; delta _ GetMark[] - gcMark; ItsShowTime[gcMark, "to collect (normal)", " "]}; ShowNumber[" objs collected: ", afterObjs]; ShowNumber[", words collected: ", afterWords]; WriteChar[15C]; IF afterObjs > 0 THEN { adj: INT _ afterWords + afterObjs/2; ShowNumber[" words/obj: ", adj/afterObjs]; IF afterObjs > 0 THEN ShowNumber[", usecs/obj: ", delta/afterObjs]; IF afterObjs > 0 THEN ShowNumber[", usecs/word: ", delta/afterWords]; WriteChar[15C]}; WriteChar[15C]; }; ShowCurrentTime: PROC = TRUSTED { IO.PutF[stream, "At the time, the tone will be %g\n", [time[BasicTime.Now[]]]]; }; GetMark: PROC RETURNS [Microseconds] = TRUSTED { RETURN [BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[]]]; }; startTime: BasicTime.GMT; SetStartTime: PROC = TRUSTED { startTime _ BasicTime.Now[]; }; ShowStartTime: PROC = TRUSTED { IO.PutF[stream, "This test started at %g\n", [time[BasicTime.Now[]]]]; }; AppendString: PROC [dst,src: LONG STRING] = TRUSTED { pos: CARDINAL = dst.length; IF src = NIL THEN RETURN; FOR i: CARDINAL IN [0..src.length) DO dst[i+pos] _ src[i]; ENDLOOP; dst.length _ pos + dst.length; }; NullAction: PROC [c: CHAR] RETURNS [BOOL] = {RETURN [FALSE]}; NullProc: PROC = {}; nullProc: PROC _ NullProc; NullEntryProc: ENTRY PROC = {}; nullEntryProc: PROC _ NullEntryProc; dummyREF: REF _ NIL; dummyPtr: LONG POINTER _ NIL; Dummy: TYPE = RECORD [a,b: INT]; DummyLink: TYPE = RECORD[next: Link _ NIL, a,b: CARDINAL]; Link: TYPE = LONG POINTER TO DummyLink; sky: Sky _ Sky[red[4]]; dummyREF1: ROPE _ "dummyREF1"; dummyREF2: ROPE _ "dummyREF2"; dummyPtr1: Link _ LOOPHOLE[dummyREF1]; Sky: TYPE = RECORD [opt: SELECT tag: * FROM red => [red: INT], blue => [blue: INT] ENDCASE]; RandomPiece: PROC [size: NAT] RETURNS [ROPE] = TRUSTED { fill: PROC RETURNS [CHAR] = TRUSTED { nat: NAT _ Random.ChooseInt[rs, 40B, 'z-0C]; RETURN [nat + 0C]}; RETURN [Rope.FromProc[Random.ChooseInt[rs, 1, size], fill]]; }; RandomRope: PROC [maxTotal: NAT _ 0, maxPiece: NAT _ 0] RETURNS [ROPE] = TRUSTED { IF maxTotal = 0 THEN maxTotal _ Random.ChooseInt[rs, 1, 1000]; IF maxPiece = 0 OR maxPiece > maxTotal THEN maxPiece _ maxTotal; {size: NAT _ Random.ChooseInt[rs, 1, maxTotal]; ref: ROPE _ RandomPiece[maxPiece]; DO rsize: INT _ Rope.Size[ref]; IF rsize >= size THEN { ref _ Rope.Substr[ref, Random.ChooseInt[rs, 0, size/2], size]; RETURN [ref]}; IF rsize > 0 THEN rsize _ rsize - 1; ref _ Rope.Replace[ref, Random.ChooseInt[rs, 0, rsize], Random.ChooseInt[rs, 0, rsize/2], RandomPiece[maxPiece]]; ENDLOOP}; }; CheckReplace: PROC [x: ROPE, start: INT, len: INT, y: ROPE] = TRUSTED { size: INT _ Rope.Size[x]; pos: INT _ start + len; IF start > size THEN start _ size; IF pos < start THEN pos _ start; IF pos > size THEN pos _ size; { left: ROPE _ Rope.Replace[x, start, len, y]; r1: ROPE _ Rope.Substr[x, 0, start]; r2: ROPE _ y; r3: ROPE _ Rope.Substr[x, pos]; c1: ROPE _ Rope.Concat[r1, r2]; right: ROPE _ Rope.Concat[c1, r3]; IF NOT Rope.Equal[left, right] THEN SIGNAL CheckReplaceFailed }; [] _ Rope.VerifyStructure[x]; }; CheckReplaceFailed: SIGNAL = CODE; CauseError: PROC = {ERROR MyError}; MyError: ERROR = CODE; maxBestIndex: NAT = 64; best: ARRAY [0..maxBestIndex] OF REAL _ ALL[0.0]; GopherIt: PROC = TRUSTED { head: LONG STRING _ "Starting major loop ..."; header: ROPE _ "Starting major loop ..."; headSize: CARDINAL _ head.length; dummy: REF _ NIL; start: INT _ 0; c: CHAR _ 0C; operationIndex: NAT _ 0; str: STRING _ [20]; mark: Pulses _ BasicTime.GetClockPulses[]; InitMark: PROC = TRUSTED { mark _ BasicTime.GetClockPulses[]; faults _ VMStatistics.pageFaults; }; TestOne: PROC [inner: PROC, operations: INT _ 100, dummyProcVar: PROC _ NIL] RETURNS [timePerOperation: REAL _ 0.0] = TRUSTED { elapsed: Microseconds _ 0; overhead: Microseconds _ 0; temp: Pulses _ 0; divisor: REAL _ 1.0; IF dummyProcVar = NIL THEN dummyProcVar _ dummyProc; <> IO.Flush[stream]; <> dummyProcVar[]; inner[]; <> CedarProcess.SetPriority[excited]; WHILE elapsed < 1000 DO divisor _ operations; <> dummyProcVar[]; dummyProcVar[]; <> temp _ BasicTime.GetClockPulses[]; temp _ BasicTime.GetClockPulses[]; FOR i: INT IN [0..operations) DO dummyProcVar[]; ENDLOOP; temp _ BasicTime.GetClockPulses[] - temp; overhead _ BasicTime.PulsesToMicroseconds[temp]; <> IF operations > 3 THEN { inner[]; -- do once to get some 1st-time effects over inner[]}; -- do once more to get some 2nd-time effects over temp _ BasicTime.GetClockPulses[]; temp _ BasicTime.GetClockPulses[]; FOR i: INT IN [0..operations) DO inner[]; ENDLOOP; temp _ BasicTime.GetClockPulses[] - temp; elapsed _ BasicTime.PulsesToMicroseconds[temp]; IF elapsed > overhead THEN elapsed _ elapsed - overhead ELSE elapsed _ 0; IF operations > 10000 AND elapsed = 0 THEN ERROR; <> operations _ operations * 10; ENDLOOP; <> CedarProcess.SetPriority[normal]; timePerOperation _ LOOPHOLE[elapsed, INT]; timePerOperation _ timePerOperation / divisor; }; Report: PROC [inner: PROC, msg: ROPE, operations: INT _ 100, dummyProcVar: PROC _ NIL] = TRUSTED { faults: INT _ VMStatistics.pageFaults; timePerOperation: REAL _ TestOne[inner, operations, dummyProcVar]; bestTime: REAL _ best[operationIndex]; IF bestTime > timePerOperation THEN best[operationIndex] _ bestTime _ timePerOperation; operationIndex _ operationIndex + 1; faults _ VMStatistics.pageFaults - faults; WriteRope[" "]; WriteReal[timePerOperation]; WriteRope[" usecs ["]; WriteReal[bestTime]; WriteRope["] "]; IF faults > 0 THEN { WriteRope[" ("]; WriteDecimal[faults]; IF faults = 1 THEN WriteRope[" fault) "] ELSE WriteRope[" faults) "]}; WriteLine[msg]; }; dummyProc: PROC = TRUSTED {i: INT _ int; {}}; -- one up-level access dummyProc0: PROC = TRUSTED {}; -- really nothing!!! innerBool1: PROC = TRUSTED { b: BOOL _ TRUE; IF b THEN {b _ TRUE}; }; innerBool2: PROC = TRUSTED { b: BOOL _ FALSE; IF b THEN {b _ TRUE}; }; innerNarrow: PROC = TRUSTED { ref: REF _ header; r: ROPE _ NARROW[ref]; }; innerRefSelect1: PROC = TRUSTED { ref: REF _ header; WITH ref SELECT FROM x: ROPE => {}; ENDCASE => ERROR; }; innerRefSelect2: PROC = TRUSTED { ref: REF _ header; WITH ref SELECT FROM a: ATOM => {}; x: ROPE => {}; ENDCASE => ERROR; }; innerRefSelect3: PROC = TRUSTED { ref: REF _ header; WITH ref SELECT FROM a: ATOM => {}; l: LIST OF REF => {}; x: ROPE => {}; ENDCASE => ERROR; }; innerVariantSelect: PROC = TRUSTED { ptr: LONG POINTER TO Sky _ @sky; WITH x: ptr SELECT FROM red => {}; ENDCASE => ERROR; }; dummyStringFetch: PROC = TRUSTED { str: LONG STRING _ head; index: CARDINAL _ start; -- to allow for narrowing c _ 0C}; innerStringFetch: PROC = TRUSTED { c _ head[start]; }; innerRopeInlineFetch: PROC = TRUSTED { c _ Rope.InlineFetch[header, start]; }; innerNewInlineFetch: PROC = TRUSTED { c _ NewInlineFetch[header, start]; }; innerRopeFetch: PROC = TRUSTED { c _ Rope.Fetch[header, start]; }; innerRopeLength: PROC = TRUSTED { [] _ Rope.Length[header]; }; innerNew: PROC = TRUSTED { dummyREF _ NEW[Dummy]; }; innerDoublePointerAssign: PROC = TRUSTED { dummyPtr _ dummyPtr1; dummyPtr _ NIL; }; innerDoubleRefAssign: PROC = TRUSTED { dummyREF _ dummyREF1; dummyREF _ NIL; }; innerDoubleRefAssign2: PROC = TRUSTED { dummyREF _ dummyREF1; dummyREF _ dummyREF2; }; innerAppendString: PROC = TRUSTED { str.length _ 2; AppendString[str, "bb"]; }; innerRopeConcat: PROC = TRUSTED { [] _ Rope.Concat["aa", "bb"]; }; dummyCardinalAdd: PROC = TRUSTED { card: CARDINAL _ cardinal; card _ cardinal; }; innerCardinalAdd: PROC = TRUSTED { card: CARDINAL _ cardinal; card _ card + cardinal; }; innerCardinalMult: PROC = TRUSTED { card: CARDINAL _ cardinal; card _ card * cardinal; }; innerCardinalDiv: PROC = TRUSTED { card: CARDINAL _ cardinal; card _ cardinal / 100; }; dummyIntAdd: PROC = TRUSTED { li: INT _ int; li _ int; }; innerIntAdd: PROC = TRUSTED { li: INT _ int; li _ li + int; }; innerIntMult: PROC = TRUSTED { li: INT _ int; li _ li * int; }; innerIntDiv: PROC = TRUSTED { li: INT _ int; li _ li / 100; }; dummyCardAdd: PROC = TRUSTED { r: CARD _ card; r _ card; }; innerCardAdd: PROC = TRUSTED { r: CARD _ card; r _ card + card; }; innerCardMult: PROC = TRUSTED { r: CARD _ card; r _ card * card; }; innerCardDiv: PROC = TRUSTED { r: CARD _ card; r _ card / 100; }; dummyRealAdd: PROC = TRUSTED { r: REAL _ pi; r _ pi; }; innerRealAdd: PROC = TRUSTED { r: REAL _ pi; r _ pi + pi; }; innerRealMult: PROC = TRUSTED { r: REAL _ pi; r _ pi * pi; }; innerRealDiv: PROC = TRUSTED { r: REAL _ pi; r _ pi / 100.0; }; innerFix: PROC = TRUSTED { li: INT _ Real.FixI[pi]; }; innerFloat: PROC = TRUSTED { r: REAL _ int; }; innerNullProc: PROC = TRUSTED { NullProc[]; }; innerNullProcVar: PROC = TRUSTED { nullProc[]; }; innerNullEntryProc: PROC = TRUSTED { NullEntryProc[]; }; innerNullEntryProcVar: PROC = TRUSTED { nullEntryProc[]; }; innerProcAndCatch: PROC = TRUSTED { CauseError[! MyError => CONTINUE]; }; innerRandom: PROC = TRUSTED { [] _ Random.ChooseInt[rs, 0, 1000]; }; innerWriteToFile: PROC = TRUSTED { st: IO.STREAM _ FS.StreamOpen["GoodTimes.test", create]; FOR i: NAT IN [0..1000) DO j: CARDINAL _ i MOD headSize; IO.PutChar[st, 15C]; ENDLOOP; IO.Close[st]; }; innerYield: PROC = TRUSTED { Process.Yield[]; }; innerPause: PROC = TRUSTED { Process.Pause[1]; }; innerDetach: PROC = TRUSTED { p: PROCESS _ FORK NullOuterProc[]; Process.Detach[p]; Process.Yield[]; WaitForDetachedDone[p]; }; innerForkJoin: PROC = TRUSTED { JOIN (FORK NullOuterProc[]); }; innerPingPong: PROC = TRUSTED { Ping[]; }; <> Report[innerBool1, "{b: BOOL _ TRUE; IF b THEN {b _ TRUE}}", 1000, dummyProc0]; Report[innerBool2, "{b: BOOL _ FALSE; IF b THEN {b _ TRUE}}", 1000, dummyProc0]; Report[innerNarrow, "NARROW", 1000]; Report[innerRefSelect1, "REF SELECT", 1000]; Report[innerRefSelect2, "REF SELECT (2nd case)", 1000]; Report[innerRefSelect3, "REF SELECT (3rd case)", 1000]; Report[innerVariantSelect, "variant record SELECT", 1000]; Report[innerStringFetch, "LONG STRING fetch", 1000, dummyStringFetch]; Report[innerRopeInlineFetch, "Rope.InlineFetch (flat rope)", 1000, dummyStringFetch]; Report[innerNewInlineFetch, "NewInlineFetch (flat rope)", 1000, dummyStringFetch]; Report[innerRopeFetch, "Rope.Fetch (flat rope)", 1000, dummyStringFetch]; Report[innerRopeLength, "Rope.Length (flat rope)", 1000]; Report[innerNew, "NEW (4-word object)"]; Report[innerDoublePointerAssign, "double long pointer assign (g1 _ g2; g1 _ NIL)", 10000, dummyProc0]; Report[innerDoubleRefAssign, "double AssignRefs (g1 _ g2; g1 _ NIL)", 1000, dummyProc0]; Report[innerDoubleRefAssign2, "double AssignRefs (g1 _ g2; g1 _ g3)", 1000, dummyProc0]; Report[innerAppendString, "AppendString[str, 'bb'] (str = 'aa')"]; Report[innerRopeConcat, "Rope.Concat['aa', 'bb']"]; Report[innerCardinalAdd, "CARDINAL add (card _ 31416 + 31416)", 10000, dummyCardinalAdd]; Report[innerCardinalMult, "CARDINAL multiply (card _ 31416 * 31416)", 10000, dummyCardinalAdd]; Report[innerCardinalDiv, "CARDINAL divide (card _ 31416 / 100)", 10000, dummyCardinalAdd]; Report[innerIntAdd, "INT add (li _ 31416 + 31416)", 1000, dummyIntAdd]; Report[innerIntMult, "INT multiply (li _ 31416 * 31416)", 1000, dummyIntAdd]; Report[innerIntDiv, "INT divide (li _ 31416 / 100)", 1000, dummyIntAdd]; Report[innerCardAdd, "CARD add (lc _ 31416 + 31416)", 1000, dummyCardAdd]; Report[innerCardMult, "CARD multiply (lc _ 31416 * 31416)", 1000, dummyCardAdd]; Report[innerCardDiv, "CARD divide (lc _ 31416 / 1000)", 1000, dummyCardAdd]; Report[innerRealAdd, "REAL add (li _ 3.1416 + 3.1416)", 1000, dummyRealAdd]; Report[innerRealMult, "REAL multiply (li _ 3.1416 * 3.1416)", 1000, dummyRealAdd]; Report[innerRealDiv, "REAL divide (li _ 3.1416 / 100.0)", 1000, dummyRealAdd]; Report[innerFix, "INT _ REAL", 1000, dummyRealAdd]; Report[innerFloat, "REAL _ INT", 1000, dummyRealAdd]; Report[innerNullProc, "local proc call", 1000, dummyProc0]; Report[innerNullProcVar, "local proc var call", 1000, dummyProc0]; Report[innerNullEntryProc, "local ENTRY proc call", 1000, dummyProc0]; Report[innerNullEntryProcVar, "local ENTRY proc var call", 1000, dummyProc0]; Report[innerProcAndCatch, "proc call & caught ERROR", 100, dummyProc0]; Report[innerRandom, "[] _ Random.ChooseInt[rs, 0, 1000]", 100, dummyProc0]; Report[innerWriteToFile, "for FileIO.Open, 1000 IO.PutChars, IO.Close", 10]; Report[innerYield, "for Process.Yield[]", 100]; Report[innerPause, "for Process.Pause[1]", 10]; Report[innerPingPong, "for Ping-Pong process communication", 100]; Report[innerForkJoin, "for JOIN FORK NullOuterProc[...]", 100]; Report[innerDetach, "for Process.Detach[...]", 100]; WriteRope["Checking consistency of Rope operations... "]; {-- perform some random consistency checks on ropes last: ROPE _ NIL; localMark: Microseconds _ GetMark[]; offset _ 0; FOR i: NAT IN [0..100) DO ref: ROPE _ RandomRope[100, 40]; size: INT _ ref.Size[]; start: INT _ Random.ChooseInt[rs, 0,size]; len: INT _ Random.ChooseInt[rs, 0,size]; rep: ROPE _ Rope.Substr[ref, Random.ChooseInt[rs, 0,size], Random.ChooseInt[rs, 0,size]]; ref _ Rope.Replace[ref, start, len, rep]; CheckReplace[ref, start, len, rep]; last _ ref; ENDLOOP; ItsShowTime[localMark, "to check."]; }; ShowGC[]; <> IF showRopes THEN { WritePageMark[]; FOR i: CARDINAL IN [0..4) DO ShowNumber["Round #", i]; {base: ROPE _ Rope.Concat[header, MakeFill['$, 100]]; replSize: CARDINAL _ Random.ChooseInt[rs, 1, 6]; rep: ROPE _ MakeFill['*, replSize]; subMark: Microseconds _ GetMark[]; size: INT _ base.Size[]; FOR j: CARDINAL IN [0..10) DO start _ Random.ChooseInt[rs, 0, size]; FOR k: CARDINAL IN [0..100) DO base _ base.Replace[start, 0, rep]; size _ size + replSize; start _ start + replSize; ENDLOOP; ENDLOOP; ItsShowTime[subMark, "for 1000 insertions", ", "]; {leaves,nodes,maxDepth: INT _ 0; [leaves,nodes,maxDepth] _ base.VerifyStructure[]; ShowNumber[" size: ", size]; ShowNumber[", leaves: ", leaves]; ShowNumber[", nodes: ", nodes]; ShowNumber[", depth: ", maxDepth]; {mapTime: Microseconds _ GetMark[]; [] _ Rope.Map[base, 0, Rope.MaxLen, NullAction]; ItsShowTime[mapTime, "to map", "; "]; mapTime _ GetMark[]; base _ base.Balance[]; ItsShowTime[mapTime, "to balance", " ", FALSE]; [leaves,nodes,maxDepth] _ base.VerifyStructure[]; IF size # base.Size[] THEN ERROR; -- Balance failed! ShowNumber[", leaves: ", leaves]; ShowNumber[", nodes: ", nodes]; ShowNumber[", depth: ", maxDepth]; WriteChar[15C]}}}; ENDLOOP; ShowGC[]; }; IF swapTraceAndSweep THEN useTraceAndSweep _ NOT useTraceAndSweep; IF pause >= 0 THEN Process.Pause[Process.MsecToTicks[pause]]; }; InnerRun: PROC [majors: NAT _ 8] = TRUSTED { oldInterval: INT _ SafeStorage.SetCollectionInterval[1000000]; in: STREAM; [in,stream] _ ViewerIO.CreateViewerStreams["GoodTimes.ts", NIL, "GoodTimes.ts", FALSE]; SetStartTime[]; FOR i: NAT IN [0..maxBestIndex] DO best[i]_ 1.0E9; ENDLOOP; FOR major: NAT IN [0..majors) WHILE gopher DO WriteChar[15C]; ShowStartTime[]; ShowCurrentTime[]; WriteRope["Major loop #"]; WriteDecimal[major]; WriteChar[15C]; GopherIt[]; ShowCurrentTime[]; WritePageMark[]; ENDLOOP; IO.Close[in]; IO.Close[stream]; [] _ SafeStorage.SetCollectionInterval[oldInterval]; }; Run: PROC [majors: NAT _ 8] = { InnerRun[majors ! ABORTED => CONTINUE]; }; Test: PROC [majors: NAT _ 4, fork: BOOL _ TRUE] = TRUSTED { <> IF fork THEN Process.Detach[FORK Run[majors]] ELSE Run[majors]; }; GoodTimesCommand: Commander.CommandProc = { Test[]; }; gopher: BOOL _ TRUE; -- _ FALSE stops the test at the next clean point abort: BOOL _ FALSE; -- _ TRUE aborts the test at the next output showRopes: BOOL _ TRUE; -- used to determine rope operations printing useTraceAndSweep: BOOL _ FALSE; -- determines use of T&S collector swapTraceAndSweep: BOOL _ FALSE; -- determines alternate use of T&S rs: Random.RandomStream _ Random.Create[]; -- random # generator IF PongProcess = NIL THEN TRUSTED { Process.Detach[PongProcess _ FORK Pong[]]; }; Commander.Register["GoodTimes", GoodTimesCommand, "Some simple timing tests."]; END.