cpu: Support virtual addr in elastic traces
This patch adds support to optionally capture the virtual address and asid for load/store instructions in the elastic traces. If they are present in the traces, Trace CPU will set those fields of the request during replay.
This commit is contained in:
parent
3080bbcc36
commit
54519fd51f
9 changed files with 86 additions and 32 deletions
|
@ -59,4 +59,6 @@ class ElasticTrace(ProbeListenerObject):
|
||||||
"after which to start tracing. Default " \
|
"after which to start tracing. Default " \
|
||||||
"zero means start tracing from first " \
|
"zero means start tracing from first " \
|
||||||
"committed instruction.")
|
"committed instruction.")
|
||||||
|
# Whether to trace virtual addresses for memory accesses
|
||||||
|
traceVirtAddr = Param.Bool(False, "Set to true if virtual addresses are " \
|
||||||
|
"to be traced.")
|
||||||
|
|
|
@ -57,7 +57,8 @@ ElasticTrace::ElasticTrace(const ElasticTraceParams* params)
|
||||||
dataTraceStream(nullptr),
|
dataTraceStream(nullptr),
|
||||||
instTraceStream(nullptr),
|
instTraceStream(nullptr),
|
||||||
startTraceInst(params->startTraceInst),
|
startTraceInst(params->startTraceInst),
|
||||||
allProbesReg(false)
|
allProbesReg(false),
|
||||||
|
traceVirtAddr(params->traceVirtAddr)
|
||||||
{
|
{
|
||||||
cpu = dynamic_cast<FullO3CPU<O3CPUImpl>*>(params->manager);
|
cpu = dynamic_cast<FullO3CPU<O3CPUImpl>*>(params->manager);
|
||||||
fatal_if(!cpu, "Manager of %s is not of type O3CPU and thus does not "\
|
fatal_if(!cpu, "Manager of %s is not of type O3CPU and thus does not "\
|
||||||
|
@ -391,7 +392,9 @@ ElasticTrace::addDepTraceRecord(const DynInstPtr &head_inst,
|
||||||
|
|
||||||
// Assign fields for creating a request in case of a load/store
|
// Assign fields for creating a request in case of a load/store
|
||||||
new_record->reqFlags = head_inst->memReqFlags;
|
new_record->reqFlags = head_inst->memReqFlags;
|
||||||
new_record->addr = head_inst->physEffAddrLow;
|
new_record->virtAddr = head_inst->effAddr;
|
||||||
|
new_record->asid = head_inst->asid;
|
||||||
|
new_record->physAddr = head_inst->physEffAddrLow;
|
||||||
// Currently the tracing does not support split requests.
|
// Currently the tracing does not support split requests.
|
||||||
new_record->size = head_inst->effSize;
|
new_record->size = head_inst->effSize;
|
||||||
new_record->pc = head_inst->instAddr();
|
new_record->pc = head_inst->instAddr();
|
||||||
|
@ -787,9 +790,9 @@ ElasticTrace::writeDepTrace(uint32_t num_to_write)
|
||||||
"is as follows:\n", temp_ptr->instNum);
|
"is as follows:\n", temp_ptr->instNum);
|
||||||
if (temp_ptr->isLoad() || temp_ptr->isStore()) {
|
if (temp_ptr->isLoad() || temp_ptr->isStore()) {
|
||||||
DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
|
DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
|
||||||
DPRINTFR(ElasticTrace, "\thas a request with addr %i, size %i,"
|
DPRINTFR(ElasticTrace, "\thas a request with phys addr %i, "
|
||||||
" flags %i\n", temp_ptr->addr, temp_ptr->size,
|
"size %i, flags %i\n", temp_ptr->physAddr,
|
||||||
temp_ptr->reqFlags);
|
temp_ptr->size, temp_ptr->reqFlags);
|
||||||
} else {
|
} else {
|
||||||
DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
|
DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
|
||||||
}
|
}
|
||||||
|
@ -813,7 +816,13 @@ ElasticTrace::writeDepTrace(uint32_t num_to_write)
|
||||||
dep_pkt.set_pc(temp_ptr->pc);
|
dep_pkt.set_pc(temp_ptr->pc);
|
||||||
if (temp_ptr->isLoad() || temp_ptr->isStore()) {
|
if (temp_ptr->isLoad() || temp_ptr->isStore()) {
|
||||||
dep_pkt.set_flags(temp_ptr->reqFlags);
|
dep_pkt.set_flags(temp_ptr->reqFlags);
|
||||||
dep_pkt.set_addr(temp_ptr->addr);
|
dep_pkt.set_p_addr(temp_ptr->physAddr);
|
||||||
|
// If tracing of virtual addresses is enabled, set the optional
|
||||||
|
// field for it
|
||||||
|
if (traceVirtAddr) {
|
||||||
|
dep_pkt.set_v_addr(temp_ptr->virtAddr);
|
||||||
|
dep_pkt.set_asid(temp_ptr->asid);
|
||||||
|
}
|
||||||
dep_pkt.set_size(temp_ptr->size);
|
dep_pkt.set_size(temp_ptr->size);
|
||||||
}
|
}
|
||||||
dep_pkt.set_comp_delay(temp_ptr->compDelay);
|
dep_pkt.set_comp_delay(temp_ptr->compDelay);
|
||||||
|
|
|
@ -289,8 +289,12 @@ class ElasticTrace : public ProbeListenerObject
|
||||||
Addr pc;
|
Addr pc;
|
||||||
/* Request flags in case of a load/store instruction */
|
/* Request flags in case of a load/store instruction */
|
||||||
Request::FlagsType reqFlags;
|
Request::FlagsType reqFlags;
|
||||||
/* Request address in case of a load/store instruction */
|
/* Request physical address in case of a load/store instruction */
|
||||||
Addr addr;
|
Addr physAddr;
|
||||||
|
/* Request virtual address in case of a load/store instruction */
|
||||||
|
Addr virtAddr;
|
||||||
|
/* Address space id in case of a load/store instruction */
|
||||||
|
uint32_t asid;
|
||||||
/* Request size in case of a load/store instruction */
|
/* Request size in case of a load/store instruction */
|
||||||
unsigned size;
|
unsigned size;
|
||||||
/** Default Constructor */
|
/** Default Constructor */
|
||||||
|
@ -366,6 +370,9 @@ class ElasticTrace : public ProbeListenerObject
|
||||||
*/
|
*/
|
||||||
bool allProbesReg;
|
bool allProbesReg;
|
||||||
|
|
||||||
|
/** Whether to trace virtual addresses for memory requests. */
|
||||||
|
const bool traceVirtAddr;
|
||||||
|
|
||||||
/** Pointer to the O3CPU that is this listener's parent a.k.a. manager */
|
/** Pointer to the O3CPU that is this listener's parent a.k.a. manager */
|
||||||
FullO3CPU<O3CPUImpl>* cpu;
|
FullO3CPU<O3CPUImpl>* cpu;
|
||||||
|
|
||||||
|
|
|
@ -597,8 +597,9 @@ PacketPtr
|
||||||
TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr)
|
TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
DPRINTF(TraceCPUData, "Executing memory request %lli (addr %d, pc %#x, "
|
DPRINTF(TraceCPUData, "Executing memory request %lli (phys addr %d, "
|
||||||
"size %d, flags %d).\n", node_ptr->seqNum, node_ptr->addr,
|
"virt addr %d, pc %#x, size %d, flags %d).\n",
|
||||||
|
node_ptr->seqNum, node_ptr->physAddr, node_ptr->virtAddr,
|
||||||
node_ptr->pc, node_ptr->size, node_ptr->flags);
|
node_ptr->pc, node_ptr->size, node_ptr->flags);
|
||||||
|
|
||||||
// If the request is strictly ordered, do not send it. Just return nullptr
|
// If the request is strictly ordered, do not send it. Just return nullptr
|
||||||
|
@ -617,17 +618,26 @@ TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr)
|
||||||
// happens. If required the code could be revised to mimick splitting such
|
// happens. If required the code could be revised to mimick splitting such
|
||||||
// a request into two.
|
// a request into two.
|
||||||
unsigned blk_size = owner.cacheLineSize();
|
unsigned blk_size = owner.cacheLineSize();
|
||||||
Addr blk_offset = (node_ptr->addr & (Addr)(blk_size - 1));
|
Addr blk_offset = (node_ptr->physAddr & (Addr)(blk_size - 1));
|
||||||
if (!(blk_offset + node_ptr->size <= blk_size)) {
|
if (!(blk_offset + node_ptr->size <= blk_size)) {
|
||||||
node_ptr->size = blk_size - blk_offset;
|
node_ptr->size = blk_size - blk_offset;
|
||||||
++numSplitReqs;
|
++numSplitReqs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a request and the packet containing request
|
// Create a request and the packet containing request
|
||||||
Request* req = new Request(node_ptr->addr, node_ptr->size, node_ptr->flags,
|
Request* req = new Request(node_ptr->physAddr, node_ptr->size,
|
||||||
masterID, node_ptr->seqNum,
|
node_ptr->flags, masterID, node_ptr->seqNum,
|
||||||
ContextID(0), ThreadID(0));
|
ContextID(0), ThreadID(0));
|
||||||
req->setPC(node_ptr->pc);
|
req->setPC(node_ptr->pc);
|
||||||
|
// If virtual address is valid, set the asid and virtual address fields
|
||||||
|
// of the request.
|
||||||
|
if (node_ptr->virtAddr != 0) {
|
||||||
|
req->setVirt(node_ptr->asid, node_ptr->virtAddr, node_ptr->size,
|
||||||
|
node_ptr->flags, masterID, node_ptr->pc);
|
||||||
|
req->setPaddr(node_ptr->physAddr);
|
||||||
|
req->setReqInstSeqNum(node_ptr->seqNum);
|
||||||
|
}
|
||||||
|
|
||||||
PacketPtr pkt;
|
PacketPtr pkt;
|
||||||
uint8_t* pkt_data = new uint8_t[req->getSize()];
|
uint8_t* pkt_data = new uint8_t[req->getSize()];
|
||||||
if (node_ptr->isLoad()) {
|
if (node_ptr->isLoad()) {
|
||||||
|
@ -1277,10 +1287,20 @@ TraceCPU::ElasticDataGen::InputStream::read(GraphNode* element)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional fields
|
// Optional fields
|
||||||
if (pkt_msg.has_addr())
|
if (pkt_msg.has_p_addr())
|
||||||
element->addr = pkt_msg.addr();
|
element->physAddr = pkt_msg.p_addr();
|
||||||
else
|
else
|
||||||
element->addr = 0;
|
element->physAddr = 0;
|
||||||
|
|
||||||
|
if (pkt_msg.has_v_addr())
|
||||||
|
element->virtAddr = pkt_msg.v_addr();
|
||||||
|
else
|
||||||
|
element->virtAddr = 0;
|
||||||
|
|
||||||
|
if (pkt_msg.has_asid())
|
||||||
|
element->asid = pkt_msg.asid();
|
||||||
|
else
|
||||||
|
element->asid = 0;
|
||||||
|
|
||||||
if (pkt_msg.has_size())
|
if (pkt_msg.has_size())
|
||||||
element->size = pkt_msg.size();
|
element->size = pkt_msg.size();
|
||||||
|
@ -1383,7 +1403,7 @@ TraceCPU::ElasticDataGen::GraphNode::writeElementAsTrace() const
|
||||||
DPRINTFR(TraceCPUData, "%lli", seqNum);
|
DPRINTFR(TraceCPUData, "%lli", seqNum);
|
||||||
DPRINTFR(TraceCPUData, ",%s", typeToStr());
|
DPRINTFR(TraceCPUData, ",%s", typeToStr());
|
||||||
if (isLoad() || isStore()) {
|
if (isLoad() || isStore()) {
|
||||||
DPRINTFR(TraceCPUData, ",%i", addr);
|
DPRINTFR(TraceCPUData, ",%i", physAddr);
|
||||||
DPRINTFR(TraceCPUData, ",%i", size);
|
DPRINTFR(TraceCPUData, ",%i", size);
|
||||||
DPRINTFR(TraceCPUData, ",%i", flags);
|
DPRINTFR(TraceCPUData, ",%i", flags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -596,7 +596,13 @@ class TraceCPU : public BaseCPU
|
||||||
RecordType type;
|
RecordType type;
|
||||||
|
|
||||||
/** The address for the request if any */
|
/** The address for the request if any */
|
||||||
Addr addr;
|
Addr physAddr;
|
||||||
|
|
||||||
|
/** The virtual address for the request if any */
|
||||||
|
Addr virtAddr;
|
||||||
|
|
||||||
|
/** The address space id which is set if the virtual address is set */
|
||||||
|
uint32_t asid;
|
||||||
|
|
||||||
/** Size of request if any */
|
/** Size of request if any */
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
|
|
|
@ -300,7 +300,7 @@ class Request
|
||||||
Addr _pc;
|
Addr _pc;
|
||||||
|
|
||||||
/** Sequence number of the instruction that creates the request */
|
/** Sequence number of the instruction that creates the request */
|
||||||
const InstSeqNum _reqInstSeqNum;
|
InstSeqNum _reqInstSeqNum;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -675,6 +675,13 @@ class Request
|
||||||
return _reqInstSeqNum;
|
return _reqInstSeqNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setReqInstSeqNum(const InstSeqNum seq_num)
|
||||||
|
{
|
||||||
|
privateFlags.set(VALID_INST_SEQ_NUM);
|
||||||
|
_reqInstSeqNum = seq_num;
|
||||||
|
}
|
||||||
|
|
||||||
/** Accessor functions for flags. Note that these are for testing
|
/** Accessor functions for flags. Note that these are for testing
|
||||||
only; setting flags should be done via setFlags(). */
|
only; setting flags should be done via setFlags(). */
|
||||||
bool isUncacheable() const { return _flags.isSet(UNCACHEABLE); }
|
bool isUncacheable() const { return _flags.isSet(UNCACHEABLE); }
|
||||||
|
|
|
@ -69,7 +69,7 @@ message InstDepRecord {
|
||||||
}
|
}
|
||||||
required uint64 seq_num = 1;
|
required uint64 seq_num = 1;
|
||||||
required RecordType type = 2 [default = INVALID];
|
required RecordType type = 2 [default = INVALID];
|
||||||
optional uint64 addr = 3;
|
optional uint64 p_addr = 3;
|
||||||
optional uint32 size = 4;
|
optional uint32 size = 4;
|
||||||
optional uint32 flags = 5;
|
optional uint32 flags = 5;
|
||||||
repeated uint64 rob_dep = 6;
|
repeated uint64 rob_dep = 6;
|
||||||
|
@ -77,4 +77,6 @@ message InstDepRecord {
|
||||||
repeated uint64 reg_dep = 8;
|
repeated uint64 reg_dep = 8;
|
||||||
optional uint32 weight = 9;
|
optional uint32 weight = 9;
|
||||||
optional uint64 pc = 10;
|
optional uint64 pc = 10;
|
||||||
|
optional uint64 v_addr = 11;
|
||||||
|
optional uint32 asid = 12;
|
||||||
}
|
}
|
|
@ -72,12 +72,12 @@
|
||||||
#
|
#
|
||||||
# The ASCII trace format uses one line per instruction with the format
|
# The ASCII trace format uses one line per instruction with the format
|
||||||
# instruction sequence number, (optional) pc, (optional) weight, type
|
# instruction sequence number, (optional) pc, (optional) weight, type
|
||||||
# (optional) flags, (optional) addr, (optional) size, comp delay,
|
# (optional) flags, (optional) phys addr, (optional) size, comp delay,
|
||||||
# (repeated) order dependencies comma-separated, and (repeated) register
|
# (repeated) order dependencies comma-separated, and (repeated) register
|
||||||
# dependencies comma-separated.
|
# dependencies comma-separated.
|
||||||
#
|
#
|
||||||
# examples:
|
# examples:
|
||||||
# seq_num,[pc],[weight,]type,[address,size,flags,]comp_delay:[rob_dep]:
|
# seq_num,[pc],[weight,]type,[p_addr,size,flags,]comp_delay:[rob_dep]:
|
||||||
# [reg_dep]
|
# [reg_dep]
|
||||||
# 1,35652,1,COMP,8500::
|
# 1,35652,1,COMP,8500::
|
||||||
# 2,35656,1,COMP,0:,1:
|
# 2,35656,1,COMP,0:,1:
|
||||||
|
@ -178,9 +178,10 @@ def main():
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
|
|
||||||
# Write to file if it has the optional fields addr, size, flags
|
# Write to file if it has the optional fields physical addr, size,
|
||||||
if packet.HasField('addr'):
|
# flags
|
||||||
ascii_out.write(',%s' % (packet.addr))
|
if packet.HasField('p_addr'):
|
||||||
|
ascii_out.write(',%s' % (packet.p_addr))
|
||||||
if packet.HasField('size'):
|
if packet.HasField('size'):
|
||||||
ascii_out.write(',%s' % (packet.size))
|
ascii_out.write(',%s' % (packet.size))
|
||||||
if packet.HasField('flags'):
|
if packet.HasField('flags'):
|
||||||
|
|
|
@ -72,12 +72,12 @@
|
||||||
#
|
#
|
||||||
# The ASCII trace format uses one line per instruction with the format
|
# The ASCII trace format uses one line per instruction with the format
|
||||||
# instruction sequence number, (optional) pc, (optional) weight, type,
|
# instruction sequence number, (optional) pc, (optional) weight, type,
|
||||||
# (optional) flags, (optional) addr, (optional) size, comp delay,
|
# (optional) flags, (optional) physical addr, (optional) size, comp delay,
|
||||||
# (repeated) order dependencies comma-separated, and (repeated) register
|
# (repeated) order dependencies comma-separated, and (repeated) register
|
||||||
# dependencies comma-separated.
|
# dependencies comma-separated.
|
||||||
#
|
#
|
||||||
# examples:
|
# examples:
|
||||||
# seq_num,[pc],[weight,]type,[address,size,flags,]comp_delay:[rob_dep]:
|
# seq_num,[pc],[weight,]type,[p_addr,size,flags,]comp_delay:[rob_dep]:
|
||||||
# [reg_dep]
|
# [reg_dep]
|
||||||
# 1,35652,1,COMP,8500::
|
# 1,35652,1,COMP,8500::
|
||||||
# 2,35656,1,COMP,0:,1:
|
# 2,35656,1,COMP,0:,1:
|
||||||
|
@ -167,11 +167,11 @@ def main():
|
||||||
print "Seq. num", dep_record.seq_num, "is of INVALID type"
|
print "Seq. num", dep_record.seq_num, "is of INVALID type"
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
# If the instruction is a load or store record the addr, size flags
|
# If the instruction is a load or store record the physical addr,
|
||||||
# in addition to recording the computation delay
|
# size flags in addition to recording the computation delay
|
||||||
if dep_record.type in [DepRecord.LOAD, DepRecord.STORE]:
|
if dep_record.type in [DepRecord.LOAD, DepRecord.STORE]:
|
||||||
addr, size, flags, comp_delay = inst_info_list[4:8]
|
p_addr, size, flags, comp_delay = inst_info_list[4:8]
|
||||||
dep_record.addr = long(addr)
|
dep_record.p_addr = long(p_addr)
|
||||||
dep_record.size = int(size)
|
dep_record.size = int(size)
|
||||||
dep_record.flags = int(flags)
|
dep_record.flags = int(flags)
|
||||||
dep_record.comp_delay = long(comp_delay)
|
dep_record.comp_delay = long(comp_delay)
|
||||||
|
|
Loading…
Reference in a new issue