diff --git a/src_Core/CPU/Core.bsv b/src_Core/CPU/Core.bsv index 46eee13..88edf12 100644 --- a/src_Core/CPU/Core.bsv +++ b/src_Core/CPU/Core.bsv @@ -1104,11 +1104,13 @@ module mkCore#(CoreId coreId)(Core); // Performance counters rule report_events; - hpm_core_events[2] <= unpack(pack(commitStage.events) | pack(coreFix.memExeIfc.events)); + hpm_core_events[2] <= unpack(pack(commitStage.events)); endrule Vector #(1, Bit #(Report_Width)) null_evt = replicate (0); - Vector #(31, Bit #(Report_Width)) core_evts_vec = to_large_vector (hpm_core_events_reg); + Vector #(31, Bit #(Report_Width)) mem_core_evts_vec = reverse(unpack({pack(coreFix.memExeIfc.events),0})); + Vector #(31, Bit #(Report_Width)) other_core_evts_vec = to_large_vector (hpm_core_events_reg); + Vector #(31, Bit #(Report_Width)) core_evts_vec = unpack(pack(mem_core_evts_vec) | pack(other_core_evts_vec)); Vector #(16, Bit #(Report_Width)) imem_evts_vec = replicate (0);//to_large_vector (near_mem.imem.events); Vector #(16, Bit #(Report_Width)) dmem_evts_vec = replicate (0);//to_large_vector (near_mem.dmem.events); Vector #(32, Bit #(Report_Width)) external_evts_vec = replicate (0);//to_large_vector (w_external_evts); diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv index 77b131d..e262e3e 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv @@ -68,6 +68,7 @@ import LatencyTimer::*; import CHERICap::*; import CHERICC_Fat::*; import ISA_Decls_CHERI::*; +import CacheUtils::*; `ifdef PERFORMANCE_MONITORING import PerformanceMonitor::*; import SpecialWires::*; @@ -233,7 +234,7 @@ interface MemExePipeline; `endif method Data getPerf(ExeStagePerfType t); `ifdef PERFORMANCE_MONITORING - method EventsCore events; + method EventsCoreMem events; `endif endinterface @@ -244,6 +245,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); // is not good with single core Bool multicore = valueof(CoreNum) > 1; + // load/store memory total latency (max 1K cycle latency for 1 Ld/St) + // These are always included as they are used by both stat counter systems. + LatencyTimer#(LdQSize, 10) ldMemLatTimer <- mkLatencyTimer; + LatencyTimer#(SBSize, 10) stMemLatTimer <- mkLatencyTimer; `ifdef PERF_COUNT // load issue stall Count#(Data) exeLdStallByLdCnt <- mkCount(0); @@ -252,8 +257,6 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); // load forward count Count#(Data) exeLdForwardCnt <- mkCount(0); // load/store memory total latency (max 1K cycle latency for 1 Ld/St) - LatencyTimer#(LdQSize, 10) ldMemLatTimer <- mkLatencyTimer; - LatencyTimer#(SBSize, 10) stMemLatTimer <- mkLatencyTimer; Count#(Data) exeLdMemLat <- mkCount(0); Count#(Data) exeStMemLat <- mkCount(0); // load to use latency: dispatch to resp @@ -273,8 +276,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); `endif `ifdef PERFORMANCE_MONITORING - Array #(Wire #(EventsCore)) events_wire <- mkDWireOR (3, unpack (0)); - Reg #(EventsCore) events_reg <- mkReg(unpack(0)); + Array #(Wire #(EventsCoreMem)) events_wire <- mkDWireOR (4, unpack (0)); + Reg #(EventsCoreMem) events_reg <- mkReg(unpack(0)); rule update_events_reg; events_reg <= events_wire[0]; endrule @@ -339,12 +342,18 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); if(verbose) begin $display("%t : [Ld resp] ", $time, fshow(id), "; ", fshow(d), "; ", fshow(info)); end -`ifdef PERF_COUNT // perf: load mem latency let lat <- ldMemLatTimer.done(tag); +`ifdef PERF_COUNT if(inIfc.doStats) begin exeLdMemLat.incr(zeroExtend(lat)); end +`endif +`ifdef PERFORMANCE_MONITORING + EventsCoreMem events = unpack(0); + events.evt_LOAD_WAIT = truncate(lat); + events.evt_MEM_CAP_LOAD_TAG_SET = (d.tag) ? 1:0; + events_wire[1] <= events; `endif endmethod method Action respLrScAmo(DProcReqId id, MemTaggedData d); @@ -361,23 +370,25 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); $display("[Store resp] idx ", fshow(id), ", ", fshow(waitSt)); end -`ifdef PERF_COUNT // perf: store mem latency let lat <- stMemLatTimer.done(0); +`ifdef PERF_COUNT if(inIfc.doStats) begin exeStMemLat.incr(zeroExtend(lat)); end `endif `ifdef PERFORMANCE_MONITORING - EventsCore events = unpack(0); + EventsCoreMem events = unpack(0); if (waitSt.shiftedBE == -1) events.evt_MEM_CAP_STORE = 1; - events_wire[1] <= events; + events.evt_STORE_WAIT = truncate(lat); + events.evt_MEM_CAP_STORE_TAG_SET = (waitSt.shiftedData.tag) ? 1:0; + events_wire[2] <= events; `endif // now figure out the data to be written Vector#(LineSzData, ByteEn) be = replicate(replicate(False)); Line data = replicate(0); be[waitSt.offset] = waitSt.shiftedBE; - data[waitSt.offset] = waitSt.shiftedData; + data[waitSt.offset] = waitSt.shiftedData; //XXX I guess this doesn't work with capabilities? Maybe we don't build TSO? return tuple2(unpack(pack(be)), data); endmethod `else @@ -386,17 +397,19 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); let e <- stb.deq(idx); // deq SB lsq.wakeupLdStalledBySB(idx); // wake up loads if(verbose) $display("[Store resp] idx = %x, ", idx, fshow(e)); -`ifdef PERF_COUNT // perf: store mem latency let lat <- stMemLatTimer.done(idx); +`ifdef PERF_COUNT if(inIfc.doStats) begin exeStMemLat.incr(zeroExtend(lat)); end `endif `ifdef PERFORMANCE_MONITORING - EventsCore events = unpack(0); + EventsCoreMem events = unpack(0); if (pack(e.byteEn) == -1) events.evt_MEM_CAP_STORE = 1; - events_wire[1] <= events; + events.evt_STORE_WAIT = truncate(lat); + events.evt_MEM_CAP_STORE_TAG_SET = pack(zeroExtend(countOnes(pack(e.line.tag)))); + events_wire[2] <= events; `endif return tuple2(unpack(pack(e.byteEn)), e.line); // return SB entry endmethod @@ -699,7 +712,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); SBSearchRes sbRes = stb.search(info.paddr, info.shiftedBE); `endif `ifdef PERFORMANCE_MONITORING - EventsCore events = unpack(0); + EventsCoreMem events = unpack(0); if (pack(info.shiftedBE) == -1) events.evt_MEM_CAP_LOAD = 1; `endif // search LSQ @@ -724,10 +737,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); end else if(issRes == ToCache) begin reqLdQ.enq(tuple2(zeroExtend(info.tag), info.paddr)); -`ifdef PERF_COUNT // perf: load mem latency ldMemLatTimer.start(info.tag); -`endif end else if(issRes matches tagged Stall .stallBy) begin `ifdef PERF_COUNT @@ -740,9 +751,6 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); default: doAssert(False, "unknow stall reason"); endcase end -`endif -`ifdef PERFORMANCE_MONITORING - events.evt_LOAD_WAIT = 1; `endif end else begin @@ -1131,10 +1139,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); // we leave deq to resp time // ROB should have already been set to executed if(verbose) $display("[doDeqStQ_St] ", fshow(lsqDeqSt)); -`ifdef PERF_COUNT // perf: store mem latency stMemLatTimer.start(0); -`endif endrule `else @@ -1158,10 +1164,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); rule doIssueSB; let {sbIdx, en} <- stb.issue; reqStQ.enq(tuple2(sbIdx, {en.addr, 0})); -`ifdef PERF_COUNT // perf: store mem latency stMemLatTimer.start(sbIdx); -`endif endrule `endif @@ -1323,9 +1327,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); end `endif `ifdef PERFORMANCE_MONITORING - EventsCore events = unpack(0); + EventsCoreMem events = unpack(0); events.evt_SC_SUCCESS = 1; - events_wire[2] <= events; + events_wire[3] <= events; `endif endrule diff --git a/src_Core/RISCY_OOO/procs/lib/ProcTypes.bsv b/src_Core/RISCY_OOO/procs/lib/ProcTypes.bsv index a76c7fc..e4e691f 100755 --- a/src_Core/RISCY_OOO/procs/lib/ProcTypes.bsv +++ b/src_Core/RISCY_OOO/procs/lib/ProcTypes.bsv @@ -50,7 +50,6 @@ import ISA_Decls_CHERI::*; import GetPut::*; import RVFI_DII_Types::*; `endif -import ISA_Decls_CHERI::*; typedef `NUM_CORES CoreNum; typedef Bit#(TLog#(CoreNum)) CoreId; @@ -1064,7 +1063,7 @@ typedef struct { SupCnt evt_FP; SupCnt evt_SC_SUCCESS; SupCnt evt_LOAD_WAIT; - SupCnt evt_STORE_WAIT; // XXX + SupCnt evt_STORE_WAIT; // XXX Don't think we can make this make sense for Toooba. Store delays overlap so we can't get a single number that tells us the cycles spent waiting for store delays. Toooba seems to measure the delay of each store independently. Maybe we could do this with ~8bits per element? One report per cycle? SupCnt evt_FENCE; SupCnt evt_F_BUSY_NO_CONSUME; // XXX SupCnt evt_D_BUSY_NO_CONSUME; // XXX @@ -1075,8 +1074,42 @@ typedef struct { SupCnt evt_UNREPRESENTABLE_CAP; // XXX SupCnt evt_MEM_CAP_LOAD; SupCnt evt_MEM_CAP_STORE; - SupCnt evt_MEM_CAP_LOAD_TAG_SET; // XXX - SupCnt evt_MEM_CAP_STORE_TAG_SET; // XXX + SupCnt evt_MEM_CAP_LOAD_TAG_SET; + SupCnt evt_MEM_CAP_STORE_TAG_SET; } EventsCore deriving (Bits, FShow); typedef TDiv#(SizeOf#(EventsCore),SizeOf#(SupCnt)) EventsCoreElements; + +typedef Bit#(Report_Width) HpmRpt; +typedef struct { + HpmRpt evt_REDIRECT; + HpmRpt evt_TRAP; + HpmRpt evt_BRANCH; + HpmRpt evt_JAL; + HpmRpt evt_JALR; + HpmRpt evt_AUIPC; + HpmRpt evt_LOAD; + HpmRpt evt_STORE; + HpmRpt evt_LR; + HpmRpt evt_SC; + HpmRpt evt_AMO; + HpmRpt evt_SERIAL_SHIFT; + HpmRpt evt_INT_MUL_DIV_REM; + HpmRpt evt_FP; + HpmRpt evt_SC_SUCCESS; + HpmRpt evt_LOAD_WAIT; + HpmRpt evt_STORE_WAIT; + HpmRpt evt_FENCE; + HpmRpt evt_F_BUSY_NO_CONSUME; // XXX + HpmRpt evt_D_BUSY_NO_CONSUME; // XXX + HpmRpt evt_1_BUSY_NO_CONSUME; // XXX + HpmRpt evt_2_BUSY_NO_CONSUME; // XXX + HpmRpt evt_3_BUSY_NO_CONSUME; // XXX + HpmRpt evt_IMPRECISE_SETBOUND; // XXX + HpmRpt evt_UNREPRESENTABLE_CAP; // XXX + HpmRpt evt_MEM_CAP_LOAD; + HpmRpt evt_MEM_CAP_STORE; + HpmRpt evt_MEM_CAP_LOAD_TAG_SET; + HpmRpt evt_MEM_CAP_STORE_TAG_SET; +} EventsCoreMem deriving (Bits, FShow); // Memory needs more space for reporting delays +typedef TDiv#(SizeOf#(EventsCoreMem),Report_Width) EventsCoreMemElements; `endif