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. DGoodTimes.mesa, some simple timing tests Copyright c 1984, 1985, 1986 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) February 4, 1986 6:13:07 pm PST make sure that the IO system is pretty quiet try the initial flush of things into our cache higher priority makes our numbers somewhat sharper try to flush the dummyProc into the caches calc the overhead time calc the operation time increase the number of iterations priority is less important now... run some timing tests now try to exercise ropes and the allocator for living with others peacefully Κ˜codešœ(™(Kšœ Οmœ=™HK™3—K˜šΟk ˜ Kšœ˜Kšœ žœžœ%˜IKšœ žœ˜!Kšœ žœ˜(Kšžœžœ˜Kšžœžœ-žœ˜=Kšœ ˜ Kšœ˜Kšœžœ%˜2Kšœ˜Kšœžœ˜Kšœ˜Kšœ žœJ˜[Kšœ žœ˜%Kšœ žœ˜ —headšœ žœž˜Kšžœ%žœžœQ˜ƒKšžœ˜ Kšœž˜K˜Kšžœžœžœžœ˜Kšœžœžœžœ˜#Kšžœžœžœžœ˜Kšœžœ˜ Kšžœžœžœ˜Kšžœžœžœžœ˜K˜šΟnœžœžœ žœžœžœžœžœ˜Ršžœžœžœ˜Kš œžœžœžœžœžœžœ˜˜DK˜K˜—Kšœžœ˜šŸ œžœžœ˜Kšœ˜K˜K˜—šŸ œžœžœ˜KšžœD˜FK˜K˜—š Ÿ œžœ žœžœžœ˜5Kšœžœ˜Kšžœžœžœžœ˜šžœžœžœž˜%K˜Kšžœ˜—K˜K˜K˜—KšŸ œžœžœžœžœžœžœ˜=K˜KšŸœžœ˜Kšœ žœ ˜KšŸ œžœžœ˜Kšœžœ˜$K˜Kšœ žœžœ˜Kšœ žœžœžœ˜Kšœžœžœžœ˜ Kš œ žœžœžœžœ˜:Kš œžœžœžœžœ ˜'K˜Kšœ žœ˜Kšœ žœ˜Kšœžœ ˜&K˜šœžœžœžœž˜+Kšœ žœ˜Kšœžœ˜Kšžœ˜ K˜—š Ÿ œžœžœžœžœžœ˜8š œžœžœžœžœ˜%Kšœžœ$˜,Kšžœ ˜—Kšžœ6˜Kšžœžœžœ˜@šœžœ%˜/Kšœžœ˜"šž˜Kšœžœ˜šžœžœ˜Kšœ>˜>Kšžœ˜—Kšžœ žœ˜$˜Kšœ˜Kšœ!˜!K˜—Kšžœ˜ ——K˜K˜—šŸ œžœžœ žœžœžœžœ˜GKšœžœ˜Kšœžœ˜Kšžœžœ˜"Kšžœ žœ ˜ Kšžœ žœ ˜šœ˜Kšœžœ"˜,Kšœžœ˜$Kšœžœ˜ Kšœžœ˜Kšœžœ˜Kšœžœ˜"Kšžœžœžœžœ˜=Kšœ˜—K˜K˜K˜—Kšœžœžœ˜"K˜KšŸ œžœžœ ˜#K˜Kšœ žœžœ˜K˜Kšœžœ˜Kš œžœžœžœžœ˜1K˜šŸœžœžœ˜Kšœžœžœ˜.Kšœžœ˜)Kšœ žœ˜!Kšœžœžœ˜Kšœžœ˜Kšœžœ˜ Kšœžœ˜Kšœžœ˜Kšœ*˜*K˜šŸœžœžœ˜Kšœ"˜"Kšœ!˜!K˜K˜—šŸœžœ žœžœžœžœžœžœ žœ˜K˜K˜K˜Kšœ žœ˜K˜Kšžœžœžœ˜4K˜Kšœ2™2Kšžœ˜K˜Kšœ.™.Kšœ˜K˜K˜Kšœ2™2Kšœ"˜"K˜šžœž˜K˜K˜Kšœ*™*K˜K˜K˜Kšœ™K˜"K˜"šžœžœžœž˜ K˜Kšžœ˜—K˜)K˜0Kšœ™šžœžœ˜Kšœ Οc,˜5Kšœ  1˜;—K˜"K˜"šžœžœžœž˜ K˜Kšžœ˜—K˜)K˜/Kšžœžœžœ ˜IKšžœžœ žœžœ˜1Kšœ!™!K˜Kšžœ˜K˜—Kšœ!™!Kšœ!˜!K˜Kšœžœ žœ˜*K˜.K˜K˜—šŸœžœ žœžœžœžœžœžœžœ˜bKšœžœ˜&Kšœžœ,˜BKšœ žœ˜&Kšžœžœ4˜WK˜$Kšœ*˜*K˜/K˜<šžœ žœ˜Kšœ'˜'Kšžœ žœžœ˜F—K˜K˜K˜—Kšœ žœžœžœ  ˜DK˜Kšœ žœžœ ˜3K˜šœ žœžœ˜Kšœžœžœ˜Kšžœžœžœ˜K˜K˜—šœ žœžœ˜Kšœžœžœ˜Kšžœžœžœ˜K˜K˜—šœ žœžœ˜Kšœžœ ˜Kšœžœžœ˜K˜K˜—šœžœžœ˜!Kšœžœ ˜šžœžœž˜Kšœžœ˜Kšžœžœ˜—K˜K˜—šœžœžœ˜!Kšœžœ ˜šžœžœž˜Kšœžœ˜Kšœžœ˜Kšžœžœ˜—K˜K˜—šœžœžœ˜!Kšœžœ ˜šžœžœž˜Kšœžœ˜Kšœžœžœžœ˜Kšœžœ˜Kšžœžœ˜—K˜K˜—šœžœžœ˜$Kšœžœžœžœ ˜ šžœžœž˜K˜ Kšžœžœ˜—K˜K˜—šœžœžœ˜"Kšœžœžœ˜Kšœžœ  ˜2K˜K˜—šœžœžœ˜"K˜K˜K˜—šœžœžœ˜&K˜$K˜K˜—šœžœžœ˜%K˜"K˜K˜—šœžœžœ˜ K˜K˜K˜—šœžœžœ˜!K˜K˜K˜—šœ žœžœ˜Kšœ žœ˜K˜K˜—šœžœžœ˜*K˜Kšœ žœ˜K˜K˜—šœžœžœ˜&K˜Kšœ žœ˜K˜K˜—šœžœžœ˜'K˜Kšœ˜K˜K˜—šœžœžœ˜#K˜K˜K˜K˜—šœžœžœ˜!K˜K˜K˜—šœžœžœ˜"Kšœžœ ˜Kšœ˜K˜K˜—šœžœžœ˜"Kšœžœ ˜Kšœ˜K˜K˜—šœžœžœ˜#Kšœžœ ˜Kšœ˜K˜K˜—šœžœžœ˜"Kšœžœ ˜Kšœ˜K˜K˜—šœ žœžœ˜Kšœžœ˜K˜ K˜K˜—šœ žœžœ˜Kšœžœ˜K˜K˜K˜—šœžœžœ˜Kšœžœ˜K˜K˜K˜—šœ žœžœ˜Kšœžœ˜K˜K˜K˜—šœžœžœ˜Kšœžœ˜K˜ K˜K˜—šœžœžœ˜Kšœžœ˜K˜K˜K˜—šœžœžœ˜Kšœžœ˜K˜K˜K˜—šœžœžœ˜Kšœžœ˜K˜K˜K˜—šœžœžœ˜Kšœžœ˜ K˜K˜K˜—šœžœžœ˜Kšœžœ˜ K˜ K˜K˜—šœžœžœ˜Kšœžœ˜ K˜ K˜K˜—šœžœžœ˜Kšœžœ˜ K˜K˜K˜—šœ žœžœ˜Kšœžœ˜K˜K˜—šœ žœžœ˜Kšœžœ˜K˜K˜—šœžœžœ˜K˜ K˜K˜—šœžœžœ˜"K˜ K˜K˜—šœžœžœ˜$K˜K˜K˜—šœžœžœ˜'K˜K˜K˜—šœžœžœ˜#Kšœžœ˜"K˜K˜—šœ žœžœ˜Kšœ#˜#K˜K˜—šœžœžœ˜"Kšœžœžœžœ&˜8šžœžœžœ ž˜Kšœžœžœ ˜Kšžœ˜Kšžœ˜—Kšžœ ˜ K˜K˜—šœ žœžœ˜K˜K˜K˜—šœ žœžœ˜K˜K˜K˜—šœ žœžœ˜Kšœžœžœ˜"Kšœ˜K˜Kšœ˜K˜K˜—šœžœžœ˜Kšžœžœ˜K˜K˜—šœžœžœ˜K˜K˜K˜—Kšœ™K˜˜Kšœžœ˜ Kšœ;žœžœ˜WK˜šžœžœžœž˜"K˜Kšžœ˜—š žœžœžœ žœž˜-K˜K˜K˜K˜K˜K˜K˜ K˜K˜Kšžœ˜—Kšžœ ˜ Kšžœ˜Kšœ4˜4K˜K˜—šŸœžœ žœ ˜Kšœžœžœ˜'K˜K˜—š Ÿœžœ žœ žœžœžœ˜;Kšœ!™!šžœ˜Kšžœžœ ˜%Kšžœ ˜—K˜K˜—˜+K˜K˜K˜—Kšœžœžœ 1˜GKšœžœžœ ,˜BKšœ žœžœ -˜EKšœžœžœ "˜BKšœžœžœ "˜CKšœ+ ˜@K˜šžœžœžœžœ˜#Kšœžœ ˜*K˜K˜—K˜OK˜Kšžœ˜K˜K˜——…—QoV