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