Trace creation example: Create trace after the paddr is ready in the packet.
in src/cpu/o3/probe/elastic_trace.cc:
ElasticTrace::fetchReqTrace
.
// src/cpu/o3/probe/elastic_trace.cc
// Create a protobuf message including the request fields necessary to
// recreate the request in the TraceCPU.
ProtoMessage::Packet inst_fetch_pkt;
inst_fetch_pkt.set_tick(curTick());
inst_fetch_pkt.set_cmd(MemCmd::ReadReq);
inst_fetch_pkt.set_pc(req->getPC());
inst_fetch_pkt.set_flags(req->getFlags());
inst_fetch_pkt.set_addr(req->getPaddr());
inst_fetch_pkt.set_size(req->getSize());
// Write the message to the stream.
instTraceStream->write(inst_fetch_pkt);
Trace read example: read one record from trace file and create packet for replay.
FixedRetryGen
class is used to read instruction fetching memory traces, and ElasticDataGen
class is used to read data access memory traces.
TraceCPU::schedIcacheNext()
is called as an event EventFunctionWrapper icacheNextEvent
.
This event is called/scheduled during the initialization of the instruction fetch trace file in TraceCPU::init()
.
TraceCPU::schedIcacheNext()
will call icacheGen.tryNext()
, which is defined as TraceCPU::FixedRetryGen::tryNext()
. This method will read a new record from the trace file (via nextExecute()
) and compose a packet from the trace and send it down to the icache port (by calling send()
.
Related code shown below:
// src/cpu/trace/trace_cpu.cc
bool
TraceCPU::FixedRetryGen::tryNext()
{
// If there is a retry packet, try to send it
if (retryPkt) {
DPRINTF(TraceCPUInst, "Trying to send retry packet.\n");
if (!port.sendTimingReq(retryPkt)) {
// Still blocked! This should never occur.
DPRINTF(TraceCPUInst, "Retry packet sending failed.\n");
return false;
}
++numRetrySucceeded;
} else {
DPRINTF(TraceCPUInst, "Trying to send packet for currElement.\n");
// try sending current element
assert(currElement.isValid());
++numSendAttempted;
if (!send(currElement.addr, currElement.blocksize,
currElement.cmd, currElement.flags, currElement.pc)) {
DPRINTF(TraceCPUInst, "currElement sending failed.\n");
++numSendFailed;
// return false to indicate not to schedule next event
return false;
} else {
++numSendSucceeded;
}
}
// If packet was sent successfully, either retryPkt or currElement, return
// true to indicate to schedule event at current Tick plus delta. If packet
// was sent successfully and there is no next packet to send, return false.
DPRINTF(TraceCPUInst, "Packet sent successfully, trying to read next "
"element.\n");
retryPkt = nullptr;
// Read next element into currElement, currElement gets cleared so save the
// tick to calculate delta
Tick last_tick = currElement.tick;
if (nextExecute()) {
assert(currElement.tick >= last_tick);
delta = currElement.tick - last_tick;
}
return !traceComplete;
}
bool
TraceCPU::FixedRetryGen::nextExecute()
{
if (traceComplete)
// We are at the end of the file, thus we have no more messages.
// Return false.
return false;
//Reset the currElement to the default values
currElement.clear();
// Read the next line to get the next message. If that fails then end of
// trace has been reached and traceComplete needs to be set in addition
// to returning false. If successful then next message is in currElement.
if (!trace.read(&currElement)) {
traceComplete = true;
instLastTick = curTick();
return false;
}
DPRINTF(TraceCPUInst, "inst fetch: %c addr %d pc %#x size %d tick %d\n",
currElement.cmd.isRead() ? 'r' : 'w',
currElement.addr,
currElement.pc,
currElement.blocksize,
currElement.tick);
return true;
}
The send()
methods will create a packet in Gem5 and send it to icache port. Necessary elements include:
0xA
chunks –> dummy contentDefinition of this methods TraceCPU::FixedRetryGen::send()
is shown below
// src/cpu/trace/trace_cpu.cc
bool
TraceCPU::FixedRetryGen::send(Addr addr, unsigned size, const MemCmd& cmd,
Request::FlagsType flags, Addr pc)
{
// Create new request
auto req = std::make_shared<Request>(addr, size, flags, masterID);
req->setPC(pc);
// If this is not done it triggers assert in L1 cache for invalid contextId
req->setContext(ContextID(0));
// Embed it in a packet
PacketPtr pkt = new Packet(req, cmd);
uint8_t* pkt_data = new uint8_t[req->getSize()];
pkt->dataDynamic(pkt_data);
if (cmd.isWrite()) {
memset(pkt_data, 0xA, req->getSize());
}
// Call MasterPort method to send a timing request for this packet
bool success = port.sendTimingReq(pkt);
if (!success) {
// If it fails, save the packet to retry when a retry is signalled by
// the cache
retryPkt = pkt;
}
return success;
}
Reference 1
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?