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 <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/37096
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Daniel R. Carvalho
2020-11-01 13:17:55 +01:00
committed by Daniel Carvalho
parent 9388ec18a4
commit 32bce3301d
2 changed files with 108 additions and 4 deletions

71
src/mem/cache/base.cc vendored
View File

@@ -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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<PacketPtr>(this->getProbeManager(), "Hit");
ppMiss = new ProbePointArg<PacketPtr>(this->getProbeManager(), "Miss");
ppFill = new ProbePointArg<PacketPtr>(this->getProbeManager(), "Fill");
ppDataUpdate =
new ProbePointArg<DataUpdate>(this->getProbeManager(), "Data Update");
}
///////////////

41
src/mem/cache/base.hh vendored
View File

@@ -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<uint64_t> oldData;
/** The new data contents. If zero-sized this is an invalidation. */
std::vector<uint64_t> 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<PacketPtr> *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<DataUpdate> *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.
*/