mem: Add PacketInfo to be used for packet probe points
This patch fixes a use-after-delete issue in the packet probe points by adding a PacketInfo struct to retain the key fields before passing the packet onwards. We want to probe the packet after it is successfully sent, but by that time the fields may be modified, and the packet may even be deleted. Amazingly enough the issue has gone undetected for months, and only recently popped up in our regressions.
This commit is contained in:
parent
806e1fbf0f
commit
9a0129dcbf
7 changed files with 56 additions and 43 deletions
|
@ -115,11 +115,13 @@ CommMonitor::recvFunctionalSnoop(PacketPtr pkt)
|
||||||
Tick
|
Tick
|
||||||
CommMonitor::recvAtomic(PacketPtr pkt)
|
CommMonitor::recvAtomic(PacketPtr pkt)
|
||||||
{
|
{
|
||||||
ppPktReq->notify(pkt);
|
ProbePoints::PacketInfo req_pkt_info(pkt);
|
||||||
|
ppPktReq->notify(req_pkt_info);
|
||||||
|
|
||||||
const Tick delay(masterPort.sendAtomic(pkt));
|
const Tick delay(masterPort.sendAtomic(pkt));
|
||||||
assert(pkt->isResponse());
|
assert(pkt->isResponse());
|
||||||
ppPktResp->notify(pkt);
|
ProbePoints::PacketInfo resp_pkt_info(pkt);
|
||||||
|
ppPktResp->notify(resp_pkt_info);
|
||||||
return delay;
|
return delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,11 +139,10 @@ CommMonitor::recvTimingReq(PacketPtr pkt)
|
||||||
|
|
||||||
// Store relevant fields of packet, because packet may be modified
|
// Store relevant fields of packet, because packet may be modified
|
||||||
// or even deleted when sendTiming() is called.
|
// or even deleted when sendTiming() is called.
|
||||||
|
const ProbePoints::PacketInfo pkt_info(pkt);
|
||||||
|
|
||||||
const bool is_read = pkt->isRead();
|
const bool is_read = pkt->isRead();
|
||||||
const bool is_write = pkt->isWrite();
|
const bool is_write = pkt->isWrite();
|
||||||
const MemCmd cmd = pkt->cmd;
|
|
||||||
const unsigned size = pkt->getSize();
|
|
||||||
const Addr addr = pkt->getAddr();
|
|
||||||
const bool expects_response(
|
const bool expects_response(
|
||||||
pkt->needsResponse() && !pkt->memInhibitAsserted());
|
pkt->needsResponse() && !pkt->memInhibitAsserted());
|
||||||
|
|
||||||
|
@ -163,14 +164,7 @@ CommMonitor::recvTimingReq(PacketPtr pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (successful) {
|
if (successful) {
|
||||||
// The receiver might already have modified the packet. We
|
ppPktReq->notify(pkt_info);
|
||||||
// want to give the probe access to the original packet, which
|
|
||||||
// means we need to fake the original packet by temporarily
|
|
||||||
// restoring the command.
|
|
||||||
const MemCmd response_cmd(pkt->cmd);
|
|
||||||
pkt->cmd = cmd;
|
|
||||||
ppPktReq->notify(pkt);
|
|
||||||
pkt->cmd = response_cmd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (successful && is_read) {
|
if (successful && is_read) {
|
||||||
|
@ -183,12 +177,12 @@ CommMonitor::recvTimingReq(PacketPtr pkt)
|
||||||
|
|
||||||
// Get sample of burst length
|
// Get sample of burst length
|
||||||
if (!stats.disableBurstLengthHists) {
|
if (!stats.disableBurstLengthHists) {
|
||||||
stats.readBurstLengthHist.sample(size);
|
stats.readBurstLengthHist.sample(pkt_info.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample the masked address
|
// Sample the masked address
|
||||||
if (!stats.disableAddrDists) {
|
if (!stats.disableAddrDists) {
|
||||||
stats.readAddrDist.sample(addr & readAddrMask);
|
stats.readAddrDist.sample(pkt_info.addr & readAddrMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it needs a response increment number of outstanding read
|
// If it needs a response increment number of outstanding read
|
||||||
|
@ -219,18 +213,18 @@ CommMonitor::recvTimingReq(PacketPtr pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stats.disableBurstLengthHists) {
|
if (!stats.disableBurstLengthHists) {
|
||||||
stats.writeBurstLengthHist.sample(size);
|
stats.writeBurstLengthHist.sample(pkt_info.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the bandwidth stats on the request
|
// Update the bandwidth stats on the request
|
||||||
if (!stats.disableBandwidthHists) {
|
if (!stats.disableBandwidthHists) {
|
||||||
stats.writtenBytes += size;
|
stats.writtenBytes += pkt_info.size;
|
||||||
stats.totalWrittenBytes += size;
|
stats.totalWrittenBytes += pkt_info.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample the masked write address
|
// Sample the masked write address
|
||||||
if (!stats.disableAddrDists) {
|
if (!stats.disableAddrDists) {
|
||||||
stats.writeAddrDist.sample(addr & writeAddrMask);
|
stats.writeAddrDist.sample(pkt_info.addr & writeAddrMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stats.disableOutstandingHists && expects_response) {
|
if (!stats.disableOutstandingHists && expects_response) {
|
||||||
|
@ -265,9 +259,10 @@ CommMonitor::recvTimingResp(PacketPtr pkt)
|
||||||
|
|
||||||
// Store relevant fields of packet, because packet may be modified
|
// Store relevant fields of packet, because packet may be modified
|
||||||
// or even deleted when sendTiming() is called.
|
// or even deleted when sendTiming() is called.
|
||||||
|
const ProbePoints::PacketInfo pkt_info(pkt);
|
||||||
|
|
||||||
bool is_read = pkt->isRead();
|
bool is_read = pkt->isRead();
|
||||||
bool is_write = pkt->isWrite();
|
bool is_write = pkt->isWrite();
|
||||||
unsigned size = pkt->getSize();
|
|
||||||
Tick latency = 0;
|
Tick latency = 0;
|
||||||
CommMonitorSenderState* received_state =
|
CommMonitorSenderState* received_state =
|
||||||
dynamic_cast<CommMonitorSenderState*>(pkt->senderState);
|
dynamic_cast<CommMonitorSenderState*>(pkt->senderState);
|
||||||
|
@ -299,8 +294,7 @@ CommMonitor::recvTimingResp(PacketPtr pkt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (successful) {
|
if (successful) {
|
||||||
assert(pkt->isResponse());
|
ppPktResp->notify(pkt_info);
|
||||||
ppPktResp->notify(pkt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (successful && is_read) {
|
if (successful && is_read) {
|
||||||
|
@ -317,8 +311,8 @@ CommMonitor::recvTimingResp(PacketPtr pkt)
|
||||||
|
|
||||||
// Update the bandwidth stats based on responses for reads
|
// Update the bandwidth stats based on responses for reads
|
||||||
if (!stats.disableBandwidthHists) {
|
if (!stats.disableBandwidthHists) {
|
||||||
stats.readBytes += size;
|
stats.readBytes += pkt_info.size;
|
||||||
stats.totalReadBytes += size;
|
stats.totalReadBytes += pkt_info.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (successful && is_write) {
|
} else if (successful && is_write) {
|
||||||
|
|
|
@ -43,8 +43,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "mem/packet.hh"
|
#include "sim/probe/mem.hh"
|
||||||
#include "sim/probe/probe.hh"
|
|
||||||
#include "sim/sim_object.hh"
|
#include "sim/sim_object.hh"
|
||||||
|
|
||||||
struct BaseMemProbeParams;
|
struct BaseMemProbeParams;
|
||||||
|
@ -72,10 +71,10 @@ class BaseMemProbe : public SimObject
|
||||||
/**
|
/**
|
||||||
* Callback to analyse intercepted Packets.
|
* Callback to analyse intercepted Packets.
|
||||||
*/
|
*/
|
||||||
virtual void handleRequest(const PacketPtr &pkt) = 0;
|
virtual void handleRequest(const ProbePoints::PacketInfo &pkt_info) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class PacketListener : public ProbeListenerArgBase<PacketPtr>
|
class PacketListener : public ProbeListenerArgBase<ProbePoints::PacketInfo>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PacketListener(BaseMemProbe &_parent,
|
PacketListener(BaseMemProbe &_parent,
|
||||||
|
@ -83,8 +82,8 @@ class BaseMemProbe : public SimObject
|
||||||
: ProbeListenerArgBase(pm, name),
|
: ProbeListenerArgBase(pm, name),
|
||||||
parent(_parent) {}
|
parent(_parent) {}
|
||||||
|
|
||||||
void notify(const PacketPtr &pkt) M5_ATTR_OVERRIDE {
|
void notify(const ProbePoints::PacketInfo &pkt_info) M5_ATTR_OVERRIDE {
|
||||||
parent.handleRequest(pkt);
|
parent.handleRequest(pkt_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -93,15 +93,15 @@ MemTraceProbe::closeStreams()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MemTraceProbe::handleRequest(const PacketPtr &pkt)
|
MemTraceProbe::handleRequest(const ProbePoints::PacketInfo &pkt_info)
|
||||||
{
|
{
|
||||||
ProtoMessage::Packet pkt_msg;
|
ProtoMessage::Packet pkt_msg;
|
||||||
|
|
||||||
pkt_msg.set_tick(curTick());
|
pkt_msg.set_tick(curTick());
|
||||||
pkt_msg.set_cmd(pkt->cmdToIndex());
|
pkt_msg.set_cmd(pkt_info.cmd.toInt());
|
||||||
pkt_msg.set_flags(pkt->req->getFlags());
|
pkt_msg.set_flags(pkt_info.flags);
|
||||||
pkt_msg.set_addr(pkt->getAddr());
|
pkt_msg.set_addr(pkt_info.addr);
|
||||||
pkt_msg.set_size(pkt->getSize());
|
pkt_msg.set_size(pkt_info.size);
|
||||||
|
|
||||||
traceStream->write(pkt_msg);
|
traceStream->write(pkt_msg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,8 @@ class MemTraceProbe : public BaseMemProbe
|
||||||
MemTraceProbe(MemTraceProbeParams *params);
|
MemTraceProbe(MemTraceProbeParams *params);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void handleRequest(const PacketPtr &pkt) M5_ATTR_OVERRIDE;
|
void handleRequest(const ProbePoints::PacketInfo &pkt_info) \
|
||||||
|
M5_ATTR_OVERRIDE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to flush and close all open output streams on exit. If
|
* Callback to flush and close all open output streams on exit. If
|
||||||
|
|
|
@ -94,15 +94,15 @@ StackDistProbe::regStats()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StackDistProbe::handleRequest(const PacketPtr &pkt)
|
StackDistProbe::handleRequest(const ProbePoints::PacketInfo &pkt_info)
|
||||||
{
|
{
|
||||||
// only capturing read and write requests (which allocate in the
|
// only capturing read and write requests (which allocate in the
|
||||||
// cache)
|
// cache)
|
||||||
if (!pkt->isRead() && !pkt->isWrite())
|
if (!pkt_info.cmd.isRead() && !pkt_info.cmd.isWrite())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Align the address to a cache line size
|
// Align the address to a cache line size
|
||||||
const Addr aligned_addr(roundDown(pkt->getAddr(), lineSize));
|
const Addr aligned_addr(roundDown(pkt_info.addr, lineSize));
|
||||||
|
|
||||||
// Calculate the stack distance
|
// Calculate the stack distance
|
||||||
const uint64_t sd(calc.calcStackDistAndUpdate(aligned_addr).first);
|
const uint64_t sd(calc.calcStackDistAndUpdate(aligned_addr).first);
|
||||||
|
@ -113,7 +113,7 @@ StackDistProbe::handleRequest(const PacketPtr &pkt)
|
||||||
|
|
||||||
// Sample the stack distance of the address in linear bins
|
// Sample the stack distance of the address in linear bins
|
||||||
if (!disableLinearHists) {
|
if (!disableLinearHists) {
|
||||||
if (pkt->isRead())
|
if (pkt_info.cmd.isRead())
|
||||||
readLinearHist.sample(sd);
|
readLinearHist.sample(sd);
|
||||||
else
|
else
|
||||||
writeLinearHist.sample(sd);
|
writeLinearHist.sample(sd);
|
||||||
|
@ -123,7 +123,7 @@ StackDistProbe::handleRequest(const PacketPtr &pkt)
|
||||||
int sd_lg2 = sd == 0 ? 1 : floorLog2(sd);
|
int sd_lg2 = sd == 0 ? 1 : floorLog2(sd);
|
||||||
|
|
||||||
// Sample the stack distance of the address in log bins
|
// Sample the stack distance of the address in log bins
|
||||||
if (pkt->isRead())
|
if (pkt_info.cmd.isRead())
|
||||||
readLogHist.sample(sd_lg2);
|
readLogHist.sample(sd_lg2);
|
||||||
else
|
else
|
||||||
writeLogHist.sample(sd_lg2);
|
writeLogHist.sample(sd_lg2);
|
||||||
|
|
|
@ -55,7 +55,8 @@ class StackDistProbe : public BaseMemProbe
|
||||||
void regStats() M5_ATTR_OVERRIDE;
|
void regStats() M5_ATTR_OVERRIDE;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void handleRequest(const PacketPtr &pkt) M5_ATTR_OVERRIDE;
|
void handleRequest(const ProbePoints::PacketInfo &pkt_info) \
|
||||||
|
M5_ATTR_OVERRIDE;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Cache line size to simulate
|
// Cache line size to simulate
|
||||||
|
|
|
@ -46,6 +46,24 @@
|
||||||
|
|
||||||
namespace ProbePoints {
|
namespace ProbePoints {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A struct to hold on to the essential fields from a packet, so that
|
||||||
|
* the packet and underlying request can be safely passed on, and
|
||||||
|
* consequently modified or even deleted.
|
||||||
|
*/
|
||||||
|
struct PacketInfo {
|
||||||
|
MemCmd cmd;
|
||||||
|
Addr addr;
|
||||||
|
uint32_t size;
|
||||||
|
Request::FlagsType flags;
|
||||||
|
|
||||||
|
explicit PacketInfo(const PacketPtr& pkt) :
|
||||||
|
cmd(pkt->cmd),
|
||||||
|
addr(pkt->getAddr()),
|
||||||
|
size(pkt->getSize()),
|
||||||
|
flags(pkt->req->getFlags()) { }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Packet probe point
|
* Packet probe point
|
||||||
*
|
*
|
||||||
|
@ -79,7 +97,7 @@ namespace ProbePoints {
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef ProbePointArg< ::PacketPtr> Packet;
|
typedef ProbePointArg<PacketInfo> Packet;
|
||||||
typedef std::unique_ptr<Packet> PacketUPtr;
|
typedef std::unique_ptr<Packet> PacketUPtr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue