-- File DBStatsImpl.mesa -- Last edited by: -- MBrown on 1-Mar-81 11:48:15 -- Cattell on October 28, 1983 2:30 pm -- Willie-Sue on June 24, 1982 12:02 pm -- Last Edited by: Wert, August 13, 1984 2:08:53 am PDT DIRECTORY BasicTime USING[GetClockPulses, Now, PulsesToMicroseconds], DBStats, IO, Rope; DBStatsImpl: PROGRAM IMPORTS BasicTime, IO, Rope EXPORTS DBStats SHARES DBStats = BEGIN OPEN IO, DBStats; ROPE: TYPE = Rope.ROPE; -- 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[BasicTime.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[BasicTime.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.STREAM, verbose: BOOLEAN] = { PrintHighResolutionTime: PROC[time: LONG CARDINAL] RETURNS[BOOLEAN] = { -- Returns TRUE iff time is less than 2 ms. time ← LOOPHOLE[BasicTime.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", rope[PNameOfCounterEvent[e]], card[CounterArray[e]]] } ELSE IF verbose THEN { out.PutF[" %g: no events\n", rope[PNameOfCounterEvent[e]]] }; }; PrintTimer: PROC[e: TimerEvent] = { IF NStopTimerCalls[e] > 0 THEN { timeIsSmall: BOOLEAN; out.PutF[" %g: ", rope[PNameOfTimerEvent[e]]]; timeIsSmall ← PrintHighResolutionTime[TotalElapsedTime[e]/NStopTimerCalls[e]]; IF timeIsSmall THEN { avgTime: CARDINAL ← BasicTime.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", rope[PNameOfTimerEvent[e]]] }; }; currentTime: LONG CARDINAL ← LOOPHOLE[BasicTime.Now[]]; 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... PNameOfCounterEvent: PROC[event: CounterEvent] RETURNS[ROPE] = { RETURN[SELECT event FROM CacheReadOrWrite => "CacheReadOrWrite", CacheHTLookup => "CacheHTLookup", CacheHTConflictInLookup => "CacheHTConflictInLookup", CacheMiss => "CacheMiss", CacheWritePageBack => "CacheWritePageBack", SegmentAllocPage => "SegmentAllocPage", SegmentFreePage => "SegmentFreePage", StorageCreateTuple => "StorageCreateTuple", StorageCreateSystemTuple => "StorageCreateSystemTuple", StorageDestroyTuple => "StorageDestroyTuple", StorageReadTupleset => "StorageReadTupleset", StorageReadField => "StorageReadField", StorageWriteField => "StorageWriteField", StorageInitVecPage => "StorageInitVecPage", StorageCheckVecPage => "StorageCheckVecPage", StorageAllocVec => "StorageAllocVec", StorageFreeVec => "StorageFreeVec", StorageModifyVec => "StorageModifyVec", StorageModifyDifficultVec => "StorageModifyDifficultVec", StorageCompactPage => "StorageCompactPage", DBIndexInsert => "DBIndexInsert", DBIndexDelete => "DBIndexDelete", DBIndexOpenScan => "DBIndexOpenScan", DBIndexNextScan => "DBIndexNextScan", DBIndexBiggerKey => "DBIndexBiggerKey", DBIndexEqualKey => "DBIndexEqualKey", BTreeSearchPage => "BTreeSearchPage", BTreeSwapInPage => "BTreeSwapInPage", BTreeSwapOutPage => "BTreeSwapOutPage", CreateEntity => "CreateEntity", CreateRelship => "CreateRelship", ReleaseRelshipSet => "ReleaseRelshipSet", ReleaseEntitySet => "ReleaseEntitySet", SurrogateCreateRelship => "SurrogateCreateRelship", SurrogateDestroyRelship => "SurrogateDestroyRelship", DomainOf => "DomainOf", RelationOf => "RelationOf", SystemGetF => "SystemGetF", DictionaryGetF => "DictionaryGetF", DictionarySetF => "DictionarySetF", GetTupleInfo => "GetTupleInfo", GetTupleInfoMiss => "GetTupleInfoMiss", GetRelationInfo => "GetRelationInfo", GetRelationInfoMiss => "GetRelationInfoMiss", GetAttributeInfo => "GetAttributeInfo", GetAttributeInfoMiss => "GetAttributeInfoMiss", GetDomainInfo => "GetDomainInfo", GetDomainInfoMiss => "GetDomainInfoMiss", SystemGetAttributeInfo => "GetAttributeInfoMiss", ENDCASE => "Don't know" ] }; PNameOfTimerEvent: PUBLIC PROC[event: TimerEvent] RETURNS[ROPE] = { RETURN[SELECT event FROM -- DBFile-- PilotFileCreateTransaction => "PilotFileCreateTransaction", PilotFileFinishTransaction => "PilotFileFinishTransaction", PilotFileOpen => "PilotFileOpen", PilotFileReadPage => "PilotFileReadPage", PilotFileWritePage => "PilotFileWritePage", PilotFileGetSize => "PilotFileGetSize", PilotFileSetSize => "PilotFileSetSize", AlpineFileCreateTransaction => "AlpineFileCreateTransaction", AlpineFileFinishTransaction => "AlpineFileFinishTransaction", AlpineFileOpen => "AlpineFileOpen", AlpineFileReadPage => "AlpineFileReadPage", AlpineFileWritePage => "AlpineFileWritePage", AlpineFileGetSize => "AlpineFileGetSize", AlpineFileSetSize =>"AlpineFileSetSize", GetP => "GetP", SetP => "SetP", GetF => "GetF", SetF => "SetF", SurrogateGetF => "SurrogateGetF", SurrogateSetF => "SurrogateSetF", NameOf => "NameOf", ChangeName => "ChangeName", DeclareEntity => "DeclareEntity", DeclareRelship => "DeclareRelship", DestroyEntity => "DestroyEntity", DestroyRelship => "DestroyRelship", RelationSubset => "RelationSubset", DomainSubset => "DomainSubset", NextRelship => "NextRelship", NextEntity => "NextEntity", PrevRelship => "PrevRelship", PrevEntity => "PrevEntity", GetDomainRefAttributes => "GetDomainRefAttributes", OpenToClose => "OpenToClose", ENDCASE => "Don't know" ] }; 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. Changed by wert on August 13, 1984 2:07:27 am PDT -- Changed the *n (BCPL new line) to \n (cedar newline) in the formatted output strings. This makes the DB.Statistics file easier to read...