From: Daniel R. Carvalho Date: Sun, 1 Nov 2020 12:17:55 +0000 (+0100) Subject: mem-cache: Add a data-update probe to cache X-Git-Tag: develop-gem5-snapshot~355 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=32bce3301ded61a4ad62ad0503d2d0c0e628b616;p=gem5.git mem-cache: Add a data-update probe to cache This probe is responsible for notifying any changes to the data contents of a block. This includes fills, overwrites, and invalidations/evictions. Jira: https://gem5.atlassian.net/browse/GEM5-814 Change-Id: I1ff3c09c63d5402765c2125c4d76d95b614877d6 Signed-off-by: Daniel R. Carvalho Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/37096 Reviewed-by: Nikos Nikoleris Maintainer: Nikos Nikoleris Tested-by: kokoro --- diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc index 98467ab98..22c28421d 100644 --- a/src/mem/cache/base.cc +++ b/src/mem/cache/base.cc @@ -676,6 +676,31 @@ BaseCache::functionalAccess(PacketPtr pkt, bool from_cpu_side) } } +void +BaseCache::updateBlockData(CacheBlk *blk, const PacketPtr cpkt, + bool has_old_data) +{ + DataUpdate data_update(regenerateBlkAddr(blk), blk->isSecure()); + if (ppDataUpdate->hasListeners()) { + if (has_old_data) { + data_update.oldData = std::vector(blk->data, + blk->data + (blkSize / sizeof(uint64_t))); + } + } + + // Actually perform the data update + if (cpkt) { + cpkt->writeDataToBlock(blk->data, blkSize); + } + + if (ppDataUpdate->hasListeners()) { + if (cpkt) { + data_update.newData = std::vector(blk->data, + blk->data + (blkSize / sizeof(uint64_t))); + } + ppDataUpdate->notify(data_update); + } +} void BaseCache::cmpAndSwap(CacheBlk *blk, PacketPtr pkt) @@ -692,6 +717,13 @@ BaseCache::cmpAndSwap(CacheBlk *blk, PacketPtr pkt) assert(sizeof(uint64_t) >= pkt->getSize()); + // Get a copy of the old block's contents for the probe before the update + DataUpdate data_update(regenerateBlkAddr(blk), blk->isSecure()); + if (ppDataUpdate->hasListeners()) { + data_update.oldData = std::vector(blk->data, + blk->data + (blkSize / sizeof(uint64_t))); + } + overwrite_mem = true; // keep a copy of our possible write value, and copy what is at the // memory address into the packet @@ -714,6 +746,12 @@ BaseCache::cmpAndSwap(CacheBlk *blk, PacketPtr pkt) if (overwrite_mem) { std::memcpy(blk_data, &overwrite_val, pkt->getSize()); blk->setCoherenceBits(CacheBlk::DirtyBit); + + if (ppDataUpdate->hasListeners()) { + data_update.newData = std::vector(blk->data, + blk->data + (blkSize / sizeof(uint64_t))); + ppDataUpdate->notify(data_update); + } } } @@ -961,6 +999,14 @@ BaseCache::satisfyRequest(PacketPtr pkt, CacheBlk *blk, bool, bool) // isWrite() will be true for them if (pkt->cmd == MemCmd::SwapReq) { if (pkt->isAtomicOp()) { + // Get a copy of the old block's contents for the probe before + // the update + DataUpdate data_update(regenerateBlkAddr(blk), blk->isSecure()); + if (ppDataUpdate->hasListeners()) { + data_update.oldData = std::vector(blk->data, + blk->data + (blkSize / sizeof(uint64_t))); + } + // extract data from cache and save it into the data field in // the packet as a return value from this atomic op int offset = tags->extractBlkOffset(pkt->getAddr()); @@ -970,6 +1016,13 @@ BaseCache::satisfyRequest(PacketPtr pkt, CacheBlk *blk, bool, bool) // execute AMO operation (*(pkt->getAtomicOp()))(blk_data); + // Inform of this block's data contents update + if (ppDataUpdate->hasListeners()) { + data_update.newData = std::vector(blk->data, + blk->data + (blkSize / sizeof(uint64_t))); + ppDataUpdate->notify(data_update); + } + // set block status to dirty blk->setCoherenceBits(CacheBlk::DirtyBit); } else { @@ -983,7 +1036,7 @@ BaseCache::satisfyRequest(PacketPtr pkt, CacheBlk *blk, bool, bool) assert(blk->isSet(CacheBlk::WritableBit)); // Write or WriteLine at the first cache with block in writable state if (blk->checkWrite(pkt)) { - pkt->writeDataToBlock(blk->data, blkSize); + updateBlockData(blk, pkt, true); } // Always mark the line as dirty (and thus transition to the // Modified state) even if we are a failed StoreCond so we @@ -1170,6 +1223,7 @@ BaseCache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, return true; } + const bool has_old_data = blk && blk->isValid(); if (!blk) { // need to do a replacement blk = allocateBlock(pkt, writebacks); @@ -1206,7 +1260,8 @@ BaseCache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, } // nothing else to do; writeback doesn't expect response assert(!pkt->needsResponse()); - pkt->writeDataToBlock(blk->data, blkSize); + + updateBlockData(blk, pkt, has_old_data); DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print()); incHitCount(pkt); @@ -1240,6 +1295,7 @@ BaseCache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, // of the block as well. assert(blkSize == pkt->getSize()); + const bool has_old_data = blk && blk->isValid(); if (!blk) { if (pkt->writeThrough()) { // if this is a write through packet, we don't try to @@ -1279,7 +1335,8 @@ BaseCache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, } // nothing else to do; writeback doesn't expect response assert(!pkt->needsResponse()); - pkt->writeDataToBlock(blk->data, blkSize); + + updateBlockData(blk, pkt, has_old_data); DPRINTF(Cache, "%s new state is %s\n", __func__, blk->print()); incHitCount(pkt); @@ -1352,6 +1409,7 @@ BaseCache::handleFill(PacketPtr pkt, CacheBlk *blk, PacketList &writebacks, assert(pkt->isResponse()); Addr addr = pkt->getAddr(); bool is_secure = pkt->isSecure(); + const bool has_old_data = blk && blk->isValid(); #if TRACING_ON const std::string old_state = blk ? blk->print() : ""; #endif @@ -1433,7 +1491,7 @@ BaseCache::handleFill(PacketPtr pkt, CacheBlk *blk, PacketList &writebacks, assert(pkt->hasData()); assert(pkt->getSize() == blkSize); - pkt->writeDataToBlock(blk->data, blkSize); + updateBlockData(blk, pkt, has_old_data); } // The block will be ready when the payload arrives and the fill is done blk->setWhenReady(clockEdge(fillLatency) + pkt->headerDelay + @@ -1507,6 +1565,9 @@ BaseCache::invalidateBlock(CacheBlk *blk) stats.unusedPrefetches++; } + // Notify that the data contents for this address are no longer present + updateBlockData(blk, nullptr, blk->isValid()); + // If handling a block present in the Tags, let it do its invalidation // process, which will update stats and invalidate the block itself if (blk != tempBlock) { @@ -2325,6 +2386,8 @@ BaseCache::regProbePoints() ppHit = new ProbePointArg(this->getProbeManager(), "Hit"); ppMiss = new ProbePointArg(this->getProbeManager(), "Miss"); ppFill = new ProbePointArg(this->getProbeManager(), "Fill"); + ppDataUpdate = + new ProbePointArg(this->getProbeManager(), "Data Update"); } /////////////// diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh index 8dad1b7f7..5342eaab0 100644 --- a/src/mem/cache/base.hh +++ b/src/mem/cache/base.hh @@ -108,6 +108,28 @@ class BaseCache : public ClockedObject NUM_BLOCKED_CAUSES }; + /** + * A data contents update is composed of the updated block's address, + * the old contents, and the new contents. + * @sa ppDataUpdate + */ + struct DataUpdate + { + /** The updated block's address. */ + Addr addr; + /** Whether the block belongs to the secure address space. */ + bool isSecure; + /** The stale data contents. If zero-sized this update is a fill. */ + std::vector oldData; + /** The new data contents. If zero-sized this is an invalidation. */ + std::vector newData; + + DataUpdate(Addr _addr, bool is_secure) + : addr(_addr), isSecure(is_secure), oldData(), newData() + { + } + }; + protected: /** @@ -334,6 +356,13 @@ class BaseCache : public ClockedObject /** To probe when a cache fill occurs */ ProbePointArg *ppFill; + /** + * To probe when the contents of a block are updated. Content updates + * include data fills, overwrites, and invalidations, which means that + * this probe partially overlaps with other probes. + */ + ProbePointArg *ppDataUpdate; + /** * The writeAllocator drive optimizations for streaming writes. * It first determines whether a WriteReq MSHR should be delayed, @@ -574,6 +603,18 @@ class BaseCache : public ClockedObject */ virtual void functionalAccess(PacketPtr pkt, bool from_cpu_side); + /** + * Update the data contents of a block. When no packet is provided no + * data will be written to the block, which means that this was likely + * triggered by an invalidation. + * + * @param blk The block being updated. + * @param cpkt The packet containing the new data. + * @param has_old_data Whether this block had data previously. + */ + void updateBlockData(CacheBlk *blk, const PacketPtr cpkt, + bool has_old_data); + /** * Handle doing the Compare and Swap function for SPARC. */