DIRECTORY BasicTime, Commander, FS, IO, PFS, PFSNames, Process, Real, RealFns, RefText, RefTextExtras, Rope, TimerLoop; TimerLoopImpl: CEDAR PROGRAM IMPORTS BasicTime, Commander, FS, IO, PFS, PFSNames, Process, Real, RealFns, RefText, RefTextExtras, Rope EXPORTS TimerLoop = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Dummy: PROC = {}; Period: PROC [start, end: BasicTime.Pulses] RETURNS [diff: BasicTime.Pulses] = { diff ¬ IF end >= start THEN end - start ELSE (LAST[BasicTime.Pulses] - start) + end + 1; }; TimeByCount: PUBLIC PROC [init: PROC, doit: PROC, count: CARD] RETURNS [totalMicrosecs, initTotalMicrosecs: CARD, avgMicrosecs, initAvgMicrosecs: REAL] = { startTime, endTime: BasicTime.Pulses ¬ 0; initTotal, total, initTotal2: BasicTime.Pulses ¬ 0; x: CARD ¬ 0; floatCount: REAL ¬ count; ok: BOOL ¬ FALSE; error: REAL; UNTIL ok DO startTime ¬ BasicTime.GetClockPulses[]; FOR i: NAT IN [0..count) DO init[]; Dummy[]; ENDLOOP; endTime ¬ BasicTime.GetClockPulses[]; initTotal ¬ Period[startTime, endTime]; startTime ¬ BasicTime.GetClockPulses[]; FOR i: NAT IN [0..count) DO init[]; doit[]; ENDLOOP; endTime ¬ BasicTime.GetClockPulses[]; total ¬ Period[startTime, endTime]; startTime ¬ BasicTime.GetClockPulses[]; FOR i: NAT IN [0..count) DO init[]; Dummy[]; ENDLOOP; endTime ¬ BasicTime.GetClockPulses[]; initTotal2 ¬ Period[startTime, endTime]; error ¬ initTotal2-initTotal; IF ABS[error]/MIN[initTotal, initTotal2] < 0.05 AND total > initTotal THEN ok ¬ TRUE; ENDLOOP; total ¬ total - initTotal; totalMicrosecs ¬ BasicTime.PulsesToMicroseconds[total]; initTotalMicrosecs ¬ BasicTime.PulsesToMicroseconds[initTotal]; avgMicrosecs ¬ totalMicrosecs/floatCount; initAvgMicrosecs ¬ initTotalMicrosecs/floatCount; }; TimeForAPeriod: PUBLIC PROC [init: PROC, doit: PROC, periodMillisecs: CARD ¬ 2000] RETURNS [avgMicrosecs, initAvgMicrosecs: REAL ¬ 0.0, count, trials: CARD, worstAvg, worstInitAvg: REAL ¬ 0.0] = { totalMicrosecs: CARD; testCount: CARD = 20; testCountFloat: REAL = testCount; startTime: BasicTime.Pulses; periodPulses: BasicTime.Pulses ¬ BasicTime.MicrosecondsToPulses[periodMillisecs*1000]; now: BasicTime.Pulses; microSecsPerTrial: REAL = 5000.0; -- can the CPU stay stable for this long? microSecsPerCall: REAL; startTime ¬ BasicTime.GetClockPulses[]; [totalMicrosecs, ----, avgMicrosecs, initAvgMicrosecs] ¬ TimeByCount[init, doit, 1]; now ¬ BasicTime.GetClockPulses[]; IF Period[startTime, now] > periodPulses THEN { count ¬ 1; trials ¬ 1; RETURN; }; [totalMicrosecs, ----, avgMicrosecs, initAvgMicrosecs] ¬ TimeByCount[init, doit, testCount]; IF Period[startTime, now] > periodPulses THEN { count ¬ testCount; trials ¬ 1; RETURN; }; microSecsPerCall ¬ avgMicrosecs + 3*initAvgMicrosecs; count ¬ Real.Ceiling[microSecsPerTrial/microSecsPerCall]; -- calls per trial IF count < 10 THEN count ¬ 10; trials ¬ 0; BEGIN thisTotal: CARD; thisAvg, thisInitAvg: REAL; worstTotal: CARD; totalMicrosecs ¬ LAST[CARD]; worstTotal ¬ 0; UNTIL Period[startTime, now] > periodPulses DO [thisTotal, ----, thisAvg, thisInitAvg] ¬ TimeByCount[init, doit, count]; trials ¬ trials + 1; IF thisTotal < totalMicrosecs THEN { totalMicrosecs ¬ thisTotal; avgMicrosecs ¬ thisAvg; initAvgMicrosecs ¬ thisInitAvg; }; IF thisTotal > worstTotal THEN { worstTotal ¬ thisTotal; worstAvg ¬ thisAvg; worstInitAvg ¬ thisInitAvg; }; now ¬ BasicTime.GetClockPulses[]; ENDLOOP; END; }; ReportForAPeriod: PUBLIC PROC [f: STREAM, name: ROPE, init: PROC, doit: PROC, periodMillisecs: CARD] = { count, trials: CARD; avg, initAvg, worstAvg, worstInitAvg: REAL; Process.PauseMsec[1000]; -- allow the machine to settle [avg, initAvg, count, trials, worstAvg, worstInitAvg] ¬ TimeForAPeriod[init, doit, periodMillisecs]; f.PutRope[name]; f.PutChar[':]; f.PutChar[IO.SP]; IF Rope.Length[name] < 15 THEN { FOR i: NAT IN [0..15-Rope.Length[name]) DO f.PutChar[IO.SP]; ENDLOOP; }; f.PutFL["%4.2f avg, %4.2f worst avg over %g calls, %g trials (init: %4.2f avg)\n", LIST[[real[avg]], [real[worstAvg]], [cardinal[count]], [cardinal[trials]], [real[initAvg]]] ]; }; TimeArithmetic: Commander.CommandProc = { x: REAL ¬ 0; n: CARD ¬ 0; msec: CARD ¬ 1000; FloatAssignment: PROC = {x ¬ 3}; FloatPlus: PROC = {x ¬ x+1}; FloatPlusInit: PROC = {x ¬ 1}; FloatPlusTwice: PROC = {x ¬ x+1; x ¬ x+1}; FloatMultiply: PROC = {x ¬ x*2}; FloatMultiplyInit: PROC = {x ¬ 2}; SquareRoot: PROC = {x ¬ RealFns.SqRt[x]}; SquareRootInit: PROC = {x ¬ 2}; Assignment: PROC = {n ¬ 3}; Plus: PROC = {n ¬ n+1}; PlusInit: PROC = {n ¬ 1}; Multiply: PROC = {n ¬ n*2}; MultiplyInit: PROC = {n ¬ 2}; cmd.out.PutRope["All times in microseconds. Spending at least 1 second on each test.\n"]; ReportForAPeriod[cmd.out, "x _ 3", Dummy, FloatAssignment, msec]; ReportForAPeriod[cmd.out, "x _ x+1", FloatPlusInit, FloatPlus, msec]; ReportForAPeriod[cmd.out, "x_x+1; x_x+1", FloatPlusInit, FloatPlusTwice, msec]; ReportForAPeriod[cmd.out, "x _ x*2", FloatMultiplyInit, FloatMultiply, msec]; ReportForAPeriod[cmd.out, "x _ RealFns.SqRt[x]", SquareRootInit, SquareRoot, msec]; cmd.out.PutChar[IO.LF]; ReportForAPeriod[cmd.out, "n _ 3", Dummy, Assignment, msec]; ReportForAPeriod[cmd.out, "n _ n+1", PlusInit, Plus, msec]; ReportForAPeriod[cmd.out, "n _ n*2", MultiplyInit, Multiply, msec]; }; TimeIO: Commander.CommandProc = { msec: CARD ¬ 3000; t: REF TEXT; input: ROPE = "Hello 3.14159 34"; spaceInput: ROPE = " 3.14159 34"; s: STREAM ¬ IO.RIS[input]; spaceS: STREAM ¬ IO.RIS[spaceInput]; InitS: PROC = {IO.SetIndex[s, 0]}; InitSpaceS: PROC = {IO.SetIndex[spaceS, 0]}; GetCedarTokenRope: PROC = {[] ¬ IO.GetCedarTokenRope[s]}; GetCedarToken: PROC = {[] ¬ IO.GetCedarToken[s, t]}; SkipWhitespace: PROC = {[] ¬ IO.SkipWhitespace[s]}; cmd.out.PutRope["All times in microseconds. Spending at least 3 seconds on each test.\n"]; ReportForAPeriod[cmd.out, "GetCedarTokenRope", InitS, GetCedarTokenRope, msec]; t ¬ RefTextExtras.ObtainScratch16[]; ReportForAPeriod[cmd.out, "GetCedarToken", InitS, GetCedarToken, msec]; RefTextExtras.ReleaseScratch16[t]; ReportForAPeriod[cmd.out, "SkipWhitespace", InitSpaceS, SkipWhitespace, msec]; }; TimeRefText: Commander.CommandProc = { msec: CARD ¬ 3000; t: REF TEXT; ObtainAndRelease54: PROC = {t ¬ RefText.ObtainScratch[54]; RefText.ReleaseScratch[t]}; ObtainAndRelease100: PROC = {t ¬ RefText.ObtainScratch[100]; RefText.ReleaseScratch[t]}; ObtainAndRelease8192: PROC = {t ¬ RefText.ObtainScratch[8192]; RefText.ReleaseScratch[t]}; ObtainAndRelease8192Inline: PROC = {t ¬ RefTextExtras.ObtainScratch8192[]; RefTextExtras.ReleaseScratch8192[t]}; ObtainAndRelease8193: PROC = {t ¬ RefText.ObtainScratch[8193]; RefText.ReleaseScratch[t]}; cmd.out.PutRope["All times in microseconds. Spending at least 3 seconds on each test.\n"]; ReportForAPeriod[cmd.out, "ObtainAndRelease[54]", Dummy, ObtainAndRelease54, msec]; ReportForAPeriod[cmd.out, "ObtainAndRelease[100]", Dummy, ObtainAndRelease100, msec]; ReportForAPeriod[cmd.out, "ObtainAndRelease[8192]", Dummy, ObtainAndRelease8192, msec]; ReportForAPeriod[cmd.out, "ObtainAndRelease8192", Dummy, ObtainAndRelease8192Inline, msec]; ReportForAPeriod[cmd.out, "ObtainAndRelease[8193]", Dummy, ObtainAndRelease8193, msec]; }; filePath, fullPath: PFSNames.PATH; fileName: ROPE = "/Cedar10.1/Top/Rope.df"; fullName: ROPE; GetVersion: PROC [path: PFSNames.PATH] RETURNS [version: CARD ¬ 0] = { NullSeparator: PFSNames.SeparatorProc = {}; FindVersion: PFSNames.ComponentProc = { IF comp.version.versionKind = numeric THEN version ¬ comp.version.version; }; PFSNames.Map[path, FindVersion, NullSeparator, NIL]; }; TimeFS: Commander.CommandProc = { msec: CARD ¬ 3000; t: REF TEXT; FileInfoRemoteCheck: PROC = {[] ¬ FS.FileInfo[name: fileName]; }; FileInfo: PROC = {[] ¬ FS.FileInfo[name: fileName, remoteCheck: FALSE]; }; FileInfoVersioned: PROC = {[] ¬ FS.FileInfo[name: fullName, remoteCheck: FALSE]; }; PFSFileInfo: PROC = {[] ¬ PFS.FileInfo[name: filePath]; }; PFSFileInfoVersioned: PROC = {[] ¬ PFS.FileInfo[name: fullPath]; }; cmd.out.PutRope["All times in microseconds. Spending at least 3 seconds on each test.\n"]; ReportForAPeriod[cmd.out, "FileInfo (with remote check)", Dummy, FileInfoRemoteCheck, msec]; ReportForAPeriod[cmd.out, "FileInfo (without remote check)", Dummy, FileInfo, msec]; ReportForAPeriod[cmd.out, "FileInfo (without remote check, versioned)", Dummy, FileInfoVersioned, msec]; ReportForAPeriod[cmd.out, "PFS.FileInfo (no version)", Dummy, PFSFileInfo, msec]; ReportForAPeriod[cmd.out, "PFS.FileInfo (versioned)", Dummy, PFSFileInfoVersioned, msec]; cmd.out.PutFL["The highest version of %g is %g (FS), %g (PFS)\n", LIST[[rope[fileName]], [rope[versionRope]], [cardinal[GetVersion[fullPath]]]] ]; }; versionRope: ROPE; Init: PROC = { filePath ¬ PFS.PathFromRope[fileName]; fullPath ¬ PFS.FileInfo[filePath].fullFName; fullName ¬ FS.FileInfo[fileName].fullFName; versionRope ¬ Rope.Substr[fullName, Rope.Index[fullName, 0, "!", FALSE]]; }; Init[]; Commander.Register["TimeArithmetic", TimeArithmetic, "Runs TimerLoopImpl on arithmetic operations"]; Commander.Register["TimeIO", TimeIO, "Runs TimerLoopImpl on IO.mesa operations"]; Commander.Register["TimeRefText", TimeRefText, "Runs TimerLoopImpl on RefText.mesa and RefTextExtras.mesa operations"]; Commander.Register["TimeFS", TimeFS, "Runs TimerLoopImpl on FS.mesa"]; END. X TimerLoopImpl.mesa Copyright c 1992 by Xerox Corporation. All rights reserved. Bier, December 29, 1992 12:18 pm PST Contents: Provides an accurate estimate of the time taken by a given Cedar routine by running that routine many times and subtracting away the loop overhead. Phase 1: Phase 2: Phase 3: PROC[comp: Component, ref: REF]; Κ r•NewlineDelimiter ™code™Kšœ Οmœ1™˜VKšŸœžœ?˜XKšŸœžœ@˜ZKšŸœžœP˜pKšŸœžœ@˜ZK˜K˜[Kšœ9Ÿœ˜SKšœ:Ÿœ˜UKšœ;Ÿœ˜WKšœ9Ÿœ˜[K˜WK˜K˜—Kšœž˜"Kšœ žœœ˜*Kšœ žœ˜K˜š Ÿ œžœžœžœ žœ ˜FKšŸ œ˜+šŸ œ˜'Kšžœžœ™ Kšžœ$žœ ˜JK˜—Kšœ/žœ˜4K˜K˜—šŸœ˜!Kšœžœ˜Kšœžœžœ˜ K˜KšŸœžœ œ˜AKš Ÿœžœ žœ œžœ˜JKš Ÿœžœ žœ œžœ˜SKšŸ œžœ žœ œ˜:Kš ŸŸœžœ žžžœ œ˜CK˜K˜[KšœA œ˜\KšœD œ˜TKšœO œ˜hKšœ>Ÿ œ˜QKšœ= œ˜YK˜’K˜K˜—Kšœ žœ˜šŸœžœ˜Kšœ žœ˜&Kšœ žœœœ œ˜,Kšœ žœ˜+KšœAžœ˜IK˜—K˜K˜dK˜QK˜wK˜FK˜Kšžœ˜K˜—…—$d/.