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