<> <> <> <> <> <<>> DIRECTORY DragOpsCross, DragOpsCrossUtils, HandCodingUtil, IO, LizardCache, LizardHeart, LizardToolOutput, Real USING [RoundLI], Rope, SparseMemory; LizardToolOutputImpl: CEDAR PROGRAM IMPORTS DragOpsCrossUtils, HandCodingUtil, IO, Real, Rope, SparseMemory EXPORTS LizardToolOutput = BEGIN OPEN LizardToolOutput; Byte: TYPE = DragOpsCross.Byte; LizardIFUStackSize: NAT = LizardHeart.LizardIFUStackSize; Inst: TYPE = DragOpsCross.Inst; ProcessorRegister: TYPE = DragOpsCross.ProcessorRegister; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Word: TYPE = DragOpsCross.Word; ZerosWord: Word = DragOpsCross.ZerosWord; LocalInstStats: TYPE = REF LocalInstStatsRep; LocalInstStatsRep: TYPE = ARRAY Inst OF LocalInstStatsEntry; LocalInstStatsEntry: TYPE = RECORD [inst: Inst, count: INT]; <> ShowRegisters: PUBLIC PROC [out: STREAM, processor: LizardHeart.Processor, testAbort: TestAbort _ NIL] = { regOut: NAT _ 0; regNameArray: HandCodingUtil.RegNameArray = HandCodingUtil.GetRegArray[]; FOR reg: ProcessorRegister IN ProcessorRegister DO word: Word = processor.regs[reg]; IF testAbort # NIL AND testAbort[] THEN GO TO requestStopPrint; IF word = ZerosWord THEN LOOP; IF regOut MOD 4 = 0 THEN IO.PutRope[out, "\n"]; regOut _ regOut + 1; IO.PutF[out, " %5g ", [rope[regNameArray[reg]]]]; PutAsBoth[out, "%w (%d)", word]; ENDLOOP; IO.PutRope[out, "\n"]; <> {youngest: NAT _ processor.youngest; eldest: NAT = processor.eldest; IF (youngest+1) MOD LizardIFUStackSize # eldest THEN { IO.PutRope[out, "\nIFU stack (youngest first)\n"]; DO entry: LizardHeart.IFUStackEntry = processor.ifuStack[youngest]; IF testAbort # NIL AND testAbort[] THEN GO TO requestStopPrint; IO.PutRope[out, " regL: "]; IO.PutRope[out, regNameArray[entry.regL]]; PutAsCard[out, ", rtnPC: %w\n", entry.pc]; IF youngest = eldest THEN EXIT; youngest _ (youngest + (LizardIFUStackSize-1)) MOD LizardIFUStackSize; ENDLOOP; } ELSE IO.PutRope[out, "\nIFU stack empty\n"]; }; EXITS requestStopPrint => { IO.PutRope[out, "\nPrinting stopped by request.\n\n"]; }; }; <<>> ShowRing: PUBLIC PROC [out: STREAM, ring: LastInstTable, mem: SparseMemory.Base, howMany: [0..LastInstMod] _ LastInstMod, testAbort: TestAbort _ NIL] = { <> regNameArray: HandCodingUtil.RegNameArray = HandCodingUtil.GetRegArray[]; instNameArray: HandCodingUtil.NameArray = HandCodingUtil.GetInstArray[]; which: CARDINAL _ ring.last; PutF1I[out, "\nLast %g instructions (most recent, first printed):\n", LastInstMod]; THROUGH [0..LastInstMod) DO pc: Word = ring.pcArray[which]; inst: DragOpsCross.Inst; rest: Word; IF pc = ZerosWord THEN EXIT; IF testAbort # NIL AND testAbort[] THEN GO TO requestStopPrint; PutAsCard[out, " pc: %w => ", pc]; [inst, rest] _ GetInstAndRest[mem, pc]; HandCodingUtil.ToStream[out, inst, rest, pc]; IO.PutRope[out, "\n"]; which _ (which-1) MOD LastInstMod; ENDLOOP; EXITS requestStopPrint => { IO.PutRope[out, "\nPrinting stopped by request.\n\n"]; }; }; <<>> ShowStats: PUBLIC PROC [out: STREAM, processor: LizardHeart.Processor, instStats: InstCountTable, testAbort: TestAbort _ NIL] = { pStats: LizardHeart.ProcessorStats _ processor.stats; instNameArray: HandCodingUtil.NameArray = HandCodingUtil.GetInstArray[]; instOut: NAT _ 0; cycles: INT _ pStats.cycles; insts: INT _ pStats.instructions; bytes: INT _ pStats.instBytes; rejects: INT _ processor.ifuCache.stats.rejectCycles+processor.euCache.stats.rejectCycles; instructionsSoFar: INT _ 0; invTotal: REAL _ IF pStats.instructions > 0 THEN 100.0 / pStats.instructions ELSE 0.0; <> PutF1I[out, "\ninstructions: %g", insts]; PutF1I[out, ", cycles: %g", cycles]; IF insts > 0 THEN { PutReal1[out, "\n bytes/inst: %g", (bytes*1.0)/insts, 2]; PutReal1[out, ", cycles/inst: %g", (cycles*1.0)/insts, 2]; IF rejects > 0 THEN PutReal1[out, ", cycles/reject: %g", (cycles*1.0)/rejects, 2]; }; PutF1I[out, "\n instBytesUsed: %g", bytes]; PutF1I[out, ", instBytesFlushed: %g", processor.instBuffer.bytesDiscarded]; PutF1I[out, "\n euFetches: %g", pStats.euFetches]; PutF1I[out, ", euStores: %g", pStats.euStores]; { <> goodPredict: INT _ pStats.fallThruGood+pStats.jumpGood; badPredict: INT _ pStats.fallThruBad+pStats.jumpBad; PutF1I[out, "\n goodPredictions: %g", goodPredict]; PutF1I[out, ", badPredictions: %g", badPredict]; PutF1I[out, ", uncond jumps: %g", pStats.jumps]; PutF1I[out, ", calls: %g", pStats.calls]; PutF1I[out, "\n (fallThruGood: %g", pStats.fallThruGood]; PutF1I[out, ", jumpGood: %g", pStats.jumpGood]; PutF1I[out, ", fallThruBad: %g", pStats.fallThruBad]; PutF1I[out, ", jumpBad: %g)", pStats.jumpBad]; }; PutF1I[out, "\n stackOver: %g", pStats.stackOver]; PutF1I[out, "\n instBufferCycles: %g", pStats.instBufferCycles]; PutF1I[out, ", returnInterlockCycles: %g", pStats.returnInterlockCycles]; PutF1I[out, ", lookaheadRejectCycles: %g", pStats.lookaheadRejects]; <<>> IF testAbort # NIL AND testAbort[] THEN GO TO requestStopPrint; <> IO.PutRope[out, "\n\nIFU cache - "]; DumpCache[out, processor.ifuCache]; IO.PutRope[out, "\nEU cache - "]; DumpCache[out, processor.euCache]; IO.PutRope[out, "\n"]; <> ShowInstStats[out, instStats, testAbort]; IO.PutRope[out, "\n"]; EXITS requestStopPrint => { IO.PutRope[out, "\nPrinting stopped by request.\n\n"]; }; }; ShowBiasedStats: PUBLIC PROC [out: STREAM, old, new: StatSnapshot, testAbort:TestAbort] = { instOut: NAT _ 0; cycles: INT _ new.pStats.cycles - old.pStats.cycles; insts: INT _ new.pStats.instructions - old.pStats.instructions; bytes: INT _ new.pStats.instBytes - old.pStats.instBytes; ifuRejects: INT _ new.ifuStats.rejectCycles - old.ifuStats.rejectCycles; euRejects: INT _ new.euStats.rejectCycles - old.euStats.rejectCycles; rejects: INT _ ifuRejects + euRejects; euFetches: INT _ new.pStats.euFetches - old.pStats.euFetches; euStores: INT _ new.pStats.euStores - old.pStats.euStores; instructionsSoFar: INT _ 0; invTotal: REAL _ IF insts > 0 THEN 100.0 / insts ELSE 0.0; discarded: INT _ new.discarded - old.discarded; <> PutF1I[out, "instructions: %g", insts]; PutF1I[out, ", cycles: %g", cycles]; IF insts > 0 THEN { PutReal1[out, "\n bytes/inst: %g", (bytes*1.0)/insts, 2]; PutReal1[out, ", cycles/inst: %g", (cycles*1.0)/insts, 2]; IF rejects > 0 THEN PutReal1[out, ", cycles/reject: %g", (cycles*1.0)/rejects, 2]; }; PutF1I[out, "\n instBytesUsed: %g", bytes]; PutF1I[out, ", instBytesFlushed: %g", discarded]; PutF1I[out, "\n euFetches: %g", euFetches]; PutF1I[out, ", euStores: %g", euStores]; { <> fallThruGood: INT _ new.pStats.fallThruGood - old.pStats.fallThruGood; jumpGood: INT _ new.pStats.jumpGood - old.pStats.jumpGood; fallThruBad: INT _ new.pStats.fallThruBad - old.pStats.fallThruBad; jumpBad: INT _ new.pStats.jumpBad - old.pStats.jumpBad; goodPredict: INT _ fallThruGood+jumpGood; badPredict: INT _ fallThruBad+jumpBad; PutF1I[out, "\n goodPredictions: %g", goodPredict]; PutF1I[out, ", badPredictions: %g", badPredict]; PutF1I[out, ", uncond jumps: %g", new.pStats.jumps - old.pStats.jumps]; PutF1I[out, ", calls: %g", new.pStats.calls - old.pStats.calls]; PutF1I[out, "\n (fallThruGood: %g", fallThruGood]; PutF1I[out, ", jumpGood: %g", jumpGood]; PutF1I[out, ", fallThruBad: %g", fallThruBad]; PutF1I[out, ", jumpBad: %g)", jumpBad]; }; PutF1I[out, "\n stackOver: %g", new.pStats.stackOver - old.pStats.stackOver]; PutF1I[out, "\n instBufferCycles: %g", new.pStats.instBufferCycles - old.pStats.instBufferCycles]; PutF1I[out, ", returnInterlockCycles: %g", new.pStats.returnInterlockCycles - old.pStats.returnInterlockCycles]; PutF1I[out, ", lookaheadRejectCycles: %g", new.pStats.lookaheadRejects - old.pStats.lookaheadRejects]; <<>> IF testAbort # NIL AND testAbort[] THEN GO TO requestStopPrint; <> IO.PutRope[out, "\n\nIFU cache - "]; ShowBiasedCache[out, old.ifuStats, new.ifuStats]; IO.PutRope[out, "\nEU cache - "]; ShowBiasedCache[out, old.euStats, new.euStats]; IO.PutRope[out, "\n"]; <> { biasedInstTable: InstCountTable _ NEW[InstCountTableRep]; FOR inst: Inst IN Inst DO biasedInstTable[inst] _ new.iStats[inst] - old.iStats[inst]; ENDLOOP; ShowInstStats[out, biasedInstTable, testAbort]; }; IO.PutRope[out, "\n"]; EXITS requestStopPrint => { IO.PutRope[out, "\nPrinting stopped by request.\n\n"]; }; }; <> PutAsBoth: PROC [out: STREAM, format: ROPE, word: Word] = { IO.PutF[out, format, [cardinal[DragOpsCrossUtils.WordToCard[word]]], [integer[DragOpsCrossUtils.WordToInt[word]]]]; }; PutAsCard: PROC [out: STREAM, format: ROPE, word: Word] = { IO.PutF[out, format, [cardinal[DragOpsCrossUtils.WordToCard[word]]]]; }; PutF1I: PROC [out: STREAM, format: ROPE, int: INT] = { IO.PutF[out, format, [integer[int]]]; }; PutReal1: PROC [out: STREAM, format: ROPE, real: REAL, fractionPlaces: [0..4] _ 1] = { <> fact: NAT _ SELECT fractionPlaces FROM 0 => 1, 1 => 10, 2 => 100, 3 => 1000, 4 => 10000, ENDCASE => ERROR; fix: INT _ Real.RoundLI[real*fact]; fract: NAT _ fix MOD fact; form: ROPE _ "%g.%g"; fix _ fix / fact; SELECT fractionPlaces FROM 0 => {PutF1I[out, format, fix]; RETURN}; 1 => form _ "%g.%01g"; 2 => form _ "%g.%02g"; 3 => form _ "%g.%03g"; 4 => form _ "%g.%04g"; ENDCASE => ERROR; IO.PutF[out, format, [rope[IO.PutFR[form, [integer[fix]], [integer[fract]] ]]]]; }; DumpCache: PROC [out: STREAM, cache: LizardCache.CacheBase] = { probes: INT _ cache.stats.probes; PutF1I[out, "probes: %g", probes]; PutF1I[out, ", misses: %g", cache.stats.misses]; PutF1I[out, ", mapMisses: %g", cache.stats.mapMisses]; PutF1I[out, ", dirtyWrites: %g", cache.stats.dirtyWrites]; PutF1I[out, ", rejectCycles: %g", cache.stats.rejectCycles]; IF probes > 0 THEN { PutReal1[out, "\n miss rate: %%%g", (cache.stats.misses*100.0)/probes, 2]; PutReal1[out, ", reject cycles/probe: %g", (cache.stats.rejectCycles*1.0)/probes, 2]; }; }; GetInstAndRest: PROC [mem: SparseMemory.Base, pc: Word] RETURNS [inst: Inst, rest: Word] = { <> lastAddr: Word _ ZerosWord; bytes: DragOpsCross.FourBytes _ LOOPHOLE[ZerosWord]; instLen: NAT; word: Word; FetchByte: PROC [offset: NAT] RETURNS [Byte] = { wordAddr: Word; byteIndex: [0..3]; [wordAddr, byteIndex] _ DragOpsCrossUtils.BytePCToWordAddress[[DragOpsCrossUtils.AddDelta[offset, pc]]]; IF lastAddr # wordAddr THEN word _ SparseMemory.Fetch[mem, lastAddr _ wordAddr]; RETURN [LOOPHOLE[word, DragOpsCross.FourBytes][byteIndex]]; }; inst _ LOOPHOLE[FetchByte[0]]; instLen _ LOOPHOLE[inst, CARDINAL] / 64; IF instLen = 0 THEN instLen _ IF LOOPHOLE[inst, CARDINAL] < 40B THEN 1 ELSE 5; SELECT instLen FROM 2 => bytes[3] _ FetchByte[1]; 3 => { bytes[2] _ FetchByte[1]; bytes[3] _ FetchByte[2]; }; 5 => { bytes[0] _ FetchByte[1]; bytes[1] _ FetchByte[2]; bytes[2] _ FetchByte[3]; bytes[3] _ FetchByte[4]; }; ENDCASE; RETURN [inst, LOOPHOLE[bytes]]; }; ShowInstStats: PROC [out: IO.STREAM, instStats: InstCountTable, testAbort: TestAbort] = { SortInstStats: PROC [instStats: InstCountTable] RETURNS [LocalInstStats] = { nonZero: NAT _ 0; zeroEntry: LocalInstStatsEntry _ [VAL[0], 0]; local: LocalInstStats _ NEW[LocalInstStatsRep _ ALL[zeroEntry] ]; FOR inst: Inst IN Inst DO count: INT = instStats[inst]; IF count # 0 THEN { j: NAT _ nonZero; FOR i: NAT DECREASING IN [0..nonZero) DO IF local[VAL[i]].count < count THEN { local[VAL[i+1]] _ local[VAL[i]]; j _ i; }; ENDLOOP; local[VAL[j]] _ [inst, count]; nonZero _ nonZero + 1; }; ENDLOOP; RETURN [local]; }; instNameArray: HandCodingUtil.NameArray = HandCodingUtil.GetInstArray[]; total: INT _ 0; invTotal: REAL; instructionsSoFar: INT _ 0; instOut: NAT _ 0; local: LocalInstStats _ SortInstStats[instStats]; FOR inst: Inst IN Inst DO total _ total + instStats[inst]; ENDLOOP; invTotal _ IF total > 0 THEN 100.0 / total ELSE 0.0; FOR inst: Inst IN Inst DO entry: LocalInstStatsEntry _ local[inst]; count: INT = entry.count; cumPerc: REAL _ (instructionsSoFar _ instructionsSoFar + count) * invTotal; cumPercRope: ROPE _ Rope.Substr[IO.PutFR1["%f4.1", [real[cumPerc]] ], 0, 4]; IF testAbort # NIL AND testAbort[] THEN GO TO requestStopPrint; IF count = 0 THEN EXIT; IF instOut MOD 4 = 0 THEN IO.PutRope[out, "\n"]; instOut _ instOut + 1; IO.PutF[out, "%7g (%4g%%): %-7g", [integer[count]], [rope[cumPercRope]], [rope[instNameArray[entry.inst]]] ]; ENDLOOP; EXITS requestStopPrint => { IO.PutRope[out, "\nPrinting stopped by request.\n\n"]; }; }; ShowBiasedCache: PROC [out: IO.STREAM, old, new: LizardCache.CacheStats] = { biasedCache: LizardCache.CacheBase _ NEW[LizardCache.CacheBaseRep]; biasedCache.stats.probes _ new.probes - old.probes; biasedCache.stats.misses _ new.misses - old.misses; biasedCache.stats.mapMisses _ new.mapMisses - old.mapMisses; biasedCache.stats.dirtyWrites _ new.dirtyWrites - old.dirtyWrites; biasedCache.stats.rejectCycles _ new.rejectCycles - old.rejectCycles; DumpCache[out, biasedCache]; }; END.