GGStatisticsImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last edited by Bier on June 18, 1986
Contents: Routines for maintaining a table of average times for user-specified operations.
DIRECTORY
Atom, BasicTime, GGStatistics, IO, Rope;
GGStatisticsImpl:
CEDAR
PROGRAM
IMPORTS Atom, BasicTime, IO
EXPORTS GGStatistics = BEGIN
Table: TYPE = REF TableObj;
TableObj: TYPE = GGStatistics.TableObj;
Interval: TYPE = REF IntervalObj;
IntervalObj:
TYPE = GGStatistics.IntervalObj;
gTableList: LIST OF Table;
Init:
PROC [] = {
gTableList ← NIL;
[] ← CreateTable[$Gargoyle];
};
CreateTable:
PUBLIC
PROC [name:
ATOM]
RETURNS [table: Table] = {
oldTable: Table;
table ← NEW[TableObj ← [NIL, name]];
oldTable ← GetTable[name];
IF oldTable = NIL THEN gTableList ← CONS[table, gTableList]
ELSE oldTable.intervals ← NIL;
};
Getting ready to test performance.
GetTable:
PUBLIC
PROC [name:
ATOM]
RETURNS [table: Table] = {
FOR list:
LIST
OF Table ← gTableList, list.rest
UNTIL list =
NIL
DO
IF list.first.name = name THEN RETURN[list.first];
ENDLOOP;
RETURN[NIL];
};
ResetTable:
PUBLIC PROC [table: Table] = {
FOR list:
LIST
OF Interval ← table.intervals, list.rest
UNTIL list =
NIL
DO
ResetIntervalInternal[list.first];
ENDLOOP;
};
CreateInterval:
PUBLIC
PROC [name:
ATOM, subintervals:
LIST
OF Interval ←
NIL]
RETURNS [interval: Interval] = {
interval ← NEW[IntervalObj ← [name: name, subintervals: subintervals, starts: 0, stops: 0, unmatchedStarts: 0, startTime: 0, totalTime: 0, maxTime: 0, maxIndex: 9999, minTime: LAST[LONG CARDINAL]]];
};
ResetIntervalInternal:
PROC [interval: Interval] = {
FOR list:
LIST
OF Interval ← interval.subintervals, list.rest
UNTIL list =
NIL
DO
ResetIntervalInternal[list.first];
ENDLOOP;
interval.starts ← 0;
interval.stops ← 0;
interval.unmatchedStarts ← 0;
interval.startTime ← 0;
interval.totalTime ← 0;
interval.maxTime ← 0;
interval.minTime ← LAST[LONG CARDINAL]
};
AddInterval:
PUBLIC
PROC [interval: Interval, table: Table] = {
table.intervals ← CONS[interval, table.intervals];
};
AddInt:
PUBLIC
PROC [interval: Interval, tableName:
ATOM] = {
AddInterval[interval, GetTable[tableName]];
};
FindInterval:
PROC [name:
ATOM, table: Table]
RETURNS [Interval] = {
sub: Interval;
success: BOOL;
FOR list:
LIST
OF Interval ← table.intervals, list.rest
UNTIL list =
NIL
DO
[sub, success] ← FindSubInterval[name, list.first];
IF success THEN RETURN[sub];
ENDLOOP;
SIGNAL Problem[msg: "No such interval in this table."];
RETURN[NIL];
};
FindSubInterval:
PROC [name:
ATOM, interval: Interval]
RETURNS [sub: Interval, success:
BOOL] = {
IF interval.name = name THEN RETURN[interval, TRUE];
FOR subList:
LIST
OF Interval ← interval.subintervals, subList.rest
UNTIL subList =
NIL
DO
[sub, success] ← FindSubInterval[name, subList.first];
IF success THEN RETURN;
ENDLOOP;
RETURN[NIL, FALSE];
};
Testing performance.
StartInterval:
PUBLIC
PROC [name:
ATOM, table: Table] = {
interval: Interval ← FindInterval[name, table];
IF interval.starts >= interval.stops + 1
THEN {
interval.starts ← interval.stops;
interval.unmatchedStarts ← interval.unmatchedStarts + 1;
};
interval.starts ← interval.starts + 1;
interval.startTime ← BasicTime.GetClockPulses[];
};
StartInt:
PUBLIC
PROC [intervalName:
ATOM, tableName:
ATOM] = {
StartInterval[intervalName, GetTable[tableName]];
};
StopInterval:
PUBLIC
PROC [name:
ATOM, table: Table] = {
interval: Interval;
stopTime, elapsedTime: BasicTime.Pulses;
stopTime ← BasicTime.GetClockPulses[];
interval ← FindInterval[name, table];
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;
};
};
StopInt:
PUBLIC
PROC [intervalName:
ATOM, tableName:
ATOM] = {
StopInterval[intervalName, GetTable[tableName]];
};
Printing results.
PrintInterval:
PROC [f:
IO.
STREAM, interval: Interval, nestingLevel:
NAT ← 0] = {
name: Rope.ROPE;
totalTime, avgTime, minTime, maxTime: LONG CARDINAL;
IF interval.starts # 0
THEN {
FOR i:
NAT
IN [1..nestingLevel]
DO
f.PutChar[IO.TAB];
ENDLOOP;
name ← Atom.GetPName[interval.name];
totalTime ← BasicTime.PulsesToMicroseconds[interval.totalTime]/1000;
f.PutF["%g. starts: %g. total: %g. ", [rope[name]], [integer[interval.starts]], [integer[totalTime]]];
avgTime ← totalTime/interval.starts;
minTime ← BasicTime.PulsesToMicroseconds[interval.minTime]/1000;
maxTime ← BasicTime.PulsesToMicroseconds[interval.maxTime]/1000;
f.PutF["avg: %g. min: %g. max: %g, index: %g, overflows: %g\n", [integer[avgTime]], [integer[minTime]], [integer[maxTime]], [integer[interval.maxIndex]], [integer[interval.unmatchedStarts]]];
FOR children:
LIST
OF Interval ← interval.subintervals, children.rest
UNTIL children =
NIL
DO
PrintInterval[f, children.first, nestingLevel+1];
ENDLOOP;
};
};
PrintInterval: PROC [f: IO.STREAM, interval: Interval, nestingLevel: NAT ← 0] = {
name: Rope.ROPE;
totalTime, avgTime, minTime, maxTime: LONG CARDINAL;
IF interval.starts # 0 THEN {
FOR i: NAT IN [1..nestingLevel] DO
Feedback.AppendTypescript[NIL, " ", begin]; -- print a Tab on the typescript
ENDLOOP;
name ← Atom.GetPName[interval.name];
totalTime ← BasicTime.PulsesToMicroseconds[interval.totalTime]/1000;
Feedback.PutFTypescript[NIL, middle, "%g. starts: %g. total: %g. ", [rope[name]], [integer[interval.starts]], [integer[totalTime]]];
avgTime ← totalTime/interval.starts;
minTime ← BasicTime.PulsesToMicroseconds[interval.minTime]/1000;
maxTime ← BasicTime.PulsesToMicroseconds[interval.maxTime]/1000;
Feedback.PutFTypescript[NIL, end, "avg: %g. min: %g. max: %g, index: %g, overflows: %g", [integer[avgTime]], [integer[minTime]], [integer[maxTime]], [integer[interval.maxIndex]], [integer[interval.unmatchedStarts]]];
FOR children: LIST OF Interval ← interval.subintervals, children.rest UNTIL children = NIL DO
PrintInterval[f, children.first, nestingLevel+1];
ENDLOOP;
};
};
PrintTable:
PUBLIC
PROC [f:
IO.
STREAM, table: Table] = {
FOR list:
LIST
OF Interval ← table.intervals, list.rest
UNTIL list =
NIL
DO
PrintInterval[f, list.first, 0];
ENDLOOP;
};
Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = CODE;
END.