-- PerfBreakHandler.Mesa; edited by Sandman on September 4, 1980 3:30 PM
DIRECTORY
ControlDefs USING [
FieldDescriptor, FrameHandle, StateVector, TraceNext, TrapStatus],
CoreSwapDefs USING [ExternalStateVector, PuntInfo, UBBPointer, UserBreakBlock],
FrameOps USING [GetReturnLink, MyLocalFrame, SetReturnFrame],
ImageDefs USING [AbortMesa],
Inline USING [BITSHIFT, LongNumber],
KeyDefs USING [Keys],
Mopcodes USING [zRFS],
PerfPrivate USING [
Histogram, Leg, LegTab, MaxLegs, MaxNodes, Node, NodeID, NodeTab, NullHist,
NullNode, Number, PerfControlRecord],
ProcessDefs USING [DisableInterrupts, EnableInterrupts],
ProcessOps USING [CurrentPSB],
TimingDefs USING [Fudge, HiLo, Machine, MaxTick, Pair, ReadTime, RealTime],
TrapOps USING [ReadXTS, WriteXTS];
PerfBreakHandler: PROGRAM
IMPORTS FrameOps, ImageDefs, Inline, ProcessDefs, TimingDefs, TrapOps
SHARES ProcessDefs =
BEGIN OPEN ControlDefs, PerfPrivate;
WBPort: PORT [POINTER TO CoreSwapDefs.ExternalStateVector];
ReadField: PROCEDURE [POINTER, FieldDescriptor] RETURNS [UNSPECIFIED] = MACHINE
CODE BEGIN Mopcodes.zRFS END;
BreakBlock: TYPE = RECORD [
count: CARDINAL, blocks: ARRAY [0..MaxNodes) OF CoreSwapDefs.UserBreakBlock];
perfRecord: PerfControlRecord;
breakBlock: BreakBlock;
machine: TimingDefs.Machine;
fudge: TimingDefs.Fudge;
activeFudge: TimingDefs.Pair;
currentState: TimingDefs.HiLo;
nodeTab: POINTER TO NodeTab;
legTab: POINTER TO LegTab;
GetFudge: PROCEDURE RETURNS [val: CARDINAL] = INLINE
BEGIN
val ← activeFudge.value;
IF (activeFudge.factor ← activeFudge.factor - 1) = 0 THEN
BEGIN
currentState ← SELECT currentState FROM hi => lo, ENDCASE => hi;
activeFudge ← fudge[currentState];
END;
RETURN
END;
MonitorBreaks: PROCEDURE =
BEGIN OPEN Inline;
state: StateVector;
frame: FrameHandle;
esv: CoreSwapDefs.ExternalStateVector;
xferTrapStatus: TrapStatus;
ubb: CoreSwapDefs.UBBPointer;
pCR: POINTER TO PerfControlRecord;
locL: POINTER;
fd: FieldDescriptor;
id: CARDINAL;
value: CARDINAL;
word: INTEGER;
longval: LongNumber;
hist: POINTER TO Histogram;
timeSpent: LongNumber;
timeOnEntry: Number;
lastExit: Number;
lastEntry: Number;
lastPerfEntry: Number;
lastOverhead: Number;
lastLegTime: Number;
breakType: {perf, normal, other};
stillMustDoLastLeg: BOOLEAN;
i: CARDINAL;
free: BOOLEAN;
node: POINTER TO Node;
leg: POINTER TO Leg;
enterTime, exitTime: TimingDefs.RealTime;
nodeID: NodeID;
state ← STATE;
pCR ← @perfRecord;
pCR.self ← FrameOps.MyLocalFrame[];
state.dest ← FrameOps.GetReturnLink[];
ProcessDefs.DisableInterrupts[];
ProcessDefs.DisableInterrupts[];
DO
OPEN pCR;
xferTrapStatus ← TrapOps.ReadXTS[];
IF xferTrapStatus.state = on THEN TrapOps.WriteXTS[TraceNext];
lastEntry ← timeOnEntry;
exitTime ← TimingDefs.ReadTime[];
ProcessDefs.EnableInterrupts[];
ProcessDefs.EnableInterrupts[];
TRANSFER WITH state;
ProcessDefs.DisableInterrupts[];
ProcessDefs.DisableInterrupts[];
state ← STATE;
enterTime ← TimingDefs.ReadTime[];
FrameOps.SetReturnFrame[state.dest ← frame ← state.source];
state.source ← FrameOps.MyLocalFrame[];
frame.pc ← [IF frame.pc < 0 THEN -frame.pc ELSE (1 - frame.pc)];
-- Fixup time
timeOnEntry ←
LONG[
WITH enterTime.low SELECT machine FROM altoI => low, altoII => low,
d0 => low, ENDCASE => 0] + BITSHIFT[enterTime.high.whole, 10] +
LOOPHOLE[LongNumber[num[highbits: enterTime.high.high, lowbits: 0]],
LONG CARDINAL];
lastExit ←
LONG[
WITH exitTime.low SELECT machine FROM altoI => low, altoII => low,
d0 => low, ENDCASE => 0] + BITSHIFT[exitTime.high.whole, 10] +
LOOPHOLE[LongNumber[num[highbits: exitTime.high.high, lowbits: 0]], LONG
CARDINAL];
i ← GetFudge[];
timeSpent.lc ← timeOnEntry - lastExit;
IF lastExit > timeOnEntry THEN
timeSpent.lc ← timeSpent.lc + TimingDefs.MaxTick;
IF timeSpent.lc > i THEN lastExit ← lastExit + i
ELSE lastExit ← lastExit + timeSpent.lc;
IF ~measuringNow THEN
BEGIN lastEntry ← lastExit; lastPerfEntry ← timeOnEntry; END;
lastOverhead ← lastExit - lastEntry;
IF lastEntry > lastExit THEN
lastOverhead ← lastOverhead + TimingDefs.MaxTick;
lastPerfEntry ← lastPerfEntry + lastOverhead;
IF lastCall = perf THEN
BEGIN
perfTime ← perfTime + lastOverhead;
totalTime ← totalTime + lastOverhead;
END
ELSE
FOR leg ← @legTab[0], leg + SIZE[Leg] UNTIL leg = @legTab[nextLeg] DO
IF leg.owner # NIL THEN leg.start ← leg.start + lastOverhead; ENDLOOP;
nodeID ← [pc: frame.pc, frame: frame.accesslink];
breakType ← normal;
FOR i IN [0..breakBlock.count) DO
ubb ← @breakBlock.blocks[i];
IF nodeID = [frame: ubb.frame, pc: ubb.pc] THEN
BEGIN
state.instbyte ← ubb.inst;
node ← @nodeTab[0];
IF process # NIL AND process # ProcessOps.CurrentPSB↑ THEN
BEGIN breakType ← other; EXIT END;
FOR id IN [0..nextNode) DO
IF nodeID = node.id THEN GOTO foundEntry;
node ← node + SIZE[Node];
ENDLOOP;
IF nextNode < MaxNodes THEN
BEGIN
id ← nextNode;
nextNode ← nextNode + 1;
node↑ ←
[id: nodeID, hitsLow: 0, hitsHigh: 0, overflowed: FALSE,
hist: NullHist];
GO TO foundEntry;
END
ELSE BEGIN breakType ← other; EXIT END;
END;
REPEAT
foundEntry =>
BEGIN
breakType ← perf;
IF (node.hitsLow ← node.hitsLow + 1) = 0 THEN
IF (node.hitsHigh ← node.hitsHigh + 1) = 0 THEN
node.overflowed ← TRUE;
IF node.hist # NullHist AND ~ubb.counterL THEN
BEGIN
locL ←
IF ubb.localL THEN frame + LOOPHOLE[ubb.ptrL, CARDINAL]
ELSE ubb.ptrL;
fd ← [offset: 0, posn: ubb.posnL, size: ubb.sizeL];
value ← ReadField[locL, fd];
hist ← @histBase[node.hist];
hist.count ← hist.count + 1;
hist.sum ← hist.sum + value;
IF LOOPHOLE[hist.base, LongNumber].lowbits > value THEN
hist.underflow ← hist.underflow + 1
ELSE
BEGIN
value ←
(value - LOOPHOLE[hist.base, LongNumber].lowbits)/hist.scale;
IF hist.class = log THEN
IF (word ← value) # 0 THEN
FOR value DECREASING IN [0..15] DO
IF word < 0 THEN EXIT; word ← word*2; ENDLOOP;
IF value < hist.nBuckets THEN
hist.buckets[value] ← hist.buckets[value] + 1
ELSE hist.overflow ← hist.overflow + 1;
END;
END;
END;
ENDLOOP;
IF breakType = perf THEN
BEGIN
lastLegTime ← timeOnEntry - lastPerfEntry;
IF lastPerfEntry > timeOnEntry THEN
lastLegTime ← lastLegTime + TimingDefs.MaxTick;
totalTime ← totalTime + lastLegTime;
IF trackLeg # none THEN
BEGIN
stillMustDoLastLeg ← TRUE;
FOR leg ← @legTab[0], leg + SIZE[Leg] UNTIL leg = @legTab[nextLeg] DO
IF leg.owner # NIL THEN
BEGIN
leg.start ← leg.start + lastOverhead;
IF id = leg.to THEN
BEGIN
IF leg.owner # ProcessOps.CurrentPSB↑ THEN leg.someIgnored ← TRUE
ELSE
BEGIN
leg.owner ← NIL;
IF lastID = leg.from THEN stillMustDoLastLeg ← FALSE;
IF (leg.hitsLow ← leg.hitsLow + 1) = 0 THEN
IF (leg.hitsHigh ← leg.hitsHigh + 1) = 0 THEN
leg.overflowed ← TRUE;
timeSpent.lc ← timeOnEntry - leg.start;
IF leg.start > timeOnEntry THEN
timeSpent.lc ← timeSpent.lc + TimingDefs.MaxTick;
leg.sum ← leg.sum + timeSpent.lc;
IF leg.hist # NullHist THEN
BEGIN
hist ← @histBase[leg.hist];
hist.count ← hist.count + 1;
hist.sum ← hist.sum + timeSpent.lc;
IF hist.base > timeSpent.lc THEN
hist.underflow ← hist.underflow + 1
ELSE
BEGIN
timeSpent.lc ← timeSpent.lc - hist.base;
longval.highbits ← BITSHIFT[
timeSpent.highbits, -hist.scale];
longval.lowbits ←
BITSHIFT[timeSpent.lowbits, -hist.scale] + BITSHIFT[
timeSpent.highbits, 16 - hist.scale];
IF hist.class = log THEN
IF (word ← longval.highbits) # 0 THEN
FOR value DECREASING IN [16..31] DO
IF word < 0 THEN EXIT; word ← word*2; ENDLOOP
ELSE
IF (word ← longval.lowbits) # 0 THEN
FOR value DECREASING IN [0..15] DO
IF word < 0 THEN EXIT; word ← word*2; ENDLOOP
ELSE value ← 0
ELSE
value ←
IF longval.highbits # 0 THEN hist.nBuckets
ELSE longval.lowbits;
IF value < hist.nBuckets THEN
hist.buckets[value] ← hist.buckets[value] + 1
ELSE hist.overflow ← hist.overflow + 1;
END;
END;
END;
END
ELSE IF trackLeg = successor THEN leg.owner ← NIL;
END;
IF id = leg.from THEN
BEGIN
leg.start ← timeOnEntry;
IF leg.owner # NIL THEN leg.someIgnored ← TRUE;
leg.owner ← ProcessOps.CurrentPSB↑;
END;
ENDLOOP;
free ← FALSE;
IF addLeg = successor AND stillMustDoLastLeg AND measuringNow THEN
BEGIN
FOR leg ← @legTab[0], leg + SIZE[Leg] UNTIL leg = @legTab[nextLeg] DO
IF ~leg.lock AND leg.from = NullNode THEN
BEGIN free ← TRUE; EXIT; END;
ENDLOOP;
IF ~free AND nextLeg < MaxLegs THEN
BEGIN
leg ← @legTab[nextLeg];
nextLeg ← nextLeg + 1;
free ← TRUE
END;
IF free THEN
BEGIN
leg↑ ←
[start: timeOnEntry, from: lastID, to: id, lock: FALSE,
someIgnored: FALSE, owner: NIL, hitsLow: 1, hitsHigh: 0,
sum: lastLegTime, hist: NullHist, overflowed: FALSE];
IF id = lastID THEN leg.owner ← ProcessOps.CurrentPSB↑;
stillMustDoLastLeg ← FALSE;
END;
END;
END;
END;
SELECT breakType FROM
perf =>
BEGIN
lastID ← id;
measuringNow ← TRUE;
totalBreaks ← totalBreaks + 1;
lastPerfEntry ← timeOnEntry;
lastCall ← perf;
END;
normal =>
BEGIN
esv ← CoreSwapDefs.PuntInfo↑.puntESV;
esv.state ← @state;
esv.reason ← worrybreak;
DO
WBPort[@esv]; -- now subtract out time spent in the debugging world
lastCall ← normal;
SELECT esv.reason FROM
proceed => EXIT;
kill => ImageDefs.AbortMesa[];
showscreen => UNTIL KeyDefs.Keys.Spare3 = down DO NULL ENDLOOP;
ENDCASE;
esv.reason ← return;
ENDLOOP;
END;
ENDCASE => lastCall ← normal;
ENDLOOP;
END;
END...