-- RTRefAccounting.Mesa

--  last edited  2-Sep-81 16:28:12 by Willie-Sue Haugeland
--  last edited 8-Feb-82 11:47:23 by Paul Rovner

DIRECTORY
  Inline USING[LongNumber, BITXOR, BITSHIFT, LowHalf, HighHalf],
  RTRefCounts,
  Runtime USING[GlobalFrame],
  SpecialSpace USING[MakeCodeResident, MakeGlobalFrameResident];

RTRefAccounting: PROGRAM
  IMPORTS RTRefCounts, Inline, SpecialSpace, Runtime
= BEGIN
  OPEN RTRefCounts;
  
  RCEntriesSummary: TYPE =
     RECORD [empty: CARDINAL← 0, normal: CARDINAL← 0, overflow: CARDINAL← 0];

  distributionSummary: TYPE = RECORD
                  [ LTrcFinalize: CARDINAL← 0,
                    EQrcFinalize: CARDINAL← 0,
		    rcFinalizePlus1: CARDINAL← 0,
                    rcFinalizePlus2: CARDINAL← 0,
                    rcFinalizePlus3: CARDINAL← 0,
		    rcFinalizePlus4: CARDINAL← 0,
		    rcFinalizePlus5: CARDINAL← 0,
		    rcFinalizePlus5Plus: CARDINAL← 0,
		    rcCountPegged: CARDINAL← 0
		  ];

  oiLengthsSummary: TYPE = RECORD
                [ two: CARDINAL← 0,
                  threeTo5: CARDINAL← 0,
		  sixTo9: CARDINAL← 0,
                  tenTo29: CARDINAL← 0,
		  GEThirty: CARDINAL← 0
	        ];

  chainHead: TYPE = RECORD [ pi: ProbeIndex← 0, length: INTEGER← 0];

  longOiChainsSummary: TYPE = ARRAY (0..5] OF chainHead;
   		  
  RefCountsSummary: TYPE = RECORD
   [ nRCEntries: RCEntriesSummary,
     distribution: distributionSummary,
     oiLengths: oiLengthsSummary,
     firstNormalEntry: ProbeIndex← 0,
     firstOiEntry: ProbeIndex← 0,
     numOiInUse: INTEGER← 0,
     longOiChains: longOiChainsSummary
   ];

  chainEntries: TYPE = ARRAY (0..10] OF LONG POINTER;

  OverflowChain: TYPE = RECORD [num: INTEGER← 0, cEntries: chainEntries];
  mappirce: LONG POINTER TO AMapPiRce← RTRefCounts.GetMapPiRce[];
  mapoioe: LONG POINTER TO AMapOiOe← RTRefCounts.GetMapOiOe[];  

  SummarizeCounts: PROC RETURNS[SummaryOfRefCounts: RefCountsSummary] =
   BEGIN
   firstNormalSeen: BOOLEAN← FALSE;
   firstOiSeen: BOOLEAN← FALSE;
   longOiIndex: INTEGER← 0;
   lowestOi: INTEGER← LAST[INTEGER];
   SummaryOfRefCounts← [,,,,,,];
   
   FOR pi: ProbeIndex IN [0..LAST[ProbeIndex]] DO
    { rce: RCEntry ← mappirce[pi];
      IF rce = rceEmpty THEN
       SummaryOfRefCounts.nRCEntries.empty← SummaryOfRefCounts.nRCEntries.empty+1
      ELSE
       WITH rce: rce SELECT FROM
        normal =>
        { SummaryOfRefCounts.nRCEntries.normal← SummaryOfRefCounts.nRCEntries.normal+1;
          DoRCaccounting[@SummaryOfRefCounts, rce];
	  IF ~firstNormalSeen THEN {SummaryOfRefCounts.firstNormalEntry← pi; firstNormalSeen← TRUE};
	 };
        overflow =>
	{ len: INTEGER← 0;
	  oiFirst: MapOiOeIndex ← rce.oi;
          pOe: LONG POINTER TO OverflowEntry;
          oi: MapOiOeIndex ← oiFirst;

          SummaryOfRefCounts.nRCEntries.overflow← SummaryOfRefCounts.nRCEntries.overflow+1;
	 IF ~firstOiSeen THEN {SummaryOfRefCounts.firstOiEntry← pi; firstOiSeen← TRUE};
	 DO
	  BEGIN
	   pOe← @mapoioe[oi];
	   len← len + 1;
	   DoRCaccounting[@SummaryOfRefCounts, pOe.rce];
	   WITH rce: pOe.oe1 SELECT FROM
	    normal => {len← len + 1; DoRCaccounting[@SummaryOfRefCounts, rce]; EXIT};
	    overflow => oi ← rce.oi;
	   ENDCASE;
	  END;
	  ENDLOOP;
	  SummaryOfRefCounts.numOiInUse← SummaryOfRefCounts.numOiInUse + len;

	  DoOiLengthAccounting[@SummaryOfRefCounts, len];
	  IF longOiIndex < 5 THEN
	  { longOiIndex← longOiIndex+ 1;
	    SummaryOfRefCounts.longOiChains[longOiIndex]← [pi: pi, length: len];
	    IF len < lowestOi THEN lowestOi← len;
	  }
	  ELSE
	  { IF len > lowestOi THEN
	     FOR i: INTEGER IN (0..5] DO
	      IF SummaryOfRefCounts.longOiChains[i].length = lowestOi THEN
	       { SummaryOfRefCounts.longOiChains[i]← [pi: pi, length: len];
	         FOR j: INTEGER IN (i..5] DO
		  IF SummaryOfRefCounts.longOiChains[j].length = lowestOi THEN GO TO done; ENDLOOP;
		 lowestOi← len; EXIT;
	        };
	     REPEAT
	       done => NULL;
	     ENDLOOP;
           };
	};
       ENDCASE;
     };
   ENDLOOP;
  END;

  FollowOiChain: PROC[pi: ProbeIndex] RETURNS[OiChain: OverflowChain] =
   {  len: INTEGER← 0;
       nrce: RCEntry← mappirce[pi];
       pOe: LONG POINTER TO OverflowEntry;
       oi: MapOiOeIndex;
       OiChain← [,];
       
       FOR i: INTEGER IN (0..10] DO OiChain.cEntries[i]← NIL; ENDLOOP;

       WITH nrce: nrce SELECT FROM
        overflow =>
        { oi← nrce.oi;
          DO
          { pOe← @mapoioe[oi];
            len← len + 1;
	    OiChain.cEntries[len]← LOOPHOLE[RcePiToRef[pOe.rce, pi], LONG POINTER];
	    IF len > 10 THEN EXIT;
	    WITH nrce: pOe.oe1 SELECT FROM
	     normal =>		-- end of chain
	      { OiChain.cEntries[len]← LOOPHOLE[RcePiToRef[pOe.oe1, pi], LONG POINTER];
	       EXIT;
	      };
	     overflow => oi ← nrce.oi;
	     ENDCASE;
           };
	  ENDLOOP;
	};
       ENDCASE;
       OiChain.num← len;
   };
    
  DoRCaccounting: PROC[SummaryOfRefCounts: LONG POINTER TO RefCountsSummary, rce: RCEntry] =
   { nrce: nRCEntry← LOOPHOLE[rce, nRCEntry];
     SELECT nrce.rc FROM
	0,1,2 => SummaryOfRefCounts.distribution.LTrcFinalize←
	          SummaryOfRefCounts.distribution.LTrcFinalize+1;
	rcFinalize => SummaryOfRefCounts.distribution.EQrcFinalize←
	               SummaryOfRefCounts.distribution.EQrcFinalize+1;
	rcFinalize+1 => SummaryOfRefCounts.distribution.rcFinalizePlus1←
	               SummaryOfRefCounts.distribution.rcFinalizePlus1+1;
	rcFinalize+2 => SummaryOfRefCounts.distribution.rcFinalizePlus2←
	                 SummaryOfRefCounts.distribution.rcFinalizePlus2+1;
	rcFinalize+3 => SummaryOfRefCounts.distribution.rcFinalizePlus3←
	                 SummaryOfRefCounts.distribution.rcFinalizePlus3+1;
	rcFinalize+4 => SummaryOfRefCounts.distribution.rcFinalizePlus4←
	                 SummaryOfRefCounts.distribution.rcFinalizePlus4+1;
	rcFinalize+5 => SummaryOfRefCounts.distribution.rcFinalizePlus5←
	                 SummaryOfRefCounts.distribution.rcFinalizePlus5+1;
	LAST[RefCt] => SummaryOfRefCounts.distribution.rcCountPegged←
	                SummaryOfRefCounts.distribution.rcCountPegged+1;
	ENDCASE => SummaryOfRefCounts.distribution.rcFinalizePlus5Plus←
	            SummaryOfRefCounts.distribution.rcFinalizePlus5Plus+1;
   };
 
  DoOiLengthAccounting: PROC[SummaryOfRefCounts: LONG POINTER TO RefCountsSummary, len: INTEGER] =
   { SELECT len FROM
	0,1,2 => SummaryOfRefCounts.oiLengths.two←
	          SummaryOfRefCounts.oiLengths.two+1;
	IN [3..5] => SummaryOfRefCounts.oiLengths.threeTo5←
	              SummaryOfRefCounts.oiLengths.threeTo5+1;
	IN [6..9] => SummaryOfRefCounts.oiLengths.sixTo9←
	                SummaryOfRefCounts.oiLengths.sixTo9+1;
	IN [10..29] => SummaryOfRefCounts.oiLengths.tenTo29←
	                SummaryOfRefCounts.oiLengths.tenTo29+1;
	ENDCASE => SummaryOfRefCounts.oiLengths.GEThirty←
	            SummaryOfRefCounts.oiLengths.GEThirty+1;
   };

  RefToPiRes: PROC[ref: LONG CARDINAL] RETURNS [pi: ProbeIndex, res: Residue] =
    { OPEN Inline;
      res← RefToRes[ref];
      pi← LOOPHOLE[BITXOR[BITSHIFT[LowHalf[ref],-1], res], ProbeIndex]};
   
  RefToRes: PROC[ref: LONG CARDINAL] RETURNS [Residue] =
   { RETURN[Inline.HighHalf[ref]]};

  RcePiToRef: PROC[rce: RCEntry, pi: ProbeIndex] RETURNS[REF] =
    { OPEN Inline;
      nrce: nRCEntry← LOOPHOLE[rce, nRCEntry];
      res: Residue = nrce.res;
      RETURN[LOOPHOLE[LongNumber[num[highbits: res,
                                     lowbits: BITSHIFT[BITXOR[pi, res], 1]]]]]};

  PiToRef: PROC[pi: ProbeIndex] RETURNS[REF] =
    { rce: RCEntry ← mappirce[pi];
      WITH rce SELECT FROM
       normal => RETURN[RcePiToRef[rce, pi]];
       ENDCASE => RETURN[NIL];
     };
      
-- *****************************

SpecialSpace.MakeCodeResident[Runtime.GlobalFrame[SummarizeCounts]];
SpecialSpace.MakeGlobalFrameResident[RTRefAccounting];

END.