-- File: PerfCommands.mesa last edited by -- Sandman on September 19, 1980 9:25 AM -- Karlton on Jun 25, 1980 2:59 AM -- Karlton on September 19, 1980 2:02 PM DIRECTORY BP USING [BBHandle, BytePC, FindBB, FindBBNum, FindModBB, FindUserBB], DebugUsefulDefs USING [ShortREAD], Format USING [NumberFormat], MachineDefs USING [ BBHandle, BytePC, ByteToRealPC, RealPC, RealToBytePC, UBBPointer], PerfCommonOps USING [ AverageTime, logSW, Number, WriteConvertedTicksToMs, WriteLongNumber, WritePercent, WriteTime], PerfOps USING [ DeleteHist, GetConfigAndModuleName, GetHistBase, GetLegTable, GetNodeTable, GetPCR, NoContext, PostError, process, PutMessage, WriteLegTableHeader, WriteNodeTableHeader], PerfPrivate USING [ AllNodes, HistBase, HistIndex, Histogram, Leg, LegIndex, LegTab, LongNumber, MaxLegs, MaxNodes, Node, NodeID, NodeIndex, NodeTab, NoLegSlot, NullHist, NullID, NullNode, Number, OverFlowNumber, PCR, SubLegIndex, SubNodeIndex], PerfStructures USING [IndexToHandle, NullPsbHandle, PsbIndex], Put USING [Char, CR, Decimal, Line, Number, Text], SDDefs USING [sBreakBlock, SD], String USING [InvalidNumber, StringToOctal], UserInput USING [userAbort], Window USING [Handle]; PerfCommands: PROGRAM IMPORTS BP, DebugUsefulDefs, MachineDefs, PerfOps, Put, UserInput, String, PerfCommonOps, PerfStructures EXPORTS PerfOps =PUBLIC BEGIN OPEN PerfCommonOps, PerfOps, PerfPrivate; handle: Window.Handle _ logSW; SetProcess: PROCEDURE = BEGIN OPEN PerfStructures; pCR: PCR _ GetPCR[write]; index: PsbIndex; IF process = NIL OR process.length = 0 THEN { pCR.process _ NullPsbHandle; Put.Line[handle, "All processes now tracked"L]} ELSE BEGIN index _ String.StringToOctal[ process ! String.InvalidNumber => GOTO badProcess]; Put.Text[handle, "Track process: "L]; Put.Line[handle, process]; pCR.process _ IndexToHandle[index]; EXITS badProcess => PostError[badProcess]; END; END; ClearTables: PROCEDURE = BEGIN i: CARDINAL; pCR: PCR _ GetPCR[write]; nodeTable: POINTER TO NodeTab _ GetNodeTable[write]; legTable: POINTER TO LegTab _ GetLegTable[write]; pCR.measuringNow _ FALSE; pCR.perfTime _ 0; pCR.totalTime _ 0; pCR.totalBreaks _ 0; pCR.process _ PerfStructures.NullPsbHandle; pCR.nextLeg _ 0; pCR.nextNode _ 0; pCR.histFree _ FIRST[HistIndex]; pCR.lastID _ NullNode; FOR i IN SubNodeIndex DO nodeTable[i] _ Node[ id: NullID, hitsLow: 0, hitsHigh: 0, overflowed: FALSE, hist: NullHist]; ENDLOOP; FOR i IN SubLegIndex DO legTable[i] _ [start: 0, from: NullNode, to: NullNode, owner: NIL, hitsLow: 0, hitsHigh: 0, sum: 0, lock: FALSE, overflowed: FALSE, someIgnored: FALSE, hist: NullHist]; ENDLOOP; Put.Line[handle, "Tables initialized"L]; END; ZeroCounts: PROCEDURE = BEGIN pCR: PCR _ GetPCR[write]; nodeTable: POINTER TO NodeTab _ GetNodeTable[write]; legTable: POINTER TO LegTab _ GetLegTable[write]; histBase: HistBase; node: POINTER TO Node; leg: POINTER TO Leg; i: CARDINAL; pCR.measuringNow _ FALSE; pCR.perfTime _ 0; pCR.totalTime _ 0; pCR.totalBreaks _ 0; pCR.lastID _ NullNode; FOR i IN SubNodeIndex DO node _ @nodeTable[i]; node.hitsLow _ 0; node.hitsHigh _ 0; node.overflowed _ FALSE; IF node.hist # NullHist THEN BEGIN histBase _ GetHistBase[write]; ZeroHist[@histBase[node.hist]]; END; ENDLOOP; FOR i IN SubLegIndex DO leg _ @legTable[i]; leg.owner _ NIL; leg.hitsLow _ 0; leg.hitsHigh _ 0; leg.someIgnored _ FALSE; leg.overflowed _ FALSE; leg.sum _ 0; IF leg.hist # NullHist THEN BEGIN histBase _ GetHistBase[write]; ZeroHist[@histBase[leg.hist]]; END; ENDLOOP; Put.Line[handle, "Tables zeroed"L]; END; ZeroHist: PROCEDURE [hist: POINTER TO Histogram] = BEGIN i: CARDINAL; hist.count _ 0; hist.overflow _ 0; hist.underflow _ 0; hist.sum _ 0; FOR i IN [0..hist.nBuckets) DO hist.buckets[i] _ 0; ENDLOOP; RETURN END; DeleteLeg: PROCEDURE [index: LegIndex] = BEGIN pCR: PCR _ GetPCR[write]; legTable: POINTER TO LegTab _ GetLegTable[write]; leg: POINTER TO Leg = @legTable[index]; IF index >= pCR.nextLeg THEN BEGIN PostError[badLeg]; RETURN END; IF leg.hist # NullHist THEN DeleteHist[leg.hist]; leg^ _ [start: 0, from: NullNode, to: NullNode, owner: NIL, hitsLow: 0, hitsHigh: 0, sum: 0, lock: FALSE, overflowed: FALSE, someIgnored: FALSE, hist: NullHist]; IF index = pCR.nextLeg - 1 THEN pCR.nextLeg _ pCR.nextLeg - 1; Put.Text[handle, "Leg "L]; Put.Decimal[handle, index]; Put.Line[handle, " deleted"L]; END; AddLeg: PROCEDURE [from, to: NodeIndex] = BEGIN pCR: PCR _ GetPCR[write]; nodeTable: POINTER TO NodeTab _ GetNodeTable[write]; legTable: POINTER TO LegTab _ GetLegTable[write]; FindLegSlot: PROCEDURE RETURNS [i: LegIndex] = BEGIN FOR i IN [0..pCR.nextLeg) DO IF ~legTable[i].lock AND legTable[i].from = NullNode THEN RETURN[i]; ENDLOOP; IF pCR.nextLeg < MaxLegs THEN BEGIN i _ pCR.nextLeg; pCR.nextLeg _ pCR.nextLeg + 1; RETURN; END; RETURN[NoLegSlot]; END; NotInLegTab: PROCEDURE [start, end: CARDINAL] RETURNS [BOOLEAN] = BEGIN i: CARDINAL; FOR i IN SubLegIndex DO IF legTable[i].from = start AND legTable[i].to = end THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; END; CreateLeg: PROCEDURE [from, to: NodeIndex] = BEGIN leg: LegIndex; IF from IN [0..pCR.nextNode) AND to IN [0..pCR.nextNode) THEN IF NotInLegTab[from, to] THEN BEGIN IF (leg _ FindLegSlot[]) # NoLegSlot THEN BEGIN legTable[leg] _ [start: 0, from: from, to: to, owner: NIL, hitsLow: 0, hitsHigh: 0, sum: 0, overflowed: FALSE, someIgnored: FALSE, lock: TRUE, hist: NullHist]; Put.Text[handle, "Leg from "L]; Put.Decimal[handle, NodeIDToBpNum[nodeTable[from].id]]; Put.Text[handle, " to "L]; Put.Decimal[handle, NodeIDToBpNum[nodeTable[to].id]]; Put.Line[handle, " added"L]; END ELSE PostError[noLegRoom]; END ELSE NULL ELSE PostError[badNode]; RETURN END; i, j: CARDINAL; IF from # AllNodes THEN IF to # AllNodes THEN CreateLeg[from, to] ELSE FOR i IN [0..pCR.nextNode) DO CreateLeg[from, i]; ENDLOOP ELSE IF to # AllNodes THEN FOR i IN [0..pCR.nextNode) DO CreateLeg[i, to]; ENDLOOP ELSE FOR i IN [0..pCR.nextNode) DO FOR j IN [0..pCR.nextNode) DO CreateLeg[i, j]; ENDLOOP ENDLOOP; RETURN END; PrintTables: PROCEDURE = BEGIN PrintTotals[]; IF UserInput.userAbort THEN BEGIN PutMessage[aborted]; Put.CR[handle]; RETURN END; PrintNodeTable[]; PrintLegTable[]; RETURN END; PrintTotals: PROCEDURE = BEGIN s: STRING _ [20]; pCR: PCR _ GetPCR[read]; Put.CR[handle]; PutMessage[totalTime]; WriteConvertedTicksToMs[pCR.totalTime, pCR.pulseConversion, 15]; Put.CR[handle]; PutMessage[elapsedTime]; WriteConvertedTicksToMs[pCR.totalTime - pCR.perfTime, pCR.pulseConversion, 15]; Put.CR[handle]; PutMessage[totalOverhead]; WriteConvertedTicksToMs[pCR.perfTime, pCR.pulseConversion, 15]; Put.CR[handle]; PutMessage[nBreaks]; WriteLongNumber[pCR.totalBreaks, 15]; Put.CR[handle]; PutMessage[avgOverhead]; WriteTime[AverageTime[pCR.perfTime, pCR.totalBreaks, pCR.pulseConversion], 15]; Put.CR[handle]; PutMessage[percentInMont]; WritePercent[pCR.perfTime, pCR.totalTime, 15]; Put.CR[handle]; END; NumberFormat: TYPE = Format.NumberFormat; ID: NumberFormat = [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 3]; PC: NumberFormat = [base: 8, zerofill: FALSE, unsigned: TRUE, columns: 9]; Frame: NumberFormat = [base: 8, zerofill: FALSE, unsigned: TRUE, columns: 7]; PrintNodeTable: PROCEDURE = BEGIN OPEN String; pCR: PCR _ GetPCR[read]; nodeTable: POINTER TO NodeTab _ GetNodeTable[read]; node: POINTER TO Node; i: CARDINAL; config: STRING _ [40]; module: STRING _ [40]; IF UserInput.userAbort THEN BEGIN PutMessage[aborted]; Put.CR[handle]; RETURN END; Put.CR[handle]; WriteNodeTableHeader[]; node _ @nodeTable[0]; FOR i IN SubNodeIndex DO IF i < pCR.nextNode OR (node.hitsLow # 0 AND node.hitsHigh # 0) THEN BEGIN IF UserInput.userAbort THEN BEGIN PutMessage[aborted]; Put.CR[handle]; RETURN END; Put.Number[handle, NodeIDToBpNum[node.id], ID]; Put.Char[handle, IF node.hist = NullHist THEN ' ELSE '*]; Put.Number[handle, node.id.frame, Frame]; Put.Number[handle, MachineDefs.RealToBytePC[node.id.pc], PC]; WriteNodeHits[node, 11]; Put.Char[handle, ' ]; IF i < pCR.nextNode THEN BEGIN module.length _ config.length _ 0; GetConfigAndModuleName[ node.id.frame, config, module ! NoContext => GOTO noContext]; PrintString[config, 8]; Put.Char[handle, ' ]; PrintString[module, 8]; Put.CR[handle]; END; EXITS noContext => PostError[noContext]; END; node _ node + SIZE[Node]; ENDLOOP; END; PrintString: PROCEDURE [s: STRING, length: CARDINAL] = BEGIN i, l: CARDINAL; l _ MIN[length, s.length]; FOR i IN [0..l) DO Put.Char[handle, s[i]]; ENDLOOP; FOR i IN [l..length) DO Put.Char[handle, ' ]; ENDLOOP; RETURN END; WriteNodeHits: PROCEDURE [node: POINTER TO Node, columns: CARDINAL] = BEGIN num: Number; num _ IF node.overflowed THEN OverFlowNumber ELSE LOOPHOLE[LongNumber[ num[lowbits: node.hitsLow, highbits: node.hitsHigh]]]; WriteLongNumber[num, columns]; Put.Char[handle, IF node.overflowed THEN '* ELSE ' ]; RETURN END; PrintLegTable: PROCEDURE = BEGIN OPEN String; i: CARDINAL; s: STRING _ [100]; pCR: PCR _ GetPCR[read]; nodeTable: POINTER TO NodeTab _ GetNodeTable[read]; legTable: POINTER TO LegTab _ GetLegTable[read]; leg: POINTER TO Leg; Put.CR[handle]; IF UserInput.userAbort THEN BEGIN PutMessage[aborted]; Put.CR[handle]; RETURN END; WriteLegTableHeader[]; leg _ @legTable[0]; FOR i IN SubLegIndex DO IF (i < pCR.nextLeg AND leg.from # NullNode) OR (leg.hitsLow # 0 AND leg.hitsHigh # 0 AND ~leg.overflowed) THEN BEGIN IF UserInput.userAbort THEN BEGIN PutMessage[aborted]; Put.CR[handle]; RETURN END; Put.Number[handle, i, ID]; Put.Char[handle, IF leg.hist = NullHist THEN ' ELSE '*]; Put.Char[handle, ' ]; Put.Number[handle, NodeIDToBpNum[nodeTable[leg.from].id], ID]; Put.Text[handle, " ->"L]; Put.Number[handle, NodeIDToBpNum[nodeTable[leg.to].id], ID]; WriteLegHits[leg, 13]; WriteConvertedTicksToMs[leg.sum, pCR.pulseConversion, 14]; WriteTime[AverageLegTime[leg], 16]; WritePercent[leg.sum, pCR.totalTime - pCR.perfTime, 8]; Put.CR[handle]; END; leg _ leg + SIZE[Leg]; ENDLOOP; END; AverageLegTime: PROCEDURE [leg: POINTER TO Leg] RETURNS [Number] = BEGIN RETURN[ AverageTime[ time: leg.sum, count: LOOPHOLE[LongNumber[num[lowbits: leg.hitsLow, highbits: leg.hitsHigh]]], conversion: GetPCR[read].pulseConversion]]; END; WriteLegHits: PROCEDURE [leg: POINTER TO Leg, columns: CARDINAL] = BEGIN num: Number; num _ IF leg.overflowed THEN OverFlowNumber ELSE LOOPHOLE[LongNumber[ num[lowbits: leg.hitsLow, highbits: leg.hitsHigh]]]; WriteLongNumber[num, columns]; Put.Text[ handle, SELECT TRUE FROM leg.overflowed AND leg.someIgnored => "*~"L, leg.someIgnored => "~ "L, leg.overflowed => "* "L, ENDCASE => " "L]; RETURN END; CollectNodes: PUBLIC PROCEDURE = BEGIN OPEN DebugUsefulDefs; pCR: PCR _ GetPCR[read]; nodeTable: POINTER TO NodeTab _ GetNodeTable[read]; i, index: CARDINAL; ubb: MachineDefs.UBBPointer; bba: MachineDefs.BBHandle = ShortREAD[@SDDefs.SD[SDDefs.sBreakBlock]]; id: NodeID; FOR i IN [0..ShortREAD[@bba.length]) DO ubb _ @bba.blocks[i]; id _ [frame: ShortREAD[@ubb.frame], pc: ShortREAD[@ubb.pc]]; IF FindIndex[id, nodeTable, pCR] = MaxNodes THEN IF pCR.nextNode < MaxNodes THEN BEGIN [] _ GetPCR[write]; [] _ GetNodeTable[write]; index _ pCR.nextNode; pCR.nextNode _ pCR.nextNode + 1; nodeTable[index] _ [id: id, hist: NullHist, overflowed: FALSE, hitsLow: 0, hitsHigh: 0]; END ELSE PutMessage[tooSmall]; ENDLOOP; Put.Line[handle, "Collected nodes"L]; END; FindIndex: PROCEDURE [id: NodeID, table: POINTER TO NodeTab, pCR: PCR] RETURNS [node: NodeIndex] = BEGIN IF id = NullID THEN RETURN[NullNode]; FOR node IN [0..pCR.nextNode) DO IF table[node].id = id THEN RETURN; ENDLOOP; RETURN[NullNode] END; FillWithSpacesAnd0Length: PROCEDURE [s: STRING] = BEGIN i: CARDINAL; FOR i IN [0..s.maxlength) DO s[i] _ ' ; ENDLOOP; s.length _ 0; RETURN END; NodeIDToBpNum: PROCEDURE [id: NodeID] RETURNS [CARDINAL] = BEGIN pc: BP.BytePC = MachineDefs.RealToBytePC[id.pc]; bb: BP.BBHandle _ BP.FindBB[id.frame, pc]; IF bb = NIL THEN bb _ BP.FindModBB[id.frame, pc]; RETURN[IF bb = NIL THEN 0 ELSE bb.num]; END; BpNumToNodeID: PROCEDURE [num: CARDINAL] RETURNS [id: NodeID] = BEGIN bb: BP.BBHandle _ BP.FindBBNum[num]; i: CARDINAL; IF bb = NIL THEN RETURN[NullID]; i _ BP.FindUserBB[bb.gf, bb.pc]; IF i = LAST[CARDINAL] THEN RETURN[NullID]; RETURN[[MachineDefs.ByteToRealPC[bb.pc], bb.gf]]; END; END.