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;
Init[];
END.