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