-- File MyPerfStatsImpl.mesa
-- Last edited by:
-- MBrown on 16-Feb-82 8:57:46
-- Kolling on September 8, 1982 4:55 pm
DIRECTORY
IO,
PerfStats,
Rope,
System;
MyPerfStatsImpl: CEDAR PROGRAM
IMPORTS
IO,
Rope,
System
EXPORTS
PerfStats
SHARES
PerfStats =
BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
-- Exported type
Timer: TYPE = REF TimerObject;
TimerObject: PUBLIC TYPE = RECORD[
pName: ROPE,
TimerWasStarted: BOOLEAN,
TimeWhenStarted: LONG CARDINAL ← NULL,
TotalElapsedTime: LONG CARDINAL ← NULL,
MaxTime: LONG CARDINAL ← NULL,
MinTime: LONG CARDINAL ← NULL,
NStopTimerCalls: LONG CARDINAL ← NULL,
next: Timer];
Counter: TYPE = PerfStats.Counter;
CounterObject: TYPE = PerfStats.CounterObject;
-- Module state
counterList: Counter ← NIL;
timerList: Timer ← NIL;
nGlitches: LONG CARDINAL ← 0;
-- Counts number of improperly-matched Start - Stop calls.
-- Procedures (also see inlines in PerfStats).
CreateCounter: PUBLIC PROC[name: ROPE] RETURNS[Counter] = {
TestForDuplicate: PROC [e: Counter] = {
IF name.Equal[e.pName] THEN ERROR DuplicateName};
EnumerateCounters[TestForDuplicate];
{e: Counter ← NEW[CounterObject ←
[pName: name, next: counterList]];
InitializeCounter[e];
RETURN[counterList ← e] }};
DuplicateName: PUBLIC ERROR = CODE;
InitializeCounter: PUBLIC PROC[event: Counter] = {
event.counter ← 0 };
DestroyCounter: PUBLIC PROC[event: Counter] = {
Remove: PROC [e: Counter] = { IF e.next = event THEN e.next ← event.next };
IF event = counterList THEN counterList ← event.next
ELSE EnumerateCounters[Remove];
event.pName ← NIL; event.next ← NIL };
EnumerateCounters: PROC[procToApply: PROC[Counter]] = {
FOR p: Counter ← counterList, p.next UNTIL p=NIL DO
procToApply[p]
ENDLOOP };
CreateTimer: PUBLIC PROC[name: ROPE] RETURNS[Timer] = {
TestForDuplicate: PROC [e: Timer] = {
IF name.Equal[e.pName] THEN ERROR DuplicateName};
EnumerateTimers[TestForDuplicate];
{e: Timer ← NEW[TimerObject ←
[pName: name, TimerWasStarted: FALSE, next: timerList]];
InitializeTimer[e];
RETURN[timerList ← e] }};
InitializeTimer: PUBLIC PROC[event: Timer] = {
-- Don't reset a running timer.
event.TotalElapsedTime ← 0;
event.MaxTime ← 0;
event.MinTime ← LAST[LONG CARDINAL];
event.NStopTimerCalls ← 0 };
DestroyTimer: PUBLIC PROC[event: Timer] = {
Remove: PROC[e: Timer] = { IF e.next = event THEN e.next ← event.next };
IF event = timerList THEN timerList ← event.next
ELSE EnumerateTimers[Remove];
event.pName ← NIL; event.next ← NIL };
EnumerateTimers: PROC[procToApply: PROC[Timer]] = {
FOR p: Timer ← timerList, p.next UNTIL p=NIL DO
procToApply[p]
ENDLOOP };
Initialize: PUBLIC PROC[] = {
EnumerateCounters[InitializeCounter];
EnumerateTimers[InitializeTimer] };
Start: PUBLIC PROC[event: Timer] = TRUSTED{
IF event.TimerWasStarted THEN nGlitches ← nGlitches + 1;
event.TimerWasStarted ← TRUE;
event.TimeWhenStarted ← System.GetClockPulses[] };
Stop: PUBLIC PROC[event: Timer] = TRUSTED{
IF ~event.TimerWasStarted THEN {
nGlitches ← nGlitches + 1;
RETURN };
event.TimerWasStarted ← FALSE;
event.NStopTimerCalls ← event.NStopTimerCalls + 1;
-- What is done next is a function of how elaborate the stats need to be. It might
--even be a function of event. For now, do something simple.
{elapsedTime: LONG CARDINAL ← System.GetClockPulses[] - event.TimeWhenStarted;
event.TotalElapsedTime ← event.TotalElapsedTime + elapsedTime;
event.MaxTime ← MAX[elapsedTime, event.MaxTime];
event.MinTime ← MIN[elapsedTime, event.MinTime] }
};
Print: PUBLIC PROC [heading: ROPE, oStream: STREAM, verbose: BOOLEAN] = {
PrintHighResolutionTime: PROC[time: LONG CARDINAL] RETURNS[BOOLEAN] = TRUSTED{
-- Returns TRUE iff time is less than 2 ms.
time ← System.PulsesToMicroseconds[[time]]/100;
-- convert to 1/10 ms units
{ms: LONG CARDINAL ← time/10;
tenthsecs: LONG CARDINAL ← time/1000;
secs: LONG CARDINAL ← tenthsecs/10;
decimal: LONG CARDINAL ← tenthsecs MOD 10;
oStream.PutF["%g", IO.card[ms]];
RETURN[ms <= 1]};
};
PrintCounter: PROC[e: Counter] = {
IF e.counter > 0 THEN {
oStream.PutF["%22g: %g events*n", IO.rope[e.pName], IO.card[e.counter]] }
ELSE IF verbose THEN {
oStream.PutF["%22g: no events*n", IO.rope[e.pName]] }
};
PrintTimer: PROC[e: Timer] = TRUSTED{
IF e.NStopTimerCalls # 1 THEN ERROR;
IF e.NStopTimerCalls > 0 THEN {
timeIsSmall: BOOLEAN;
timeIsSmall ← PrintHighResolutionTime[e.TotalElapsedTime/e.NStopTimerCalls];
IF timeIsSmall THEN {
avgTime: System.Microseconds ←
System.PulsesToMicroseconds[[e.TotalElapsedTime/e.NStopTimerCalls]];
oStream.PutF[" ms. (%g us)", IO.card[avgTime]] }
ELSE {
oStream.PutRope[" ms."] }; }
ELSE IF verbose THEN { oStream.PutF["%g: no events*n", IO.rope[e.pName]] };
};
IF heading # NIL AND heading.Size[] # 0 THEN oStream.PutF["%g", IO.rope[heading]];
EnumerateCounters[PrintCounter];
EnumerateTimers[PrintTimer];
IF nGlitches > 0 THEN
oStream.PutF["?%g out of order calls to Starting or Stopping!*n", IO.card[nGlitches]];
nGlitches ← 0;
oStream.PutF["*n"];
oStream.Flush[];
};
END.--PerfStatsImpl
CHANGE LOG
Created by MBrown on November 4, 1980 4:23 PM
-- By editing DBStatsImpl.
Changed by MBrown on November 6, 1980 3:30 PM
-- Uses DBLogStream instead of its own internal stream, to allow output
--to go to same file as DBStatsImpl.
Changed by MBrown on November 7, 1980 9:31 AM
-- Make InitializeCounterEvent and InitializeTimerEvent public.
Changed by MBrown on November 7, 1980 4:26 PM
-- Fix Print to make output take fewer lines.
Changed by MBrown on November 10, 1980 1:11 PM
-- Make ReadClock for Alto I faster (marginal improvement). When average time is small, print it
--in microseconds.
Changed by MBrown on December 8, 1980 6:21 PM
-- Don't reset running timers in InitializeTimerEvent.
Changed by MBrown on January 10, 1981 9:29 PM
-- Created Pilot/collectible storage version. Print now takes putChar and cleanup procs as parms.
--Renamed to PerfStatsImpl.
Changed by MBrown on January 11, 1981 5:02 PM
-- Added DuplicateName ERROR. Added verbose parm to Print.
Changed by MBrown on 18-Aug-81 18:46:34
-- CedarString -> Rope (ugly since CWF does not know about Rope.)
Changed by MBrown on 7-Dec-81 16:02:11
-- Convert to use IO.
Changed by MBrown on 16-Feb-82 8:58:33
-- Remove LOOPHOLEs in dealing with times (compiler bug fixed.)