From 3a9643739a4c7b516a3f64dac0941634af1d8f78 Mon Sep 17 00:00:00 2001 From: Michael Davies Date: Tue, 4 Dec 2018 11:36:46 -0600 Subject: [PATCH] [prefetcher] Fix issue causing a race condition between cache access and invalidates When the prefetcher issues memory requests, it uses the same child lock as the given demand request. This means when the parent cache begins its transaction, it gives up this lock meaning a pending invalidate could overwrite the demand request before the response is sent back to the child cache. This causes an assert failure in the cache coherence code (coherence_ctrls.cpp:114). This fix resolves the issue by performing the demand access LAST in the prefetcher's access routine. This ensures the request always returns with a valid coherence state and does not cause the assert failure. --- src/prefetcher.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/prefetcher.cpp b/src/prefetcher.cpp index b440c4ce..053c53ad 100644 --- a/src/prefetcher.cpp +++ b/src/prefetcher.cpp @@ -65,7 +65,7 @@ uint64_t StreamPrefetcher::access(MemReq& req) { profAccesses.inc(); uint64_t reqCycle = req.cycle; - uint64_t respCycle = parent->access(req); + uint64_t respCycle = reqCycle; Address pageAddr = req.lineAddr >> 6; uint32_t pos = req.lineAddr & (64-1); @@ -139,7 +139,7 @@ uint64_t StreamPrefetcher::access(MemReq& req) { if (prefetchPos < 64 && !e.valid[prefetchPos]) { MESIState state = I; MemReq pfReq = {req.lineAddr + prefetchPos - pos, GETS, req.childId, &state, reqCycle, req.childLock, state, req.srcId, MemReq::PREFETCH}; - uint64_t pfRespCycle = parent->access(pfReq); // FIXME, might segfault + uint64_t pfRespCycle = parent->access(pfReq); e.valid[prefetchPos] = true; e.times[prefetchPos].fill(reqCycle, pfRespCycle); profPrefetches.inc(); @@ -179,6 +179,11 @@ uint64_t StreamPrefetcher::access(MemReq& req) { } req.childId = origChildId; + + // Demand access must be executed _after_ any prefetch accesses to avoid a race + // condition that could invalidate the demand request before returning. + respCycle = MAX(respCycle, parent->access(req)); + return respCycle; } @@ -186,5 +191,3 @@ uint64_t StreamPrefetcher::access(MemReq& req) { uint64_t StreamPrefetcher::invalidate(const InvReq& req) { return child->invalidate(req); } - -