-- File DBStatsImpl.mesa -- Last edited by: -- MBrown on 1-Mar-81 11:48:15 -- Cattell on March 14, 1983 2:11 pm -- Willie-Sue on June 24, 1982 12:02 pm DIRECTORY DBStats, Inline USING[LowHalf], IO, Rope, System USING[GetClockPulses, GetGreenwichMeanTime, PulsesToMicroseconds], String USING [AppendString]; DBStatsImpl: PROGRAM IMPORTS IO, I: Inline, Rope, String, System EXPORTS DBStats SHARES DBStats = BEGIN OPEN IO, DBStats; -- Module state nGlitches: LONG CARDINAL ← 0; -- Counts number of poorly-matched Starting - Stopping calls. CounterArray: PUBLIC ARRAY CounterEvent OF LONG CARDINAL; TimerWasStarted: REF ARRAY TimerEvent OF BOOLEAN← NEW[ARRAY TimerEvent OF BOOLEAN]; TimeWhenStarted: REF ARRAY TimerEvent OF LONG CARDINAL← NEW[ARRAY TimerEvent OF LONG CARDINAL]; NStopTimerCalls: REF ARRAY TimerEvent OF LONG CARDINAL← NEW[ARRAY TimerEvent OF LONG CARDINAL]; -- Only the following structures are a function of the data gathered by StopTimer. TotalElapsedTime: REF ARRAY TimerEvent OF LONG CARDINAL← NEW[ARRAY TimerEvent OF LONG CARDINAL]; MaxTime: REF ARRAY TimerEvent OF LONG CARDINAL← NEW[ARRAY TimerEvent OF LONG CARDINAL]; MinTime: REF ARRAY TimerEvent OF LONG CARDINAL← NEW[ARRAY TimerEvent OF LONG CARDINAL]; -- Procedures (see also the inlines in DBStats). Initialized: BOOLEAN ← FALSE; Initialize: PUBLIC PROC[] = { -- Don't wipe out timer events in progress, please. nGlitches ← 0; CounterArray ← ALL[0]; IF ~Initialized THEN TimerWasStarted↑ ← ALL[FALSE]; NStopTimerCalls↑ ← ALL[0]; TotalElapsedTime↑ ← ALL[0]; MaxTime↑ ← ALL[0]; MinTime↑ ← ALL[LAST[LONG CARDINAL]]; Initialized ← TRUE; }; StartTimer: PUBLIC PROC[event: TimerEvent] = { -- Called by DBStats.Starting. IF TimerWasStarted[event] THEN nGlitches ← nGlitches + 1; TimerWasStarted[event] ← TRUE; TimeWhenStarted[event] ← LOOPHOLE[System.GetClockPulses[]]; }; StopTimer: PUBLIC PROC[event: TimerEvent] = { -- Called by DBStats.Stopping. IF ~TimerWasStarted[event] THEN { nGlitches ← nGlitches + 1; RETURN; }; TimerWasStarted[event] ← FALSE; NStopTimerCalls[event] ← NStopTimerCalls[event] + 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 ← LOOPHOLE[System.GetClockPulses[], LONG CARDINAL] - TimeWhenStarted[event]; TotalElapsedTime[event] ← TotalElapsedTime[event] + elapsedTime; MaxTime[event] ← MAX[elapsedTime, MaxTime[event]]; MinTime[event] ← MIN[elapsedTime, MinTime[event]]; }; }; AbortTimer: PUBLIC PROC[event: TimerEvent] = { -- Called by DBStats.Aborting. Aborts timing of this event. TimerWasStarted[event] ← FALSE; }; EnumerateCounters: PROC[procToApply: PROC[CounterEvent]] = { FOR p: CounterEvent IN CounterEvent DO procToApply[p] ENDLOOP; }; EnumerateTimers: PROC[procToApply: PROC[TimerEvent]] = { FOR p: TimerEvent IN TimerEvent DO procToApply[p] ENDLOOP; }; Print: PUBLIC PROC[ heading: ROPE, out: IO.Handle, verbose: BOOLEAN] = { PrintHighResolutionTime: PROC[time: LONG CARDINAL] RETURNS[BOOLEAN] = { -- Returns TRUE iff time is less than 2 ms. time ← LOOPHOLE[System.PulsesToMicroseconds[LOOPHOLE[time]],LONG CARDINAL]/100; -- convert to 1/10 ms units {ms: LONG CARDINAL ← time/10; decimal: LONG CARDINAL ← time MOD 10; out.PutF["%g.%g", card[ms], card[decimal]]; RETURN[ms <= 1]}; }; PrintCounter: PROC[e: CounterEvent] = { IF CounterArray[e] > 0 THEN { out.PutF[" %g: %g events*n", string[PNameOfCounterEvent[e]], card[CounterArray[e]]] } ELSE IF verbose THEN { out.PutF[" %g: no events*n", string[PNameOfCounterEvent[e]]] }; }; PrintTimer: PROC[e: TimerEvent] = { IF NStopTimerCalls[e] > 0 THEN { timeIsSmall: BOOLEAN; out.PutF[" %g: ", string[PNameOfTimerEvent[e]]]; timeIsSmall ← PrintHighResolutionTime[TotalElapsedTime[e]/NStopTimerCalls[e]]; IF timeIsSmall THEN { avgTime: CARDINAL ← I.LowHalf[System.PulsesToMicroseconds[LOOPHOLE[TotalElapsedTime[e]/NStopTimerCalls[e]]]]; out.PutF[" ms (%g us) average time for %g events.", card[avgTime], card[NStopTimerCalls[e]]];} ELSE out.PutF[" ms average time for %g events.", card[NStopTimerCalls[e]]]; out.PutF[" Max = "]; [] ← PrintHighResolutionTime[MaxTime[e]]; out.PutF[", Min = "]; [] ← PrintHighResolutionTime[MinTime[e]]; out.PutF[".*n"] } ELSE IF verbose THEN { out.PutF[" %g: no events*n", string[PNameOfTimerEvent[e]]] }; }; currentTime: LONG CARDINAL ← LOOPHOLE[System.GetGreenwichMeanTime[]]; IF heading = NIL OR heading.Length[] = 0 THEN heading ← "DBStats"; out.PutF[IF verbose THEN "%g (printing all events at %g)*n" ELSE "%g (printing nonzero events at %g)*n", IO.rope[heading], IO.time[]]; EnumerateCounters[PrintCounter]; EnumerateTimers[PrintTimer]; IF nGlitches > 0 THEN out.PutF["Note: %g out of order calls to Starting or Stopping*n", card[nGlitches]]; nGlitches ← 0; out.PutF["*n*n"]; out.Flush[]; --force stream if necessary }; -- This stuff will soon be provided by Cedar RTTypes; watch this space... pName: STRING ← [40]; PNameOfCounterEvent: PUBLIC PROC[event: CounterEvent] RETURNS[LONG STRING] = { pName.length ← 0; String.AppendString[to: pName, from: SELECT event FROM CacheReadOrWrite => "CacheReadOrWrite"L, CacheHTLookup => "CacheHTLookup"L, CacheHTConflictInLookup => "CacheHTConflictInLookup"L, CacheMiss => "CacheMiss"L, CacheWritePageBack => "CacheWritePageBack"L, SegmentAllocPage => "SegmentAllocPage"L, SegmentFreePage => "SegmentFreePage"L, StorageCreateTuple => "StorageCreateTuple"L, StorageCreateSystemTuple => "StorageCreateSystemTuple"L, StorageDestroyTuple => "StorageDestroyTuple"L, StorageReadTupleset => "StorageReadTupleset"L, StorageReadField => "StorageReadField"L, StorageWriteField => "StorageWriteField"L, StorageInitVecPage => "StorageInitVecPage"L, StorageCheckVecPage => "StorageCheckVecPage"L, StorageAllocVec => "StorageAllocVec"L, StorageFreeVec => "StorageFreeVec"L, StorageModifyVec => "StorageModifyVec"L, StorageModifyDifficultVec => "StorageModifyDifficultVec"L, StorageCompactPage => "StorageCompactPage"L, DBIndexInsert => "DBIndexInsert"L, DBIndexDelete => "DBIndexDelete"L, DBIndexOpenScan => "DBIndexOpenScan"L, DBIndexNextScan => "DBIndexNextScan"L, DBIndexBiggerKey => "DBIndexBiggerKey"L, DBIndexEqualKey => "DBIndexEqualKey"L, BTreeSearchPage => "BTreeSearchPage"L, BTreeSwapInPage => "BTreeSwapInPage"L, BTreeSwapOutPage => "BTreeSwapOutPage"L, CreateEntity => "CreateEntity"L, CreateRelship => "CreateRelship"L, ReleaseRelshipSet => "ReleaseRelshipSet"L, ReleaseEntitySet => "ReleaseEntitySet"L, SurrogateCreateRelship => "SurrogateCreateRelship"L, SurrogateDestroyRelship => "SurrogateDestroyRelship"L, DomainOf => "DomainOf"L, RelationOf => "RelationOf"L, SystemGetF => "SystemGetF"L, DictionaryGetF => "DictionaryGetF"L, DictionarySetF => "DictionarySetF"L, GetTupleInfo => "GetTupleInfo"L, GetTupleInfoMiss => "GetTupleInfoMiss"L, GetRelationInfo => "GetRelationInfo"L, GetRelationInfoMiss => "GetRelationInfoMiss"L, GetAttributeInfo => "GetAttributeInfo"L, GetAttributeInfoMiss => "GetAttributeInfoMiss"L, GetDomainInfo => "GetDomainInfo"L, GetDomainInfoMiss => "GetDomainInfoMiss"L, SystemGetAttributeInfo => "GetAttributeInfoMiss"L, ENDCASE => "Don't know"L ]; RETURN[pName]; }; PNameOfTimerEvent: PUBLIC PROC[event: TimerEvent] RETURNS[LONG STRING] = { pName.length ← 0; String.AppendString[to: pName, from: SELECT event FROM -- DBFile-- PilotFileCreateTransaction => "PilotFileCreateTransaction"L, PilotFileFinishTransaction => "PilotFileFinishTransaction"L, PilotFileOpen => "PilotFileOpen", PilotFileReadPage => "PilotFileReadPage"L, PilotFileWritePage => "PilotFileWritePage"L, PilotFileGetSize => "PilotFileGetSize"L, PilotFileSetSize => "PilotFileSetSize"L, AlpineFileCreateTransaction => "AlpineFileCreateTransaction"L, AlpineFileFinishTransaction => "AlpineFileFinishTransaction"L, AlpineFileOpen => "AlpineFileOpen"L, AlpineFileReadPage => "AlpineFileReadPage"L, AlpineFileWritePage => "AlpineFileWritePage"L, AlpineFileGetSize => "AlpineFileGetSize"L, AlpineFileSetSize =>"AlpineFileSetSize"L, GetP => "GetP"L, SetP => "SetP"L, GetF => "GetF"L, SetF => "SetF"L, SurrogateGetF => "SurrogateGetF"L, SurrogateSetF => "SurrogateSetF"L, NameOf => "NameOf"L, ChangeName => "ChangeName"L, DeclareEntity => "DeclareEntity"L, DeclareRelship => "DeclareRelship"L, DestroyEntity => "DestroyEntity"L, DestroyRelship => "DestroyRelship"L, RelationSubset => "RelationSubset"L, DomainSubset => "DomainSubset"L, NextRelship => "NextRelship"L, NextEntity => "NextEntity"L, PrevRelship => "PrevRelship"L, PrevEntity => "PrevEntity"L, GetDomainRefAttributes => "GetDomainRefAttributes"L, OpenToClose => "OpenToClose"L, ENDCASE => "Don't know"L ]; RETURN[pName]; }; END.--DBStatsImpl CHANGE LOG Created by MBrown on February 26, 1981 10:21 AM -- Pilot version created by editing PerfStatsImpl. Changed by MBrown on 1-Mar-81 11:47:23 -- Left out a few necessary things, like PNameOfTimerEvent, etc. Changed by Cattell on 15-Dec-81 10:23:31 -- Converted to IOStream. Changed by Cattell on April 29, 1982 10:03 pm -- Added DBView items. Changed by Willie-Sue on June 24, 1982 12:02 pm -- IOStream => IO Changed by Cattell on October 11, 1982 4:22 pm -- Added some timer events.