-- File: StatsCold.mesa - last edit:
-- AOF 15-Feb-88 16:52:54
-- Copyright (C) 1983, 1988 by Xerox Corporation. All rights reserved.
DIRECTORY
Heap USING [systemZone],
Process USING [Detach, SetTimeout, SecondsToTicks],
System USING [
GreenwichMeanTime, GetGreenwichMeanTime, Pulses, GetClockPulses, Microseconds,
PulsesToMicroseconds],
Time USING [AppendCurrent],
Stats USING [StatBump, StatCounterIndex, StringProc],
StatsOps USING [
StatArray, statGrand, StatPrintCounters, StatsPrint, StatsStrings],
StatsOpsExtras USING [GetDoStats],
String USING [AppendString];
StatsCold: MONITOR LOCKS statLock
IMPORTS Heap, Process, System, Time, Stats, StatsOps, StatsOpsExtras, String
EXPORTS Stats, StatsOps =
BEGIN
statLock: PUBLIC MONITORLOCK;
CantDo: ERROR = CODE; --used to be able to, but can't now.
-- our copy of grand at last call to StatSince or StatReady
StatGrand: TYPE = ARRAY Stats.StatCounterIndex OF LONG CARDINAL;
recent: StatsOps.StatArray ← NIL; --allocated from heap
initDateAndTime: STRING = [18]; -- when we were initialized
StatsGetCounters: PUBLIC PROC
RETURNS [POINTER TO ARRAY Stats.StatCounterIndex OF LONG CARDINAL] =
BEGIN RETURN WITH <<UNEXPORTED>> ERROR CantDo; END;
StatUpdater: ENTRY PROC =
BEGIN
updater: CONDITION;
Process.SetTimeout[@updater, Process.SecondsToTicks[15*60]];
DO
-- forever
WAIT updater;
StatUpdateLocked[];
ENDLOOP;
END;
StatUpdate: PUBLIC ENTRY PROC = {StatUpdateLocked[]};
<<
Update various things.
It can be called anytime, but must be called "often enough". The 39ms clock
overflows every 41 min, so be sure to call it more often than that. StatsCold
FORKs to a PROCESS that calls it every 20 minutes.
Also, it should be called before looking at grand[StatTime or statSeconds],
as in when printing things out.
One idea to make things go faster is to actually count things in 16 bit mode,
and call somebody before the small counters overflow to copy the info out and
reset them. This is where that should get done, but its a hard problem because
there are no MESA instructions that do an atomic read and reset.
Our copies of the time sampled when we last looked at the clock.
>>
oldSeconds: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[];
oldPulses: System.Pulses ← System.GetClockPulses[];
-- Time may go backwards when it gets reset.
spareSeconds: LONG INTEGER ← 0; -- remembers fractions of an hour
StatUpdateLocked: INTERNAL PROC =
BEGIN
nowPulses: System.Pulses ← System.GetClockPulses[];
recent: LONG CARDINAL;
delta: System.Microseconds;
newSeconds: System.GreenwichMeanTime ← System.GetGreenwichMeanTime[];
delta ← System.PulsesToMicroseconds[System.Pulses[nowPulses - oldPulses]];
StatsOps.statGrand↑[statTime] ← StatsOps.statGrand↑[statTime] + delta/1000;
oldPulses ← nowPulses;
recent ← newSeconds - oldSeconds;
oldSeconds ← newSeconds;
StatsOps.statGrand↑[statSeconds] ← StatsOps.statGrand↑[statSeconds] + recent;
spareSeconds ← spareSeconds + recent;
UNTIL spareSeconds < 3600 DO
spareSeconds ← spareSeconds - 3600;
StatsOps.statGrand↑[statHours] ← StatsOps.statGrand↑[statHours] + 1;
ENDLOOP;
END;
-- remember current date and time for header lines
StatNew: PUBLIC ENTRY PROC =
BEGIN
initDateAndTime.length ← 0;
Time.AppendCurrent[initDateAndTime];
StatZap[];
END;
-- reset counters, and print a here-we-go line
StatStart: PUBLIC ENTRY PROC[proc: Stats.StringProc, header: LONG STRING] =
BEGIN
string: STRING ← [100];
StatZap[];
Time.AppendCurrent[string];
String.AppendString[string, " "L];
proc[string]; string.length ← 0;
String.AppendString[string, header];
IF (initDateAndTime # NIL) AND (initDateAndTime.length # 0) THEN
BEGIN
String.AppendString[string, " of "L];
String.AppendString[string, initDateAndTime];
END;
proc[string];
END;
-- print out current numbers
StatPrintCurrent: PUBLIC ENTRY PROC[proc: Stats.StringProc] =
BEGIN
string: STRING ← [80];
StatUpdateLocked[];
Time.AppendCurrent[string];
String.AppendString[string, " Current counters."L];
proc[string];
StatsOps.StatPrintCounters[proc, StatsOps.statGrand];
END;
-- print out current numbers
StatFinish: PUBLIC ENTRY PROC[proc: Stats.StringProc] =
BEGIN
string: STRING ← [40];
StatUpdateLocked[];
Time.AppendCurrent[string];
String.AppendString[string, " Grand Totals."L];
proc[string];
StatsOps.StatPrintCounters[proc, StatsOps.statGrand];
StatZap[]; -- just in case
END;
-- reset the world to be nice and clean again
StatZapit: ENTRY PROC = BEGIN StatZap[]; END;
StatZap: INTERNAL PROC =
BEGIN
StatUpdateLocked[]; -- init most internal stuff
spareSeconds ← 0;
recent↑ ← StatsOps.statGrand↑ ← ALL[0];
END;
-- setup things for StatSince or StatSummary
StatReady: PUBLIC ENTRY PROC =
BEGIN
StatUpdateLocked[];
recent↑ ← StatsOps.statGrand↑;
END;
-- print out new numbers since last call to StatReady or StatSince
StatSince: PUBLIC PROC[proc: Stats.StringProc] =
BEGIN
GetCopies: ENTRY PROC = INLINE
BEGIN
StatUpdateLocked[];
temp↑ ← StatsOps.statGrand↑;
END;
string: STRING ← [80];
temp: StatsOps.StatArray ← Heap.systemZone.NEW[StatGrand];
GetCopies[];
FOR i: Stats.StatCounterIndex IN Stats.StatCounterIndex DO
recent[i] ← temp[i] - recent[i]; ENDLOOP;
Time.AppendCurrent[string];
String.AppendString[string, " Recent Statistics.\n"L];
proc[string];
StatsOps.StatPrintCounters[proc, recent];
recent↑ ← temp↑;
Heap.systemZone.FREE[@temp];
END;
-- AppendCurrent has format of dd-mmm-yy hh:mm:ss
StatPrintDateAndTime: PUBLIC PROC[proc: Stats.StringProc] =
BEGIN
string: STRING ← [40];
Time.AppendCurrent[string];
String.AppendString[string, " "L];
proc[string];
END;
Init: PROC[] =
BEGIN
IF StatsOpsExtras.GetDoStats[] THEN
BEGIN
recent ← Heap.systemZone.NEW[StatGrand];
Stats.StatBump[statMouseTrap, 0];
START StatsOps.StatsPrint;
START StatsOps.StatsStrings;
StatZapit[];
Process.Detach[FORK StatUpdater[]];
END;
END; --Init
-- initialization
Init[]; --maybe stop some nonsense early
END.