diff --git a/Doc/Performance_Monitoring.md b/Doc/Performance_Monitoring.md index 68c8197..45ad08f 100644 --- a/Doc/Performance_Monitoring.md +++ b/Doc/Performance_Monitoring.md @@ -60,7 +60,7 @@ to the fact that they are Flute-only events) - Mem cap load tag set – count when a tagged capability is loaded (0x1c) - Mem cap store tag set – count when stage a tagged capability is stored (0x1d) -IMem, DMem L1 Cache, and LL Cache; events identical for all three, though some are irrelevant for the respective caches. IDs in format (IMem/DMem/LLC): +IMem, DMem L1 Cache, and LL Cache (including the respective TLBs); events identical for all three, though some are irrelevant for the respective caches. IDs in format (IMem/DMem/LLC): - Load – count loads requested by cpu (0x20/0x30/unimplemented) - Load miss – count loads missed (0x21/0x31/0x61) - Load miss latency – count cycles waiting on a load miss (0x22/0x32/0x62) @@ -70,10 +70,10 @@ IMem, DMem L1 Cache, and LL Cache; events identical for all three, though some a - Amo – count atomic ops requested by cpu (unimplemented/0x36/unimplemented) - Amo miss – count atomics missed (unimplemented/0x37/unimplemented) - Amo miss latency – count cycles waiting on a atomics miss (unimplemented/0x38/unimplemented) -- Tlb – count tlb accesses (0x29/0x39/unimplemented) -- Tlb miss – count tlb missed (0x2a/0x3a/unimplemented) +- Tlb – count tlb accesses (0x29/0x39/0x69) +- Tlb miss – count tlb missed (0x2a/0x3a/0x6a) - Tlb miss latency – count cycles waiting on a tlb miss (0x2b/0x3b/unimplemented) -- Tlb flush – count tlb flushes (0x2c/0x3c/unimplemented) +- Tlb flush – count tlb flushes (0x2c/0x3c/0x6c) - Evict – count cache line evictions (unimplemented/unimplemented/unimplemented) diff --git a/src_Core/CPU/Core.bsv b/src_Core/CPU/Core.bsv index 2196fcb..8328fc3 100644 --- a/src_Core/CPU/Core.bsv +++ b/src_Core/CPU/Core.bsv @@ -1094,6 +1094,8 @@ module mkCore#(CoreId coreId)(Core); `ifdef PERFORMANCE_MONITORING // ================================================================ // Performance counters + // Each cache and TLB pair uses the same struct (EventsCache), but the cache accesses + // different fields than the TLB, which makes it safe to combine them Reg#(EventsCache) events_llc_reg <- mkRegU; Reg#(EventsCache) events_tgc_reg <- mkRegU; @@ -1112,7 +1114,8 @@ module mkCore#(CoreId coreId)(Core); EventsCache dataMem = unpack(pack(dMem.events) | pack(dTlb.events)); Vector #(16, Bit #(Report_Width)) dmem_evts_vec = to_large_vector (dataMem); Vector #(32, Bit #(Report_Width)) external_evts_vec = replicate (0);//to_large_vector (w_external_evts); - Vector #(16, Bit #(Report_Width)) llc_evts_vec = to_large_vector (events_llc_reg); + EventsCache llMem = unpack(pack(events_llc_reg) | pack(l2Tlb.events)); + Vector #(16, Bit #(Report_Width)) llc_evts_vec = to_large_vector (llMem); Vector #(16, Bit #(Report_Width)) tgc_evts_vec = to_large_vector (events_tgc_reg); let events = append (null_evt, core_evts_vec); diff --git a/src_Core/RISCY_OOO/procs/lib/L2Tlb.bsv b/src_Core/RISCY_OOO/procs/lib/L2Tlb.bsv index 139169f..9b1ca13 100644 --- a/src_Core/RISCY_OOO/procs/lib/L2Tlb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/L2Tlb.bsv @@ -54,6 +54,11 @@ import SetAssocTlb::*; import L2SetAssocTlb::*; import TranslationCache::*; import LatencyTimer::*; +`ifdef PERFORMANCE_MONITORING +import PerformanceMonitor::*; +import CCTypes::*; +import BlueUtils::*; +`endif // for SV39 only @@ -114,6 +119,9 @@ interface L2Tlb; // performace interface Perf#(L2TlbPerfType) perf; +`ifdef PERFORMANCE_MONITORING + method EventsCache events; +`endif endinterface typedef FullAssocTlb#(`L2_TLB_HUGE_SIZE) L2FullAssocTlb; @@ -277,6 +285,9 @@ module mkL2Tlb(L2Tlb::L2Tlb); }); endrule `endif +`ifdef PERFORMANCE_MONITORING + Array #(Reg #(EventsCache)) perf_events <- mkDRegOR (3, unpack (0)); +`endif // when flushing is true, since both I and D TLBs have finished flush and // is waiting for L2 to flush, all I/D TLB req must have been responded. @@ -289,6 +300,11 @@ module mkL2Tlb(L2Tlb::L2Tlb); // check no req doAssert(!rqFromCQ.notEmpty, "cannot have new req"); doAssert(readVEhr(0, pendValid) == replicate(False), "cannot have pending req"); +`ifdef PERFORMANCE_MONITORING + EventsCache ev = unpack(0); + ev.evt_TLB_FLUSH = 1; + perf_events[2] <= ev; +`endif endrule rule doWaitFlush(flushing && waitFlushDone && tlb4KB.flush_done && transCache.flush_done); @@ -402,6 +418,11 @@ module mkL2Tlb(L2Tlb::L2Tlb); dataHugePageHitCnt.incr(1); end end +`endif +`ifdef PERFORMANCE_MONITORING + EventsCache ev = unpack(0); + ev.evt_TLB = 1; + perf_events[1] <= ev; `endif end else if(resp4KB.hit) begin @@ -411,6 +432,11 @@ module mkL2Tlb(L2Tlb::L2Tlb); pageHit(entry); // update 4KB array replacement, no need to touch MG array tlb4KB.deqResp(Valid (resp4KB.way)); +`ifdef PERFORMANCE_MONITORING + EventsCache ev = unpack(0); + ev.evt_TLB = 1; + perf_events[1] <= ev; +`endif end else begin // miss, deq resp @@ -429,6 +455,11 @@ module mkL2Tlb(L2Tlb::L2Tlb); dataMissCnt.incr(1); end end +`endif +`ifdef PERFORMANCE_MONITORING + EventsCache ev = unpack(0); + ev.evt_TLB_MISS = 1; + perf_events[0] <= ev; `endif end endrule @@ -662,6 +693,12 @@ module mkL2Tlb(L2Tlb::L2Tlb); child: cRq.child, entry: Valid (entry) }); +`ifdef PERFORMANCE_MONITORING + // page table walks are counted as accesses + EventsCache ev = unpack(0); + ev.evt_TLB = 1; + perf_events[1] <= ev; +`endif // update TLB array if(entry.level > 0) begin // add to mega/giga page tlb @@ -675,6 +712,11 @@ module mkL2Tlb(L2Tlb::L2Tlb); dataHugePageMissCnt.incr(1); end end +`endif +`ifdef PERFORMANCE_MONITORING + EventsCache ev = unpack(0); + ev.evt_TLB_MISS = 1; + perf_events[0] <= ev; `endif end else begin @@ -764,4 +806,7 @@ module mkL2Tlb(L2Tlb::L2Tlb); `endif endmethod endinterface +`ifdef PERFORMANCE_MONITORING + method EventsCache events = perf_events[0]; +`endif endmodule