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