-- 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.