}
}
+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)
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
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);
+ }
}
}
// 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());
// 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 {
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
return true;
}
+ const bool has_old_data = blk && blk->isValid();
if (!blk) {
// need to do a replacement
blk = allocateBlock(pkt, writebacks);
}
// 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);
// 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
}
// 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);
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
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 +
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) {
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");
}
///////////////
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:
/**
/** 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,
*/
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.
*/