Implement all the remaining core (not cache) memory stat counters.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user