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:
committed by
Daniel Carvalho
parent
9388ec18a4
commit
32bce3301d
71
src/mem/cache/base.cc
vendored
71
src/mem/cache/base.cc
vendored
@@ -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
41
src/mem/cache/base.hh
vendored
@@ -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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user