Implement all the remaining core (not cache) memory stat counters.

This commit is contained in:
jon
2020-12-11 15:47:04 +00:00
parent d6243be1dd
commit 1bae03da9c
3 changed files with 70 additions and 31 deletions

View File

@@ -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);

View File

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

View File

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