-- File: HistCommands.mesa last edited by -- Sandman on September 4, 1980 10:15 AM -- Karlton on Jun 23, 1980 3:17 PM DIRECTORY Inline USING [BITSHIFT, COPY, LongNumber], MsgSW USING [Post], PerfCommonOps USING [logSW, msgSW, Number, WriteLongNumber], PerfOps USING [ GetBase, GetBuckets, GetHistBase, GetHistLeg, GetHistNode, GetLegTable, GetNodeTable, GetPCR, GetScale, histClass, histType, PutMessage], PerfPrivate USING [ HistBase, HistIndex, Histogram, HistType, LegTab, MaxLegs, MaxNodes, NodeTab, NullHist, NullNode, Number, PCR], Put USING [CR, Decimal, Line, Number, Text], String USING [AppendChar, AppendDecimal], UserInput USING [ResetUserAbort, userAbort], Window USING [Handle]; HistCommands: PROGRAM IMPORTS Inline, PerfOps, UserInput, String, Put, MsgSW, PerfCommonOps EXPORTS PerfOps =PUBLIC BEGIN OPEN PerfCommonOps, PerfOps, PerfPrivate; handle: Window.Handle ← PerfCommonOps.logSW; AddHistogram: PUBLIC PROCEDURE = BEGIN hIndex: HistIndex; hist: POINTER TO Histogram; index: CARDINAL; size, scale, limit: CARDINAL; type: HistType ← PerfOps.histType; histBase: HistBase; nodeTab: POINTER TO NodeTab ← GetNodeTable[read]; legTab: POINTER TO LegTab ← GetLegTable[read]; pCR: PCR ← GetPCR[read]; SELECT type FROM node => BEGIN index ← GetHistNode[]; IF index ~IN [0..pCR.nextNode) THEN GOTO invalidNode; IF (hIndex ← nodeTab[index].hist) # NullHist THEN BEGIN PutHistError[alreadyOne]; DeleteHist[hIndex]; END; END; leg => BEGIN index ← GetHistLeg[]; IF index ~IN [0..pCR.nextLeg) THEN GOTO invalidLeg; IF (hIndex ← legTab[index].hist) # NullHist THEN BEGIN PutHistError[alreadyOne]; DeleteHist[hIndex]; END; END; ENDCASE => ERROR; limit ← FindAvailableSpace[pCR.histFree]; IF histClass = log THEN limit ← IF type = node THEN MIN[16, limit] ELSE MIN[32, limit]; size ← CheckBuckets[limit ! Confused => GOTO return]; scale ← CheckScale[type ! Confused => GOTO return]; hIndex ← GrabHistogramSlot[size]; Put.Text[handle, "Added Histogram for "L]; IF histType = node THEN BEGIN [] ← GetNodeTable[write]; nodeTab[index].hist ← hIndex; Put.Text[handle, "Node "L]; END ELSE BEGIN [] ← GetLegTable[write]; legTab[index].hist ← hIndex; Put.Text[handle, "Leg "L]; END; Put.Decimal[handle, index]; Put.CR[handle]; histBase ← GetHistBase[write]; hist ← @histBase[hIndex]; Zero[hist, SIZE[Histogram] + size]; hist.scale ← scale; hist.type ← type; hist.class ← histClass; hist.nBuckets ← size; hist.base ← GetBase[]; EXITS return => NULL; invalidNode => PutHistError[invalidNode]; invalidLeg => PutHistError[invalidLeg]; END; Zero: PROC [p: POINTER, l: CARDINAL] = { IF l # 0 THEN {p↑ ← 0; Inline.COPY[from: p, to: p + 1, nwords: l - 1]}}; ValidateIndex: PROCEDURE [type: HistType, index: CARDINAL, pCR: PCR] RETURNS [hIndex: HistIndex] = BEGIN SELECT type FROM node => BEGIN nodeTab: POINTER TO NodeTab ← GetNodeTable[read]; IF index ~IN [0..pCR.nextNode) THEN SIGNAL Invalid; IF (hIndex ← nodeTab[index].hist) = NullHist THEN SIGNAL Confused; END; leg => BEGIN legTab: POINTER TO LegTab ← GetLegTable[read]; IF index ~IN [0..pCR.nextLeg) THEN SIGNAL Invalid; IF (hIndex ← legTab[index].hist) = NullHist THEN SIGNAL Confused; END; ENDCASE; RETURN END; Confused: SIGNAL = CODE; Invalid: SIGNAL = CODE; DeleteHistogram: PROCEDURE = BEGIN hIndex: HistIndex; type: HistType ← histType; index: CARDINAL; nodeTab: POINTER TO NodeTab ← GetNodeTable[read]; legTab: POINTER TO LegTab ← GetLegTable[read]; pCR: PCR ← GetPCR[read]; index ← IF type = node THEN GetHistNode[] ELSE GetHistLeg[]; hIndex ← ValidateIndex[ type, index, pCR ! Invalid => IF type = node THEN GOTO invalidNode ELSE GOTO invalidLeg; Confused => GOTO return]; Put.Text[handle, "Deleted Histogram for "L]; SELECT type FROM node => BEGIN [] ← GetNodeTable[write]; DeleteHist[hIndex]; nodeTab[index].hist ← NullHist; Put.Text[handle, "Node "L]; END; leg => BEGIN [] ← GetLegTable[write]; DeleteHist[hIndex]; legTab[index].hist ← NullHist; Put.Text[handle, "Leg "L]; END; ENDCASE; Put.Decimal[handle, index]; Put.CR[handle]; EXITS invalidNode => PutHistError[invalidNode]; invalidLeg => PutHistError[invalidLeg]; return => PutHistError[none]; END; DeleteHist: PROCEDURE [hIndex: HistIndex] = BEGIN histBase: HistBase ← GetHistBase[read]; nodeTab: POINTER TO NodeTab ← GetNodeTable[read]; legTab: POINTER TO LegTab ← GetLegTable[read]; pCR: PCR ← GetPCR[write]; count, i: CARDINAL; from, to: HistIndex; to ← hIndex; from ← hIndex + SIZE[Histogram] + histBase[hIndex].nBuckets; UNTIL from = pCR.histFree DO FOR i IN [0..MaxNodes) DO IF nodeTab[i].hist = from THEN BEGIN [] ← GetNodeTable[write]; nodeTab[i].hist ← to END; ENDLOOP; FOR i IN [0..MaxLegs) DO IF legTab[i].hist = from THEN BEGIN [] ← GetLegTable[write]; legTab[i].hist ← to END; ENDLOOP; [] ← GetHistBase[write]; count ← SIZE[Histogram] + histBase[from].nBuckets; Inline.COPY[from: @histBase[from], to: @histBase[to], nwords: count]; from ← from + count; to ← to + SIZE[Histogram] + histBase[to].nBuckets; ENDLOOP; pCR.histFree ← to; END; PrintHistogram: PROCEDURE = BEGIN type: HistType ← PerfOps.histType; hIndex: HistIndex; index: CARDINAL ← IF type = node THEN GetHistNode[] ELSE GetHistLeg[]; nodeTab: POINTER TO NodeTab ← GetNodeTable[read]; legTab: POINTER TO LegTab ← GetLegTable[read]; pCR: PCR ← GetPCR[read]; Put.CR[handle]; hIndex ← ValidateIndex[ type, index, pCR ! Invalid => IF type = node THEN GOTO invalidNode ELSE GOTO invalidLeg; Confused => GOTO return]; ListHist[hIndex, index, type]; EXITS invalidNode => PutHistError[invalidNode]; invalidLeg => PutHistError[invalidLeg]; return => PutHistError[none]; END; ListHist: PROCEDURE [hIndex: HistIndex, index: CARDINAL, type: HistType] = BEGIN i: CARDINAL; histBase: HistBase ← GetHistBase[read]; hist: POINTER TO Histogram ← @histBase[hIndex]; Put.CR[handle]; Put.Text[handle, "Histogram for "L]; Put.Text[handle, IF type = node THEN "Node "L ELSE "Leg "L]; Put.Decimal[handle, index]; Put.CR[handle]; Put.Text[handle, "Number of References "L]; WriteLongNumber[hist.count, 15]; Put.CR[handle]; Put.Text[handle, "Sum of Values "L]; WriteLongNumber[hist.sum, 15]; Put.CR[handle]; Put.Text[handle, "Average Value "L]; WriteLongNumber[IF hist.count = 0 THEN 0 ELSE hist.sum/hist.count, 15]; Put.CR[handle]; Put.Text[handle, "Scale Factor"L]; Put.Text[handle, IF type = leg THEN " (2↑n)"L ELSE " "L]; Put.Text[handle, " "L]; WriteLongNumber[hist.scale, 15]; Put.CR[handle]; IF hist.class = linear THEN BEGIN Put.Text[handle, "Base "L]; WriteLongNumber[hist.base, 15]; Put.CR[handle]; END; Put.Line[handle, " Value Count"L]; Put.Line[handle, " -------------- -------"L]; IF hist.class = linear AND hist.base # 0 THEN BEGIN Put.Text[handle, " Underflow"L]; WriteLongNumber[hist.underflow, 8]; Put.CR[handle]; END; FOR i IN [0..hist.nBuckets) DO IF UserInput.userAbort THEN BEGIN PutMessage[aborted]; UserInput.ResetUserAbort[]; RETURN END; WriteLongNumber[ScaleBucket[i, hist], 15]; WriteLongNumber[hist.buckets[i], 8]; Put.CR[handle]; ENDLOOP; Put.Text[handle, " Overflow"L]; WriteLongNumber[hist.overflow, 8]; Put.CR[handle]; END; ScaleBucket: PROCEDURE [bucket: CARDINAL, hist: POINTER TO Histogram] RETURNS [val: Number] = BEGIN SELECT hist.type FROM node => SELECT hist.class FROM linear => val ← LONG[bucket]*hist.scale; ENDCASE => val ← TimesTwoToN[hist.scale, bucket]; leg => SELECT hist.class FROM linear => val ← TimesTwoToN[bucket, hist.scale]; ENDCASE => val ← TimesTwoToN[1, bucket*(hist.scale + 1)]; ENDCASE; IF hist.class = linear THEN val ← val + hist.base; END; TimesTwoToN: PROCEDURE [z: Number, n: CARDINAL] RETURNS [Number] = BEGIN OPEN Inline; y, x: LongNumber; x.lc ← z; IF n = 0 THEN RETURN[z]; IF n > 31 THEN RETURN[0]; IF n > 15 THEN BEGIN y.lowbits ← 0; y.highbits ← BITSHIFT[x.lowbits, n - 16]; RETURN[y.lc] END; y.lowbits ← BITSHIFT[x.lowbits, n]; y.highbits ← BITSHIFT[x.lowbits, n - 16] + BITSHIFT[x.highbits, n]; RETURN[y.lc] END; LegLegal: PROCEDURE [index: CARDINAL] RETURNS [BOOLEAN] = BEGIN legTab: POINTER TO LegTab ← GetLegTable[read]; pCR: PCR ← GetPCR[read]; RETURN[index IN [0..pCR.nextLeg) AND legTab[index].from # NullNode]; END; FindAvailableSpace: PROCEDURE [free: HistIndex] RETURNS [limit: CARDINAL] = BEGIN limit ← NullHist - free; RETURN[IF limit > SIZE[Histogram] THEN limit - SIZE[Histogram] ELSE 0]; END; GrabHistogramSlot: PROCEDURE [size: CARDINAL] RETURNS [hist: HistIndex] = BEGIN pCR: PCR ← GetPCR[write]; hist ← pCR.histFree; pCR.histFree ← hist + size + SIZE[Histogram]; RETURN END; CheckScale: PROCEDURE [type: HistType] RETURNS [n: CARDINAL] = BEGIN n ← GetScale[]; SELECT TRUE FROM type = leg AND n IN [0..31] => RETURN; type = node AND n # 0 => RETURN; ENDCASE; MsgSW.Post[ sw: PerfCommonOps.msgSW, string: "Scale must be"L, endOfMsg: FALSE]; MsgSW.Post[ PerfCommonOps.msgSW, IF type = leg THEN " (2↑n) [0..31]"L ELSE " [1..65,535]"L]; ERROR Confused; END; CheckBuckets: PROCEDURE [top: CARDINAL] RETURNS [n: CARDINAL] = BEGIN OPEN String; s: STRING ← [5]; n ← GetBuckets[]; IF n IN [1..top] THEN RETURN; MsgSW.Post[ sw: PerfCommonOps.msgSW, string: "Number of Buckets must be [1.."L, endOfMsg: FALSE]; AppendDecimal[s, LOOPHOLE[top]]; AppendChar[s, ']]; MsgSW.Post[PerfCommonOps.msgSW, s]; ERROR Confused; END; HistError: TYPE = {invalidLeg, invalidNode, alreadyOne, none}; PutHistError: PROCEDURE [message: HistError] = BEGIN MsgSW.Post[ PerfCommonOps.msgSW, SELECT message FROM invalidLeg => "!Invalid Leg"L, invalidNode => "!Invalid Node"L, alreadyOne => "Old Histogram deleted!"L, none => "No Histogram exists!"L, ENDCASE => "?"L]; RETURN END; END.