<<>> <> <> <> <> <> <<>> DIRECTORY Atom, BasicTime, CodeTimerConcrete, Commander, IO, CodeTimer, Process, RefTab, Rope; CodeTimerImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, Commander, IO, Process, RefTab EXPORTS CodeTimer = BEGIN ProcessPair: TYPE = CodeTimerConcrete.ProcessPair; ProcessPairObj: TYPE = CodeTimerConcrete.ProcessPairObj; Table: TYPE = REF TableObj; TableObj: PUBLIC TYPE = CodeTimerConcrete.TableObj; IntervalInContext: TYPE = REF IntervalInContextObj; IntervalInContextObj: PUBLIC TYPE = CodeTimerConcrete.IntervalInContextObj; gTablesRef: RefTab.Ref; intervalPoolMax: CARD32 = 25; intervalPool: ARRAY [0..intervalPoolMax) OF IntervalInContext; intervalPoolIndex: INT32 _ -1; Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE; <> <<>> CreateIntervalInContext: PROC [intervalName: ATOM] RETURNS [intervalInContext: IntervalInContext] = { intervalInContext _ NEW[IntervalInContextObj]; intervalInContext.name _ intervalName; }; <> <= 0 THEN {>> <> <> <> <> <> <<}>> <> <<};>> <<>> AllocateIntervalInternal: INTERNAL PROC [intervalName: ATOM] RETURNS [interval: IntervalInContext] = { IF intervalPoolIndex >= 0 THEN { interval _ intervalPool[intervalPoolIndex]; ZeroInterval[interval]; interval.children _ NIL; interval.name _ intervalName; intervalPoolIndex _ intervalPoolIndex - 1; } ELSE interval _ CreateIntervalInContext[intervalName]; }; <> <> <> <> <<};>> <> <> <<};>> <<>> FreeIntervalInternal: INTERNAL PROC [interval: IntervalInContext] = { IF intervalPoolIndex < intervalPoolMax -1 THEN { intervalPoolIndex _ intervalPoolIndex + 1; intervalPool[intervalPoolIndex] _ interval; }; interval.children _ NIL; interval.parent _ NIL; }; CreateTable: PUBLIC PROC [name: ATOM _ NIL] RETURNS [table: Table] = { oldTable: Table _ GetTable[name]; IF oldTable = NIL THEN { <> table _ NEW[TableObj _ [name, NIL]]; IF name # NIL THEN AddTableToTables[table]; } ELSE { table _ oldTable; ResetTable[table]; }; }; GetTable: PUBLIC PROC [name: ATOM] RETURNS [table: Table] = { val: RefTab.Val; found: BOOL _ FALSE; [found, val] _ RefTab.Fetch[gTablesRef, name]; IF found THEN table _ NARROW[val] ELSE table _ NIL; }; AddTableToTables: PROC [table: Table] = { new: BOOL _ RefTab.Store[gTablesRef, table.name, table]; IF NOT new THEN ERROR; }; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <<};>> <> <<};>> <> <<};>> <<>> ResetTable: PUBLIC ENTRY PROC [table: Table] = { <> FOR lp: LIST OF ProcessPair _ table.processes, lp.rest UNTIL lp = NIL DO pair: ProcessPair _ lp.first; FOR list: LIST OF IntervalInContext _ pair.outer.children, list.rest UNTIL list = NIL DO FreeIntervalAndChildren[list.first]; ENDLOOP; pair.outer.children _ NIL; pair.current _ pair.outer; ENDLOOP; table.processes _ NIL; }; FreeIntervalAndChildren: INTERNAL PROC [interval: IntervalInContext] = { FOR list: LIST OF IntervalInContext _ interval.children, list.rest UNTIL list = NIL DO FreeIntervalAndChildren[list.first]; ENDLOOP; FreeIntervalInternal[interval]; }; <> <> <> <> <> <> <> <> <> <> <<};>> <<};>> <> <<};>> <> <<};>> <<>> ResetInterval: PUBLIC ENTRY PROC [intervalName: ATOM, table: Table] = { <> FOR lp: LIST OF ProcessPair _ table.processes, lp.rest UNTIL lp = NIL DO pair: ProcessPair _ lp.first; ZeroNamedIntervalInTree[intervalName, pair.outer]; ENDLOOP; }; ZeroNamedIntervalInTree: INTERNAL PROC [intervalName: ATOM, interval: IntervalInContext] = { IF interval.name = intervalName THEN ZeroInterval[interval]; FOR list: LIST OF IntervalInContext _ interval.children, list.rest UNTIL list = NIL DO ZeroNamedIntervalInTree[intervalName, list.first]; ENDLOOP; }; ZeroInterval: INTERNAL PROC [interval: IntervalInContext] = { interval.starts _ 0; interval.stops _ 0; interval.prematureStops _ 0; interval.prematureStopName _ NIL; interval.startTime _ 0; interval.totalTime _ 0; interval.maxTime _ 0; interval.minTime _ LAST[LONG CARDINAL] }; <<>> <> codeTimerOn: BOOL _ FALSE; noteThreads: BOOL _ FALSE; FindChildIntervalInContext: PROC [intervalName: ATOM, context: IntervalInContext] RETURNS [interval: IntervalInContext _ NIL] = { FOR list: LIST OF IntervalInContext _ context.children, list.rest UNTIL list = NIL DO IF list.first.name = intervalName THEN RETURN[list.first]; ENDLOOP; }; defaultProcess: PROCESS; GetPairForProcess: INTERNAL PROC [table: Table] RETURNS [pp: ProcessPair] = { IF noteThreads THEN { process: PROCESS _ Process.GetCurrent[]; FOR list: LIST OF ProcessPair _ table.processes, list.rest UNTIL list = NIL DO pair: ProcessPair _ list.first; IF pair.process = process THEN RETURN[pair]; ENDLOOP; pp _ AddProcessPair[table, process]; } ELSE { IF table.processes = NIL THEN pp _ AddProcessPair[table, defaultProcess] ELSE { pp _ table.processes.first; }; }; }; AddProcessPair: INTERNAL PROC [table: Table, process: PROCESS] RETURNS [pair: ProcessPair] = { pair _ NEW[ProcessPairObj]; pair.current _ pair.outer _ AllocateIntervalInternal[$Outer]; pair.process _ process; table.processes _ CONS[pair, table.processes]; }; StartInterval: PUBLIC ENTRY PROC [intervalName: ATOM, table: Table] = { <> ENABLE UNWIND => NULL; interval: IntervalInContext; current: IntervalInContext; pair: ProcessPair; IF NOT codeTimerOn THEN RETURN; pair _ GetPairForProcess[table]; current _ pair.current; interval _ FindChildIntervalInContext[intervalName, current]; IF interval = NIL THEN { interval _ AllocateIntervalInternal[intervalName]; current.children _ CONS[interval, current.children]; interval.parent _ current; }; interval.starts _ interval.starts + 1; interval.startTime _ BasicTime.GetClockPulses[]; pair.current _ interval; }; StartInt: PUBLIC PROC [intervalName: ATOM, tableName: ATOM] = { table: Table; IF NOT codeTimerOn THEN RETURN; table _ GetTable[tableName]; IF table = NIL THEN table _ CreateTable[tableName]; StartInterval[intervalName, table]; }; StopInterval: PUBLIC ENTRY PROC [intervalName: ATOM, table: Table] = { ENABLE UNWIND => NULL; interval: IntervalInContext; pair: ProcessPair; stopTime, elapsedTime: BasicTime.Pulses; IF NOT codeTimerOn THEN RETURN; stopTime _ BasicTime.GetClockPulses[]; pair _ GetPairForProcess[table]; interval _ pair.current; IF interval.name = intervalName THEN { -- normal case <> interval.stops _ interval.stops + 1; elapsedTime _ stopTime - interval.startTime; interval.totalTime _ interval.totalTime + elapsedTime; interval.minTime _ IF elapsedTime < interval.minTime THEN elapsedTime ELSE interval.minTime; IF elapsedTime > interval.maxTime THEN { interval.maxTime _ elapsedTime; interval.maxIndex _ interval.starts; }; IF interval.parent # NIL THEN pair.current _ interval.parent; } ELSE { -- encountered a stop while a different interval is active interval.prematureStops _ interval.prematureStops + 1; IF interval.prematureStops = 1 THEN interval.prematureStopName _ intervalName; }; }; StopInt: PUBLIC PROC [intervalName: ATOM, tableName: ATOM] = { table: Table; IF NOT codeTimerOn THEN RETURN; table _ GetTable[tableName]; IF table = NIL THEN table _ CreateTable[tableName]; StopInterval[intervalName, table]; }; SetIntMilliseconds: PUBLIC ENTRY PROC [intervalName: ATOM, startTime: CARD32, stopTime: CARD32, tableName: ATOM] = { <> period: INT32; table: Table; interval: IntervalInContext; current: IntervalInContext; pair: ProcessPair; InnerProc: INTERNAL PROC = { -- workaround for 4.1 C optimizer bug JKF 2/21/90 IF NOT codeTimerOn THEN RETURN; period _ Period[startTime, stopTime]; table _ GetTable[tableName]; IF table = NIL THEN table _ CreateTable[tableName]; pair _ GetPairForProcess[table]; current _ pair.current; interval _ FindChildIntervalInContext[intervalName, current]; IF interval = NIL THEN { interval _ AllocateIntervalInternal[intervalName]; current.children _ CONS[interval, current.children]; interval.parent _ current; }; IF period > 0 THEN { posPer: CARD32 _ period; pulses: CARD32 _ BasicTime.MicrosecondsToPulses[posPer*1000]; interval.starts _ interval.starts + 1; interval.stops _ interval.stops + 1; interval.totalTime _ interval.totalTime + pulses; interval.minTime _ IF pulses < interval.minTime THEN pulses ELSE interval.minTime; IF pulses > interval.maxTime THEN { interval.maxTime _ pulses; interval.maxIndex _ interval.stops; }; } ELSE { interval.prematureStops _ interval.prematureStops + 1; interval.prematureStopName _ $NegativeTimePeriod }; }; -- InnerProc InnerProc[]; }; Period: PUBLIC PROC [from, to: CARD32] RETURNS [INT32] ~ { -- in milliseconds RETURN [LOOPHOLE[to-from]] }; <<>> <> ForEachTable: PUBLIC PROC [proc: ForEachTableProc] RETURNS [aborted: BOOL _ FALSE] = { <> DoForEachTable: RefTab.EachPairAction = { <> tableName: ATOM _ NARROW[key]; table: Table _ NARROW[val]; quit _ proc[tableName, table]; }; aborted _ RefTab.Pairs[gTablesRef, DoForEachTable]; }; ForEachTableProc: TYPE = CodeTimer.ForEachTableProc; <> ForEachIntervalInContext: PUBLIC PROC [table: Table, proc: ForEachIntervalInContextProc] RETURNS [aborted: BOOL _ FALSE] = { <> processCount: CARD _ 0; IF table = NIL THEN RETURN; FOR lp: LIST OF ProcessPair _ table.processes, lp.rest UNTIL lp = NIL DO pair: ProcessPair _ lp.first; FOR list: LIST OF IntervalInContext _ pair.outer.children, list.rest UNTIL list = NIL DO aborted _ WalkInterval[processCount, list.first, proc, 0]; IF aborted THEN RETURN; ENDLOOP; processCount _ processCount + 1; ENDLOOP; }; ForEachIntervalInContextProc: TYPE = CodeTimer.ForEachIntervalInContextProc; <> <<>> WalkInterval: PROC [process: CARD, interval: IntervalInContext, proc: ForEachIntervalInContextProc, level: CARD] RETURNS [aborted: BOOL _ FALSE] = { totalMsec, minMsec, maxMsec: CARD; totalMsec _ BasicTime.PulsesToMicroseconds[interval.totalTime]/1000; minMsec _ BasicTime.PulsesToMicroseconds[interval.minTime]/1000; maxMsec _ BasicTime.PulsesToMicroseconds[interval.maxTime]/1000; aborted _ proc[interval.name, process, interval.starts, totalMsec, minMsec, maxMsec, interval.maxIndex, interval.prematureStops, level]; IF aborted THEN RETURN; FOR list: LIST OF IntervalInContext _ interval.children, list.rest UNTIL list = NIL DO aborted _ WalkInterval[process, list.first, proc, level+1]; IF aborted THEN RETURN; ENDLOOP; }; PrintTable: PUBLIC PROC [f: IO.STREAM, table: Table] = { DoPrintIntervalInContext: ForEachIntervalInContextProc = { <> IF starts # 0 THEN { avgMsec: CARD; FOR i: NAT IN [1..level] DO f.PutRope[" "]; ENDLOOP; -- indent f.PutF["%g.%g. n: %g. total: %g. ", [cardinal[process]], [atom[intervalName]], [integer[starts]], [integer[totalMsec]]]; avgMsec _ totalMsec/starts; IF startsWithoutStops > 0 THEN f.PutF["avg: %g. range: [%g..%g], worst: %g, errs: %g\n", [integer[avgMsec]], [integer[minMsec]], [integer[maxMsec]], [integer[maxIndex]], [integer[startsWithoutStops]]] ELSE f.PutF["avg: %g. range: [%g..%g], worst: %g\n", [integer[avgMsec]], [integer[minMsec]], [integer[maxMsec]], [integer[maxIndex]]]; }; }; IF table = NIL THEN RETURN; [] _ ForEachIntervalInContext[table, DoPrintIntervalInContext]; }; PrintIntervalInContext: PROC [f: IO.STREAM, process: CARD, interval: IntervalInContext, nestingLevel: NAT _ 0, children: BOOL _ FALSE] = { name: Rope.ROPE; totalTime, avgTime, minTime, maxTime: LONG CARDINAL; IF interval.starts # 0 THEN { FOR i: NAT IN [1..nestingLevel] DO f.PutRope[" "]; ENDLOOP; -- indent name _ Atom.GetPName[interval.name]; totalTime _ BasicTime.PulsesToMicroseconds[interval.totalTime]/1000; f.PutF["%g.%g. n: %g. total: %g. ", [cardinal[process]], [rope[name]], [integer[interval.starts]], [integer[totalTime]]]; avgTime _ totalTime/interval.starts; minTime _ BasicTime.PulsesToMicroseconds[interval.minTime]/1000; maxTime _ BasicTime.PulsesToMicroseconds[interval.maxTime]/1000; IF interval.prematureStops > 0 THEN f.PutF["avg: %g. range: [%g..%g], worst: %g, errs: %g", [integer[avgTime]], [integer[minTime]], [integer[maxTime]], [integer[interval.maxIndex]], [integer[interval.prematureStops]]] ELSE f.PutF["avg: %g. range: [%g..%g], worst: %g", [integer[avgTime]], [integer[minTime]], [integer[maxTime]], [integer[interval.maxIndex]]]; IF interval.starts > interval.stops THEN f.PutF[", %g extra starts", [integer[interval.starts - interval.stops]] ]; f.PutRope["\n"]; IF children THEN { FOR list: LIST OF IntervalInContext _ interval.children, list.rest UNTIL list = NIL DO PrintIntervalInContext[f, process, list.first, nestingLevel+1, children]; ENDLOOP; }; }; }; PrintInterval: PUBLIC PROC [f: IO.STREAM, intervalName: ATOM, table: Table, nestingLevel: NAT _ 0] = { <> IF table # NIL THEN { processCount: CARD _ 0; FOR lp: LIST OF ProcessPair _ table.processes, lp.rest UNTIL lp = NIL DO pair: ProcessPair _ lp.first; FOR list: LIST OF IntervalInContext _ pair.outer.children, list.rest UNTIL list = NIL DO PrintPartsContaining[f, processCount, intervalName, list.first, nestingLevel]; ENDLOOP; processCount _ processCount + 1; ENDLOOP; }; }; PrintInt: PUBLIC PROC [f: IO.STREAM, intervalName: ATOM, tableName: ATOM, nestingLevel: NAT _ 0] = { <> table: Table _ GetTable[tableName]; IF table # NIL THEN PrintInterval[f, intervalName, table, nestingLevel]; }; PrintPartsContaining: PROC [f: IO.STREAM, process: CARD, intervalName: ATOM, interval: IntervalInContext, nestingLevel: NAT _ 0] = { IF interval.name = intervalName THEN PrintIntervalInContext[f, process, interval, nestingLevel, TRUE] ELSE IF ContainsNamedInterval[intervalName, interval] THEN { PrintIntervalInContext[f, process, interval, nestingLevel, FALSE]; FOR list: LIST OF IntervalInContext _ interval.children, list.rest UNTIL list = NIL DO PrintPartsContaining[f, process, intervalName, list.first, nestingLevel + 1]; ENDLOOP; }; }; ContainsNamedInterval: PROC [intervalName: ATOM, tree: IntervalInContext] RETURNS [BOOL] = { IF tree.name = intervalName THEN RETURN[TRUE]; FOR list: LIST OF IntervalInContext _ tree.children, list.rest UNTIL list = NIL DO IF ContainsNamedInterval[intervalName, list.first] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; IntervalStatistics: TYPE = REF IntervalStatisticsObj; IntervalStatisticsObj: TYPE = CodeTimer.IntervalStatisticsObj; GetIntervalTotals: PUBLIC PROC [intervalName: ATOM, table: Table] RETURNS [starts, totalMsec, averageMsec, minMsec, maxMsec, maxIndex, startsWithoutStops: CARD _ 0] = { <> totalPulse, minPulse, maxPulse: CARD; starts1, totalPulse1, minPulse1, maxPulse1, maxIndex1, prematureStops1: CARD; IF table = NIL THEN RETURN; totalPulse _ 0; minPulse _ LAST[CARD]; maxPulse _ 0; FOR list: LIST OF ProcessPair _ table.processes, list.rest UNTIL list = NIL DO pair: ProcessPair _ list.first; [starts1, totalPulse1, minPulse1, maxPulse1, maxIndex1, prematureStops1] _ NamedIntervalTotals[intervalName, pair.outer]; IF starts1 > 0 THEN { starts _ starts + starts1; totalPulse _ totalPulse + totalPulse1; IF minPulse1 < minPulse THEN minPulse _ minPulse1; IF maxPulse1 > maxPulse THEN { maxPulse _ maxPulse1; maxIndex _ maxIndex1; }; startsWithoutStops _ startsWithoutStops + prematureStops1; }; ENDLOOP; IF starts = 0 THEN RETURN; -- to avoid divide by 0 below totalMsec _ BasicTime.PulsesToMicroseconds[totalPulse]/1000; averageMsec _ totalMsec/starts; minMsec _ BasicTime.PulsesToMicroseconds[minPulse]/1000; maxMsec _ BasicTime.PulsesToMicroseconds[maxPulse]/1000; }; GetIntervalStats: PUBLIC PROC [intervalName: ATOM, table: Table] RETURNS [stats: LIST OF IntervalStatistics] = { <> IF table = NIL THEN RETURN; FOR lp: LIST OF ProcessPair _ table.processes, lp.rest UNTIL lp = NIL DO pair: ProcessPair _ lp.first; theseStats: LIST OF IntervalStatistics _ NamedIntervalStats[intervalName, pair.outer]; stats _ AppendStatList[theseStats, stats]; ENDLOOP; }; NamedIntervalTotals: PROC [intervalName: ATOM, interval: IntervalInContext] RETURNS [starts, totalPulse, minPulse, maxPulse, maxIndex, prematureStops: CARD] = { starts1, totalPulse1, minPulse1, maxPulse1, maxIndex1, prematureStops1: CARD; starts _ totalPulse _ maxPulse _ maxIndex _ prematureStops _ 0; minPulse _ LAST[CARD]; FOR list: LIST OF IntervalInContext _ interval.children, list.rest UNTIL list = NIL DO [starts1, totalPulse1, minPulse1, maxPulse1, maxIndex1, prematureStops1] _ NamedIntervalTotals[intervalName, list.first]; IF starts1 > 0 THEN { starts _ starts + starts1; totalPulse _ totalPulse + totalPulse1; IF minPulse1 < minPulse THEN minPulse _ minPulse1; IF maxPulse1 > maxPulse THEN { maxPulse _ maxPulse1; maxIndex _ maxIndex1; }; prematureStops _ prematureStops + prematureStops1; }; ENDLOOP; IF interval.name = intervalName THEN { IF interval.starts > 0 THEN { starts _ starts + interval.starts; totalPulse _ totalPulse + interval.totalTime; IF interval.minTime < minPulse THEN minPulse _ interval.minTime; IF interval.maxTime > maxPulse THEN { maxPulse _ interval.maxTime; maxIndex _ interval.maxIndex; }; prematureStops _ prematureStops + interval.prematureStops; }; }; }; <<>> AddAtom: PROC [entity: ATOM, entityList, ptr: LIST OF ATOM] RETURNS [newList, newPtr: LIST OF ATOM] = { IF ptr = NIL THEN { IF NOT entityList = NIL THEN ERROR; newPtr _ newList _ CONS[entity, NIL]; RETURN; } ELSE { newList _ entityList; ptr.rest _ CONS[entity, NIL]; newPtr _ ptr.rest; }; }; AddStats: PROC [entity: IntervalStatistics, entityList, ptr: LIST OF IntervalStatistics] RETURNS [newList, newPtr: LIST OF IntervalStatistics] = { IF ptr = NIL THEN { IF NOT entityList = NIL THEN ERROR; newPtr _ newList _ CONS[entity, NIL]; RETURN; } ELSE { newList _ entityList; ptr.rest _ CONS[entity, NIL]; newPtr _ ptr.rest; }; }; AppendStatList: PROC [list1, list2: LIST OF IntervalStatistics] RETURNS [result: LIST OF IntervalStatistics] = { pos: LIST OF IntervalStatistics; newCell: LIST OF IntervalStatistics; <> IF list1 = NIL THEN RETURN[list2]; result _ CONS[list1.first, NIL]; pos _ result; FOR l: LIST OF IntervalStatistics _ list1.rest, l.rest UNTIL l = NIL DO newCell _ CONS[l.first, NIL]; pos.rest _ newCell; pos _ newCell; ENDLOOP; pos.rest _ list2; }; NamedIntervalStats: PROC [intervalName: ATOM, interval: IntervalInContext] RETURNS [stats: LIST OF IntervalStatistics] = { statTail, childStats: LIST OF IntervalStatistics; IF interval.name = intervalName THEN { IF interval.starts > 0 THEN { tail: LIST OF ATOM; parent: IntervalInContext; theseStats: IntervalStatistics; theseStats _ NEW[CodeTimer.IntervalStatisticsObj]; theseStats.process _ 0; -- for now parent _ interval.parent; UNTIL parent.parent = NIL DO [theseStats.context, tail] _ AddAtom[parent.name, theseStats.context, tail]; parent _ parent.parent; ENDLOOP; theseStats.starts _ interval.starts; theseStats.totalMsec _ BasicTime.PulsesToMicroseconds[interval.totalTime]/1000; theseStats.minMsec _ BasicTime.PulsesToMicroseconds[interval.minTime]/1000; theseStats.maxMsec _ BasicTime.PulsesToMicroseconds[interval.maxTime]/1000; theseStats.maxIndex _ interval.maxIndex; theseStats.startsWithoutStops _ interval.prematureStops; [stats, statTail] _ AddStats[theseStats, stats, statTail]; }; }; FOR list: LIST OF IntervalInContext _ interval.children, list.rest UNTIL list = NIL DO childStats _ NamedIntervalStats[intervalName, list.first]; stats _ AppendStatList[stats, childStats]; ENDLOOP; }; <<>> CodeTimerNoteThreadsOn: Commander.CommandProc = { noteThreads _ TRUE; }; CodeTimerNoteThreadsOff: Commander.CommandProc = { noteThreads _ FALSE; }; CodeTimerOn: Commander.CommandProc = { codeTimerOn _ TRUE; }; CodeTimerOff: Commander.CommandProc = { codeTimerOn _ FALSE; }; TimerOn: PUBLIC PROC = { codeTimerOn _ TRUE; }; TimerOff: PUBLIC PROC = { codeTimerOn _ FALSE; }; PrintCodeTimes: Commander.CommandProc = { nameStream: IO.STREAM _ IO.RIS[cmd.commandLine]; name: Rope.ROPE; atom: ATOM; table: Table; IF cmd.commandLine = "" THEN RETURN[$Failure, "Please specify a table name"]; [] _ IO.SkipWhitespace[nameStream]; name _ IO.GetLineRope[nameStream]; atom _ Atom.MakeAtom[name]; table _ GetTable[atom]; IF table # NIL THEN PrintTable[cmd.out, table] ELSE cmd.out.PutF["No such table.\n"]; }; ResetCodeTimes: Commander.CommandProc = { nameStream: IO.STREAM _ IO.RIS[cmd.commandLine]; name: Rope.ROPE; atom: ATOM; table: Table; IF cmd.commandLine = "" THEN RETURN[$Failure, "Please specify a table name"]; [] _ IO.SkipWhitespace[nameStream]; name _ IO.GetLineRope[nameStream]; atom _ Atom.MakeAtom[name]; table _ GetTable[atom]; IF table # NIL THEN ResetTable[table] ELSE cmd.out.PutF["I don't (yet) know of a table named %g.\n", [atom[atom]]]; }; PrintIntervalTimes: Commander.CommandProc = { nameStream: IO.STREAM _ IO.RIS[cmd.commandLine]; name: Rope.ROPE; tableName, intervalName: ATOM; table: Table; IF cmd.commandLine = "" THEN RETURN[$Failure, "Please specify a table name"]; [] _ IO.SkipWhitespace[nameStream]; name _ IO.GetTokenRope[nameStream].token; intervalName _ Atom.MakeAtom[name]; name _ IO.GetTokenRope[nameStream].token; tableName _ Atom.MakeAtom[name]; table _ GetTable[tableName]; IF table # NIL THEN PrintInterval[cmd.out, intervalName, table] ELSE cmd.out.PutF["I don't (yet) know of a table named %g.\n", [atom[tableName]]]; }; PrintIntervalTotals: Commander.CommandProc = { nameStream: IO.STREAM _ IO.RIS[cmd.commandLine]; tableRope, intervalRope: Rope.ROPE; tableName, intervalName: ATOM; table: Table; IF cmd.commandLine = "" THEN RETURN[$Failure, "Please specify a table name"]; [] _ IO.SkipWhitespace[nameStream]; intervalRope _ IO.GetTokenRope[nameStream].token; intervalName _ Atom.MakeAtom[intervalRope]; tableRope _ IO.GetTokenRope[nameStream].token; tableName _ Atom.MakeAtom[tableRope]; table _ GetTable[tableName]; IF table # NIL THEN { starts, totalMsec, averageMsec, minMsec, maxMsec, maxIndex, prematureStops: CARD; [starts, totalMsec, averageMsec, minMsec, maxMsec, maxIndex, prematureStops] _ GetIntervalTotals[intervalName, table]; cmd.out.PutF["%g. n: %g. total: %g. ", [rope[intervalRope]], [integer[starts]], [integer[totalMsec]]]; IF prematureStops > 0 THEN cmd.out.PutF["avg: %g. range: [%g..%g], worst: %g, errs: %g\n", [integer[averageMsec]], [integer[minMsec]], [integer[maxMsec]], [integer[maxIndex]], [integer[prematureStops]]] ELSE cmd.out.PutF["avg: %g. range: [%g..%g], worst: %g\n", [integer[averageMsec]], [integer[minMsec]], [integer[maxMsec]], [integer[maxIndex]]]; } ELSE cmd.out.PutF["I don't (yet) know of a table named %g.\n", [atom[tableName]]]; }; ResetIntervalTimes: Commander.CommandProc = { nameStream: IO.STREAM _ IO.RIS[cmd.commandLine]; name: Rope.ROPE; tableName, intervalName: ATOM; table: Table; IF cmd.commandLine = "" THEN RETURN[$Failure, "Please specify a table name"]; [] _ IO.SkipWhitespace[nameStream]; name _ IO.GetTokenRope[nameStream].token; intervalName _ Atom.MakeAtom[name]; name _ IO.GetTokenRope[nameStream].token; tableName _ Atom.MakeAtom[name]; table _ GetTable[tableName]; IF table # NIL THEN ResetInterval[intervalName, table] ELSE cmd.out.PutF["I don't (yet) know of a table named %g.\n", [atom[tableName]]]; }; PrintCodeTimeTables: Commander.CommandProc = { PrintTableName: CodeTimer.ForEachTableProc = { <> cmd.out.PutF["\n %g", [atom[tableName]] ]; }; [] _ ForEachTable[PrintTableName]; cmd.out.PutRope["\n"]; }; <> <<>> Init: PROC [] = { gTablesRef _ RefTab.Create[7]; defaultProcess _ Process.GetCurrent[]; Commander.Register["PrintCodeTimes", PrintCodeTimes, "PrintCodeTimes -- prints out the minimum, maximum, and average times taken to execute the marked code blocks in the table named in the first argument"]; Commander.Register["ResetCodeTimes", ResetCodeTimes, "ResetCodeTimes -- zeros the code times for all of the intervals in this table"]; Commander.Register["PrintCodeTimeTables", PrintCodeTimeTables, "Prints out all code time tables that CodeTimer currently knows about"]; Commander.Register["PrintIntervalTimes", PrintIntervalTimes, "PrintIntervalTime -- prints out the minimum, maximum, and average times taken to execute the named interval (in each context in which in appears) and its children"]; Commander.Register["PrintIntervalTotals", PrintIntervalTotals, "PrintIntervalTotals -- prints out the minimum, maximum, and average times taken to execute the named interval (totaled over all contexts in which it appears)"]; Commander.Register["ResetIntervalTimes", ResetIntervalTimes, "ResetIntervalTimes -- zeros the code times for the named interval in the named table"]; Commander.Register["codeTimerOn", CodeTimerOn, "Causes CodeTimer to begin timing code intervals that have been marked with StartInt and StopInt calls (use CodeTimerTool to view the results)"]; Commander.Register["codeTimerOff", CodeTimerOff, "Causes CodeTimer to stop timing code intervals that have been marked with StartInt and StopInt calls (use CodeTimerTool to view the results)"]; Commander.Register["codeTimerNoteThreadsOn", CodeTimerNoteThreadsOn, "Causes CodeTimer to distinguish calls to the same interval by different threads"]; Commander.Register["codeTimerNoteThreadsOff", CodeTimerNoteThreadsOff, "Causes CodeTimer to treat calls to an interval identically regardless of which thread makes the call (this is the default)"]; }; Test: PROC [] = { FOR i: NAT IN [1..9] DO StartInt[$LoopOnI, $CodeTimer]; Process.PauseMsec[100]; StartInt[$InnerBlock, $CodeTimer]; Process.PauseMsec[53]; StartInt[$InnermostBlock, $CodeTimer]; StopInt[$InnermostBlock, $CodeTimer]; StopInt[$InnerBlock, $CodeTimer]; StartInt[$AnotherBlock, $CodeTimer]; StartInt[$InnermostBlock, $CodeTimer]; Process.PauseMsec[20]; StopInt[$InnermostBlock, $CodeTimer]; StopInt[$AnotherBlock, $CodeTimer]; StopInt[$LoopOnI, $CodeTimer]; ENDLOOP; }; Init[]; END.