Implemented double target table and the corresponding markov prefetcher

This commit is contained in:
Karlis Susters
2023-04-12 21:52:56 +03:00
parent 2d94cba951
commit bf0f26ce56
2 changed files with 281 additions and 1 deletions

View File

@@ -77,7 +77,7 @@ endif
ifeq (,$(filter $(DATA_PREFETCHER_LOCATION),NONE L1 L1LL LL))
$(error unsupported DATA_PREFETCHER_LOCATION)
endif
ifeq (,$(filter $(DATA_PREFETCHER_TYPE),MARKOV MARKOV_ON_HIT BLOCK STRIDE STRIDE_ADAPTIVE))
ifeq (,$(filter $(DATA_PREFETCHER_TYPE),MARKOV MARKOV_ON_HIT MARKOV_ON_HIT_2 BLOCK STRIDE STRIDE_ADAPTIVE))
$(error unsupported DATA_PREFETCHER_TYPE)
endif

View File

@@ -1,4 +1,6 @@
import ISA_Decls :: *;
import CrossBar::*;
import GetPut::*;
import RWBramCore::*;
import FIFO::*;
import Fifos::*;
@@ -9,6 +11,7 @@ import CacheUtils::*;
import CCTypes::*;
import Types::*;
import Vector::*;
import BuildVector::*;
import ProcTypes::*;
typedef enum {
@@ -512,6 +515,221 @@ module mkTargetTableBRAM(TargetTableBRAM#(narrowTableSize, wideTableSize)) provi
endmethod
endmodule
interface TargetTableDouble#(numeric type narrowTableSize, numeric type wideTableSize);
method Action sendReadWriteReq(LineAddr addr, HitOrMiss hitMiss);
method ActionValue#(Tuple2#(Maybe#(LineAddr), Maybe#(LineAddr))) readResp();
endinterface
module mkTargetTableDouble(TargetTableDouble#(narrowTableSize, wideTableSize)) provisos
(
NumAlias#(narrowTableIdxBits, TLog#(narrowTableSize)),
NumAlias#(wideTableIdxBits, TLog#(wideTableSize)),
NumAlias#(narrowTableTagBits, TSub#(24, narrowTableIdxBits)),
NumAlias#(wideTableTagBits, TSub#(24, wideTableIdxBits)),
NumAlias#(narrowDistanceBits, 10),
NumAlias#(narrowMaxDistanceAbs, TExp#(TSub#(narrowDistanceBits, 1))),
Alias#(narrowTargetEntryT, NarrowTargetEntry#(narrowTableTagBits, narrowDistanceBits)),
Alias#(wideTargetEntryT, WideTargetEntry#(wideTableTagBits)),
Add#(a__, TLog#(narrowTableSize), 32),
Add#(b__, TLog#(narrowTableSize), 58),
Add#(c__, TLog#(wideTableSize), 32),
Add#(d__, TLog#(wideTableSize), 58)
);
//on any request, read all 4 tables. get prefetches. if it's a miss save both MRU entries.
//on a miss, perform a regular table write to the MRU table. if it's a narrow write, write the old MRU narrow entry to the LRU narrow table.
//one method, readReq, with parameter isMiss. sends read requests to all 4 tables.
//also saves read address
//one method setMRU.
// sends a write request with the previous miss address to the current miss address.
// if narrow table write, then also write the old MRU narrow entry to the LRU narrow table.
//one method, getPrefetches, which also saves all results if isMiss true.
RWBramCore#(Bit#(narrowTableIdxBits), Maybe#(narrowTargetEntryT)) narrowTableMRU <- mkRWBramCoreForwarded;
RWBramCore#(Bit#(wideTableIdxBits), Maybe#(wideTargetEntryT)) wideTableMRU <- mkRWBramCoreForwarded;
RWBramCore#(Bit#(narrowTableIdxBits), Maybe#(narrowTargetEntryT)) narrowTableLRU <- mkRWBramCoreForwarded;
RWBramCore#(Bit#(wideTableIdxBits), Maybe#(wideTargetEntryT)) wideTableLRU <- mkRWBramCoreForwarded;
Reg#(LineAddr) readReqLineAddr <- mkReg(0);
Reg#(HitOrMiss) readReqHitMiss <- mkReg(HIT);
Reg#(LineAddr) lastMissAddr <- mkReg(0);
Reg#(Maybe#(wideTargetEntryT)) lastMissWideMRUEntry <- mkReg(unpack(0));
Reg#(Maybe#(narrowTargetEntryT)) lastMissNarrowMRUEntry <- mkReg(unpack(0));
Reg#(Maybe#(wideTargetEntryT)) lastMissWideLRUEntry <- mkReg(unpack(0));
Reg#(Maybe#(narrowTargetEntryT)) lastMissNarrowLRUEntry <- mkReg(unpack(0));
function Bool narrowTagMatch(Bit#(32) addrHash, narrowTargetEntryT narrow);
return narrow.tag == addrHash[23:valueOf(narrowTableIdxBits)];
endfunction
function Bool narrowTagMatchMaybe(Bit#(32) addrHash, Maybe#(narrowTargetEntryT) narrowMaybe);
if (narrowMaybe matches tagged Valid .narrow &&& narrowTagMatch(addrHash, narrow))
return True;
else
return False;
endfunction
function Bool wideTagMatch(Bit#(32) addrHash, wideTargetEntryT wide);
return wide.tag == addrHash[23:valueOf(wideTableIdxBits)];
endfunction
function Bool wideTagMatchMaybe(Bit#(32) addrHash, Maybe#(wideTargetEntryT) wideMaybe);
if (wideMaybe matches tagged Valid .wide &&& wideTagMatch(addrHash, wide))
return True;
else
return False;
endfunction
function ActionValue#(Maybe#(LineAddr))
checkReadResp(LineAddr addr, Bit#(32) addrHash, Maybe#(narrowTargetEntryT) narrowWrapped, Maybe#(wideTargetEntryT) wideWrapped);
actionvalue
if (narrowWrapped matches tagged Valid .narrow
&&& narrowTagMatch(addrHash, narrow)) begin
//$display("%t found narrow table entry %h", $time, addr + signExtend(pack(narrow.distance)));
return Valid(addr + signExtend(pack(narrow.distance)));
end
else if (wideWrapped matches tagged Valid .wide
&&& wideTagMatch(addrHash, wide)) begin
//$display("%t found wide table entry %h", $time, wide.target);
return Valid(wide.target);
end
else
return Invalid;
endactionvalue
endfunction
function Action updateTables(
Bit#(32) lastMissAddrHash,
Bit#(idxBits) idx,
RWBramCore#(Bit#(idxBits), Maybe#(otherEntryT)) otherMRU,
RWBramCore#(Bit#(idxBits), Maybe#(otherEntryT)) otherLRU,
function Bool otherTagMatch(Bit#(32) addrHash, Maybe#(otherEntryT) entry),
function Bool myTagMatch(Bit#(32) addrHash, Maybe#(myEntryT) entry),
Maybe#(otherEntryT) otherMRUEntry,
Maybe#(otherEntryT) otherLRUEntry,
Maybe#(myEntryT) myMRUEntry
);
action
//Am inserting a new table entry into "my" table.
//So need to re-order the entries in the "other" table.
//To maintain the property that can't have both a narrow and wide entry in the same recency table.
if (otherTagMatch(lastMissAddrHash, otherMRUEntry)) begin
//If MRU other entry matches
if (otherTagMatch(lastMissAddrHash, otherLRUEntry)) begin
//If LRU other entry matches
// Shift other down
otherMRU.wrReq(idx, Invalid);
otherLRU.wrReq(idx, otherMRUEntry);
end
else begin
//If LRU other entry doesnt match
// Switch other entries around
otherMRU.wrReq(idx, otherLRUEntry);
otherLRU.wrReq(idx, otherMRUEntry);
end
end
else begin
//If other MRU entry doesn't match
if (otherTagMatch(lastMissAddrHash, otherLRUEntry) &&
myTagMatch(lastMissAddrHash, myMRUEntry)) begin
//will shift my MRU entry down, so
// invalidate other LRU entry
otherLRU.wrReq(idx, Invalid);
end
end
endaction
endfunction
function Action writeMissEntry(LineAddr currAddr);
action
let distance = currAddr - lastMissAddr;
Bit#(32) lastMissAddrHash = hash(lastMissAddr);
$display("%t Recording miss from %x to %x", $time, lastMissAddr, currAddr);
if (abs(distance) < fromInteger(valueOf(narrowMaxDistanceAbs))) begin
//Store lastMissAddr -> currAddr in narrow MRU table
Bit#(narrowTableIdxBits) idx = truncate(lastMissAddrHash);
narrowTargetEntryT entry;
entry.tag = lastMissAddrHash[23:valueOf(narrowTableIdxBits)];
entry.distance = truncate(distance);
if (Valid(entry) != lastMissNarrowMRUEntry) begin
//$display("%t Recording miss -- modifying narrow table", $time);
//Maintain the property that one address can only have
// at most 2 of 4 table entries for it.
//Shift narrow table entries down, storing in MRU.
//But only if the entry was not already the MRU entry.
narrowTableMRU.wrReq(idx, Valid(entry));
narrowTableLRU.wrReq(idx, lastMissNarrowMRUEntry);
Bit#(wideTableIdxBits) wideIdx = truncate(lastMissAddrHash);
updateTables(lastMissAddrHash, wideIdx, wideTableMRU, wideTableLRU, wideTagMatchMaybe, narrowTagMatchMaybe,
lastMissWideMRUEntry, lastMissWideLRUEntry, lastMissNarrowMRUEntry);
end
end
else begin
//Store lastMissAddr -> currAddr in wide MRU table
wideTargetEntryT entry;
Bit#(wideTableIdxBits) idx = truncate(lastMissAddrHash);
entry.tag = lastMissAddrHash[23:valueOf(wideTableIdxBits)];
entry.target = currAddr;
if (Valid(entry) != lastMissWideMRUEntry) begin
//$display("%t Recording miss -- modifying wide table", $time);
wideTableMRU.wrReq(idx, Valid(entry));
wideTableLRU.wrReq(idx, lastMissWideMRUEntry);
Bit#(narrowTableIdxBits) narrowIdx = truncate(lastMissAddrHash);
updateTables(lastMissAddrHash, narrowIdx, narrowTableMRU, narrowTableLRU, narrowTagMatchMaybe, wideTagMatchMaybe,
lastMissNarrowMRUEntry, lastMissNarrowLRUEntry, lastMissWideMRUEntry);
end
end
endaction
endfunction
method Action sendReadWriteReq(LineAddr addr, HitOrMiss hitMiss);
$display("%t send read write req for %x", $time, addr);
Bit#(32) addrHash = hash(addr);
Bit#(narrowTableIdxBits) narrowIdx = truncate(addrHash);
narrowTableMRU.rdReq(narrowIdx);
narrowTableLRU.rdReq(narrowIdx);
Bit#(wideTableIdxBits) wideIdx = truncate(addrHash);
wideTableMRU.rdReq(wideIdx);
wideTableLRU.rdReq(wideIdx);
readReqLineAddr <= addr;
readReqHitMiss <= hitMiss;
endmethod
method ActionValue#(Tuple2#(Maybe#(LineAddr), Maybe#(LineAddr))) readResp();
// Returns the read response and if a table had a hit,
// sends a write request to clear the entry in that table
narrowTableMRU.deqRdResp;
narrowTableLRU.deqRdResp;
wideTableMRU.deqRdResp;
wideTableLRU.deqRdResp;
let addr = readReqLineAddr;
Bit#(32) addrHash = hash(addr);
if (readReqHitMiss == MISS) begin
//Update the entries for the last miss to point to this one
writeMissEntry(addr);
//Save the raw table entries
//$display("idx: %x", addrHash);
//$display("%t Read resp: nMRU: ", fshow(narrowTableMRU.rdResp), "wMRU: ", fshow(wideTableMRU.rdResp));
//$display("%t Read resp: nLRU: ", fshow(narrowTableLRU.rdResp), "wLRU: ", fshow(wideTableLRU.rdResp));
lastMissWideMRUEntry <= wideTableMRU.rdResp;
lastMissNarrowMRUEntry <= narrowTableMRU.rdResp;
lastMissWideLRUEntry <= wideTableLRU.rdResp;
lastMissNarrowLRUEntry <= narrowTableLRU.rdResp;
lastMissAddr <= addr; // save for future use
end
let entryMRU <- checkReadResp(addr, addrHash, narrowTableMRU.rdResp, wideTableMRU.rdResp);
let entryLRU <- checkReadResp(addr, addrHash, narrowTableLRU.rdResp, wideTableLRU.rdResp);
Tuple2#(Maybe#(LineAddr), Maybe#(LineAddr)) retval = tuple2(entryMRU, entryLRU);
$display("%t read resp for %x returning ", $time, addr, fshow(retval));
return retval;
endmethod
endmodule
module mkBRAMSingleWindowTargetPrefetcher(Prefetcher) provisos
(
NumAlias#(numLastRequests, 16)
@@ -852,6 +1070,62 @@ module mkBRAMMarkovOnHitPrefetcher(Prefetcher) provisos
endmodule
module mkMarkovOnHit2Prefetcher(Prefetcher) provisos
(
NumAlias#(maxChainLength, 1),
NumAlias#(numLastRequests, 32),
Alias#(chainLengthT, Bit#(TLog#(TAdd#(maxChainLength,1))))
);
Reg#(LineAddr) lastChildRequest <- mkReg(0);
Reg#(Vector#(numLastRequests, Bit#(32))) lastAddrRequests <- mkReg(replicate(0));
TargetTableDouble#(2048, 256) targetTable <- mkTargetTableDouble;
Fifo#(8, LineAddr) highPriorityPrefetches <- mkOverflowBypassFifo;
Fifo#(8, LineAddr) lowPriorityPrefetches <- mkOverflowBypassFifo;
//on reportAccess, read the current address in both tables, and save it
// Next cycle, add any found next lines to prefetch queues. Have 2 prefetch queues, High and low priority.
// If this was a miss, save as lastMissEntry
// And issue a write of table[lastMissEntry] = thisMiss.
// but checking for LRU and everything.
rule addPrefetchesToQueues;
match { .highPrio, .lowPrio } <- targetTable.readResp();
if (highPrio matches tagged Valid .cl)
highPriorityPrefetches.enq(cl);
if (lowPrio matches tagged Valid .cl)
lowPriorityPrefetches.enq(cl);
endrule
method ActionValue#(Addr) getNextPrefetchAddr
if (highPriorityPrefetches.notEmpty || lowPriorityPrefetches.notEmpty);
//if (false);
Addr retAddr = unpack(0);
if (highPriorityPrefetches.notEmpty) begin
retAddr = {highPriorityPrefetches.first, '0};
highPriorityPrefetches.deq;
end
else if (lowPriorityPrefetches.notEmpty) begin
retAddr = {lowPriorityPrefetches.first, '0};
lowPriorityPrefetches.deq;
end
$display("%t Prefetcher getNextPrefetchAddr requesting chain entry %h", $time, retAddr);
return retAddr;
endmethod
method Action reportAccess(Addr addr, HitOrMiss hitMiss);
let cl = getLineAddr(addr);
if (hitMiss == MISS)
$display("%t Prefetcher report MISS %h", $time, addr);
if (hitMiss == MISS || !elem(hash(cl), lastAddrRequests)) begin
//Don't start a markov chain if we started a markov chain with that address recently
$display("%t Prefetcher start new chain with %h", $time, addr);
targetTable.sendReadWriteReq(cl, hitMiss);
lastAddrRequests <= shiftInAt0(lastAddrRequests, hash(cl));
end
endmethod
endmodule
module mkBlockPrefetcher(Prefetcher) provisos (
NumAlias#(numLinesEachWay, 1),
Alias#(lineCountT, Bit#(TLog#(TAdd#(numLinesEachWay, 1))))
@@ -1582,6 +1856,8 @@ module mkL1DPrefetcher(PCPrefetcher);
let m <- mkPCPrefetcherAdapter(mkBRAMMarkovPrefetcher);
`elsif DATA_PREFETCHER_MARKOV_ON_HIT
let m <- mkPCPrefetcherAdapter(mkBRAMMarkovOnHitPrefetcher);
`elsif DATA_PREFETCHER_MARKOV_ON_HIT_2
let m <- mkPCPrefetcherAdapter(mkMarkovOnHit2Prefetcher);
`endif
//let m <- mkPCPrefetcherAdapter(mkAlwaysRequestPrefetcher);
`else
@@ -1602,6 +1878,8 @@ module mkLLDPrefetcherInL1D(PCPrefetcher);
let m <- mkPCPrefetcherAdapter(mkBRAMMarkovPrefetcher);
`elsif DATA_PREFETCHER_MARKOV_ON_HIT
let m <- mkPCPrefetcherAdapter(mkBRAMMarkovOnHitPrefetcher);
`elsif DATA_PREFETCHER_MARKOV_ON_HIT_2
let m <- mkPCPrefetcherAdapter(mkMarkovOnHit2Prefetcher);
`endif
//let m <- mkPCPrefetcherAdapter(mkAlwaysRequestPrefetcher);
`else
@@ -1622,6 +1900,8 @@ module mkLLDPrefetcher(Prefetcher);
let m <- mkBRAMMarkovPrefetcher;
`elsif DATA_PREFETCHER_MARKOV_ON_HIT
let m <- mkBRAMMarkovOnHitPrefetcher;
`elsif DATA_PREFETCHER_MARKOV_ON_HIT_2
let m <- mkMarkovOnHit2Prefetcher;
`endif
//let m <- mkPCPrefetcherAdapter(mkAlwaysRequestPrefetcher);
`else