cpu: Create record type enum for elastic traces
This patch replaces the booleans that specified the elastic trace record type with an enum type. The source of change is the proto message for elastic trace where the enum is introduced. The struct definitions in the elastic trace probe listener as well as the Trace CPU replace the boleans with the proto message enum. The patch does not impact functionality, but traces are not compatible with previous version. This is preparation for adding new types of records in subsequent patches.
This commit is contained in:
parent
9bd5051b60
commit
3080bbcc36
7 changed files with 182 additions and 110 deletions
|
@ -384,9 +384,10 @@ ElasticTrace::addDepTraceRecord(const DynInstPtr &head_inst,
|
||||||
|
|
||||||
// Assign fields from the instruction
|
// Assign fields from the instruction
|
||||||
new_record->instNum = head_inst->seqNum;
|
new_record->instNum = head_inst->seqNum;
|
||||||
new_record->load = head_inst->isLoad();
|
|
||||||
new_record->store = head_inst->isStore();
|
|
||||||
new_record->commit = commit;
|
new_record->commit = commit;
|
||||||
|
new_record->type = head_inst->isLoad() ? Record::LOAD :
|
||||||
|
(head_inst->isStore() ? Record::STORE :
|
||||||
|
Record::COMP);
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -503,7 +504,7 @@ void
|
||||||
ElasticTrace::updateCommitOrderDep(TraceInfo* new_record,
|
ElasticTrace::updateCommitOrderDep(TraceInfo* new_record,
|
||||||
bool find_load_not_store)
|
bool find_load_not_store)
|
||||||
{
|
{
|
||||||
assert(new_record->store);
|
assert(new_record->isStore());
|
||||||
// Iterate in reverse direction to search for the last committed
|
// Iterate in reverse direction to search for the last committed
|
||||||
// load/store that completed earlier than the new record
|
// load/store that completed earlier than the new record
|
||||||
depTraceRevItr from_itr(depTrace.end());
|
depTraceRevItr from_itr(depTrace.end());
|
||||||
|
@ -552,11 +553,11 @@ ElasticTrace::updateIssueOrderDep(TraceInfo* new_record)
|
||||||
uint32_t num_go_back = 0;
|
uint32_t num_go_back = 0;
|
||||||
Tick execute_tick = 0;
|
Tick execute_tick = 0;
|
||||||
|
|
||||||
if (new_record->load) {
|
if (new_record->isLoad()) {
|
||||||
// The execution time of a load is when a request is sent
|
// The execution time of a load is when a request is sent
|
||||||
execute_tick = new_record->executeTick;
|
execute_tick = new_record->executeTick;
|
||||||
++numIssueOrderDepLoads;
|
++numIssueOrderDepLoads;
|
||||||
} else if (new_record->store) {
|
} else if (new_record->isStore()) {
|
||||||
// The execution time of a store is when it is sent, i.e. committed
|
// The execution time of a store is when it is sent, i.e. committed
|
||||||
execute_tick = curTick();
|
execute_tick = curTick();
|
||||||
++numIssueOrderDepStores;
|
++numIssueOrderDepStores;
|
||||||
|
@ -589,10 +590,8 @@ ElasticTrace::updateIssueOrderDep(TraceInfo* new_record)
|
||||||
void
|
void
|
||||||
ElasticTrace::assignRobDep(TraceInfo* past_record, TraceInfo* new_record) {
|
ElasticTrace::assignRobDep(TraceInfo* past_record, TraceInfo* new_record) {
|
||||||
DPRINTF(ElasticTrace, "%s %lli has ROB dependency on %lli\n",
|
DPRINTF(ElasticTrace, "%s %lli has ROB dependency on %lli\n",
|
||||||
new_record->load ? "Load" : (new_record->store ? "Store" :
|
new_record->typeToStr(), new_record->instNum,
|
||||||
"Non load/store"),
|
past_record->instNum);
|
||||||
new_record->instNum, past_record->instNum);
|
|
||||||
|
|
||||||
// Add dependency on past record
|
// Add dependency on past record
|
||||||
new_record->robDepList.push_back(past_record->instNum);
|
new_record->robDepList.push_back(past_record->instNum);
|
||||||
// Update new_record's compute delay with respect to the past record
|
// Update new_record's compute delay with respect to the past record
|
||||||
|
@ -608,14 +607,14 @@ bool
|
||||||
ElasticTrace::hasStoreCommitted(TraceInfo* past_record,
|
ElasticTrace::hasStoreCommitted(TraceInfo* past_record,
|
||||||
Tick execute_tick) const
|
Tick execute_tick) const
|
||||||
{
|
{
|
||||||
return (past_record->store && past_record->commitTick <= execute_tick);
|
return (past_record->isStore() && past_record->commitTick <= execute_tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ElasticTrace::hasLoadCompleted(TraceInfo* past_record,
|
ElasticTrace::hasLoadCompleted(TraceInfo* past_record,
|
||||||
Tick execute_tick) const
|
Tick execute_tick) const
|
||||||
{
|
{
|
||||||
return(past_record->load && past_record->commit &&
|
return(past_record->isLoad() && past_record->commit &&
|
||||||
past_record->toCommitTick <= execute_tick);
|
past_record->toCommitTick <= execute_tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,7 +623,7 @@ ElasticTrace::hasLoadBeenSent(TraceInfo* past_record,
|
||||||
Tick execute_tick) const
|
Tick execute_tick) const
|
||||||
{
|
{
|
||||||
// Check if previous inst is a load sent earlier than this
|
// Check if previous inst is a load sent earlier than this
|
||||||
return (past_record->load && past_record->commit &&
|
return (past_record->isLoad() && past_record->commit &&
|
||||||
past_record->executeTick <= execute_tick);
|
past_record->executeTick <= execute_tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,8 +631,7 @@ bool
|
||||||
ElasticTrace::hasCompCompleted(TraceInfo* past_record,
|
ElasticTrace::hasCompCompleted(TraceInfo* past_record,
|
||||||
Tick execute_tick) const
|
Tick execute_tick) const
|
||||||
{
|
{
|
||||||
return(!past_record->store && !past_record->load &&
|
return(past_record->isComp() && past_record->toCommitTick <= execute_tick);
|
||||||
past_record->toCommitTick <= execute_tick);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -674,15 +672,15 @@ ElasticTrace::compDelayRob(TraceInfo* past_record, TraceInfo* new_record)
|
||||||
// computation delay
|
// computation delay
|
||||||
execution_tick = new_record->getExecuteTick();
|
execution_tick = new_record->getExecuteTick();
|
||||||
|
|
||||||
if (past_record->load) {
|
if (past_record->isLoad()) {
|
||||||
if (new_record->store) {
|
if (new_record->isStore()) {
|
||||||
completion_tick = past_record->toCommitTick;
|
completion_tick = past_record->toCommitTick;
|
||||||
} else {
|
} else {
|
||||||
completion_tick = past_record->executeTick;
|
completion_tick = past_record->executeTick;
|
||||||
}
|
}
|
||||||
} else if (past_record->store) {
|
} else if (past_record->isStore()) {
|
||||||
completion_tick = past_record->commitTick;
|
completion_tick = past_record->commitTick;
|
||||||
} else {
|
} else if (past_record->isComp()){
|
||||||
completion_tick = past_record->toCommitTick;
|
completion_tick = past_record->toCommitTick;
|
||||||
}
|
}
|
||||||
assert(execution_tick >= completion_tick);
|
assert(execution_tick >= completion_tick);
|
||||||
|
@ -722,7 +720,7 @@ ElasticTrace::compDelayPhysRegDep(TraceInfo* past_record,
|
||||||
// completion tick of that instruction is when it wrote to the register,
|
// completion tick of that instruction is when it wrote to the register,
|
||||||
// that is toCommitTick. In case, of a store updating a destination
|
// that is toCommitTick. In case, of a store updating a destination
|
||||||
// register, this is approximated to commitTick instead
|
// register, this is approximated to commitTick instead
|
||||||
if (past_record->store) {
|
if (past_record->isStore()) {
|
||||||
completion_tick = past_record->commitTick;
|
completion_tick = past_record->commitTick;
|
||||||
} else {
|
} else {
|
||||||
completion_tick = past_record->toCommitTick;
|
completion_tick = past_record->toCommitTick;
|
||||||
|
@ -745,11 +743,11 @@ ElasticTrace::compDelayPhysRegDep(TraceInfo* past_record,
|
||||||
Tick
|
Tick
|
||||||
ElasticTrace::TraceInfo::getExecuteTick() const
|
ElasticTrace::TraceInfo::getExecuteTick() const
|
||||||
{
|
{
|
||||||
if (load) {
|
if (isLoad()) {
|
||||||
// Execution tick for a load instruction is when the request was sent,
|
// Execution tick for a load instruction is when the request was sent,
|
||||||
// that is executeTick.
|
// that is executeTick.
|
||||||
return executeTick;
|
return executeTick;
|
||||||
} else if (store) {
|
} else if (isStore()) {
|
||||||
// Execution tick for a store instruction is when the request was sent,
|
// Execution tick for a store instruction is when the request was sent,
|
||||||
// that is commitTick.
|
// that is commitTick.
|
||||||
return commitTick;
|
return commitTick;
|
||||||
|
@ -779,27 +777,26 @@ ElasticTrace::writeDepTrace(uint32_t num_to_write)
|
||||||
depTraceItr dep_trace_itr_start = dep_trace_itr;
|
depTraceItr dep_trace_itr_start = dep_trace_itr;
|
||||||
while (num_to_write > 0) {
|
while (num_to_write > 0) {
|
||||||
TraceInfo* temp_ptr = *dep_trace_itr;
|
TraceInfo* temp_ptr = *dep_trace_itr;
|
||||||
// If no node dependends on a non load/store node then there is
|
assert(temp_ptr->type != Record::INVALID);
|
||||||
// no reason to track it in the dependency graph. We filter out such
|
// If no node dependends on a comp node then there is no reason to
|
||||||
|
// track the comp node in the dependency graph. We filter out such
|
||||||
// nodes but count them and add a weight field to the subsequent node
|
// nodes but count them and add a weight field to the subsequent node
|
||||||
// that we do include in the trace.
|
// that we do include in the trace.
|
||||||
if (temp_ptr->numDepts != 0 || temp_ptr->load || temp_ptr->store) {
|
if (!temp_ptr->isComp() || temp_ptr->numDepts != 0) {
|
||||||
|
|
||||||
DPRINTFR(ElasticTrace, "Instruction with seq. num %lli "
|
DPRINTFR(ElasticTrace, "Instruction with seq. num %lli "
|
||||||
"is as follows:\n", temp_ptr->instNum);
|
"is as follows:\n", temp_ptr->instNum);
|
||||||
if (temp_ptr->load || temp_ptr->store) {
|
if (temp_ptr->isLoad() || temp_ptr->isStore()) {
|
||||||
DPRINTFR(ElasticTrace, "\tis a %s\n",
|
DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
|
||||||
(temp_ptr->load ? "Load" : "Store"));
|
|
||||||
DPRINTFR(ElasticTrace, "\thas a request with addr %i, size %i,"
|
DPRINTFR(ElasticTrace, "\thas a request with addr %i, size %i,"
|
||||||
" flags %i\n", temp_ptr->addr, temp_ptr->size,
|
" flags %i\n", temp_ptr->addr, temp_ptr->size,
|
||||||
temp_ptr->reqFlags);
|
temp_ptr->reqFlags);
|
||||||
} else {
|
} else {
|
||||||
DPRINTFR(ElasticTrace, "\tis not a load or store\n");
|
DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr());
|
||||||
}
|
}
|
||||||
if (firstWin && temp_ptr->compDelay == -1) {
|
if (firstWin && temp_ptr->compDelay == -1) {
|
||||||
if (temp_ptr->load) {
|
if (temp_ptr->isLoad()) {
|
||||||
temp_ptr->compDelay = temp_ptr->executeTick;
|
temp_ptr->compDelay = temp_ptr->executeTick;
|
||||||
} else if (temp_ptr->store) {
|
} else if (temp_ptr->isStore()) {
|
||||||
temp_ptr->compDelay = temp_ptr->commitTick;
|
temp_ptr->compDelay = temp_ptr->commitTick;
|
||||||
} else {
|
} else {
|
||||||
temp_ptr->compDelay = temp_ptr->toCommitTick;
|
temp_ptr->compDelay = temp_ptr->toCommitTick;
|
||||||
|
@ -812,10 +809,9 @@ ElasticTrace::writeDepTrace(uint32_t num_to_write)
|
||||||
// Create a protobuf message for the dependency record
|
// Create a protobuf message for the dependency record
|
||||||
ProtoMessage::InstDepRecord dep_pkt;
|
ProtoMessage::InstDepRecord dep_pkt;
|
||||||
dep_pkt.set_seq_num(temp_ptr->instNum);
|
dep_pkt.set_seq_num(temp_ptr->instNum);
|
||||||
dep_pkt.set_load(temp_ptr->load);
|
dep_pkt.set_type(temp_ptr->type);
|
||||||
dep_pkt.set_store(temp_ptr->store);
|
|
||||||
dep_pkt.set_pc(temp_ptr->pc);
|
dep_pkt.set_pc(temp_ptr->pc);
|
||||||
if (temp_ptr->load || temp_ptr->store) {
|
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_addr(temp_ptr->addr);
|
||||||
dep_pkt.set_size(temp_ptr->size);
|
dep_pkt.set_size(temp_ptr->size);
|
||||||
|
@ -916,6 +912,12 @@ ElasticTrace::regStats() {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string&
|
||||||
|
ElasticTrace::TraceInfo::typeToStr() const
|
||||||
|
{
|
||||||
|
return Record::RecordType_Name(type);
|
||||||
|
}
|
||||||
|
|
||||||
const std::string
|
const std::string
|
||||||
ElasticTrace::name() const
|
ElasticTrace::name() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -92,6 +92,10 @@ class ElasticTrace : public ProbeListenerObject
|
||||||
typedef typename O3CPUImpl::DynInstPtr DynInstPtr;
|
typedef typename O3CPUImpl::DynInstPtr DynInstPtr;
|
||||||
typedef typename std::pair<InstSeqNum, PhysRegIndex> SeqNumRegPair;
|
typedef typename std::pair<InstSeqNum, PhysRegIndex> SeqNumRegPair;
|
||||||
|
|
||||||
|
/** Trace record types corresponding to instruction node types */
|
||||||
|
typedef ProtoMessage::InstDepRecord::RecordType RecordType;
|
||||||
|
typedef ProtoMessage::InstDepRecord Record;
|
||||||
|
|
||||||
/** Constructor */
|
/** Constructor */
|
||||||
ElasticTrace(const ElasticTraceParams *params);
|
ElasticTrace(const ElasticTraceParams *params);
|
||||||
|
|
||||||
|
@ -260,14 +264,16 @@ class ElasticTrace : public ProbeListenerObject
|
||||||
*/
|
*/
|
||||||
/* Instruction sequence number. */
|
/* Instruction sequence number. */
|
||||||
InstSeqNum instNum;
|
InstSeqNum instNum;
|
||||||
|
/** The type of trace record for the instruction node */
|
||||||
|
RecordType type;
|
||||||
/* Tick when instruction was in execute stage. */
|
/* Tick when instruction was in execute stage. */
|
||||||
Tick executeTick;
|
Tick executeTick;
|
||||||
/* Tick when instruction was marked ready and sent to commit stage. */
|
/* Tick when instruction was marked ready and sent to commit stage. */
|
||||||
Tick toCommitTick;
|
Tick toCommitTick;
|
||||||
/* Tick when instruction was committed. */
|
/* Tick when instruction was committed. */
|
||||||
Tick commitTick;
|
Tick commitTick;
|
||||||
/* If instruction was a load, a store, committed. */
|
/* If instruction was committed, as against squashed. */
|
||||||
bool load, store, commit;
|
bool commit;
|
||||||
/* List of order dependencies. */
|
/* List of order dependencies. */
|
||||||
std::list<InstSeqNum> robDepList;
|
std::list<InstSeqNum> robDepList;
|
||||||
/* List of physical register RAW dependencies. */
|
/* List of physical register RAW dependencies. */
|
||||||
|
@ -287,6 +293,18 @@ class ElasticTrace : public ProbeListenerObject
|
||||||
Addr addr;
|
Addr addr;
|
||||||
/* Request size in case of a load/store instruction */
|
/* Request size in case of a load/store instruction */
|
||||||
unsigned size;
|
unsigned size;
|
||||||
|
/** Default Constructor */
|
||||||
|
TraceInfo()
|
||||||
|
: type(Record::INVALID)
|
||||||
|
{ }
|
||||||
|
/** Is the record a load */
|
||||||
|
bool isLoad() const { return (type == Record::LOAD); }
|
||||||
|
/** Is the record a store */
|
||||||
|
bool isStore() const { return (type == Record::STORE); }
|
||||||
|
/** Is the record a fetch triggering an Icache request */
|
||||||
|
bool isComp() const { return (type == Record::COMP); }
|
||||||
|
/** Return string specifying the type of the node */
|
||||||
|
const std::string& typeToStr() const;
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -453,7 +453,7 @@ TraceCPU::ElasticDataGen::execute()
|
||||||
++numRetrySucceeded;
|
++numRetrySucceeded;
|
||||||
retryPkt = nullptr;
|
retryPkt = nullptr;
|
||||||
}
|
}
|
||||||
} else if (node_ptr->isLoad || node_ptr->isStore) {
|
} else if (node_ptr->isLoad() || node_ptr->isStore()) {
|
||||||
// If there is no retryPkt, attempt to send a memory request in
|
// If there is no retryPkt, attempt to send a memory request in
|
||||||
// case of a load or store node. If the send fails, executeMemReq()
|
// case of a load or store node. If the send fails, executeMemReq()
|
||||||
// returns a packet pointer, which we save in retryPkt. In case of
|
// returns a packet pointer, which we save in retryPkt. In case of
|
||||||
|
@ -474,7 +474,7 @@ TraceCPU::ElasticDataGen::execute()
|
||||||
// dependencies complete. But as per dependency modelling we need
|
// dependencies complete. But as per dependency modelling we need
|
||||||
// to mark ROB dependencies of load and non load/store nodes which
|
// to mark ROB dependencies of load and non load/store nodes which
|
||||||
// are based on successful sending of the load as complete.
|
// are based on successful sending of the load as complete.
|
||||||
if (node_ptr->isLoad && !node_ptr->isStrictlyOrdered()) {
|
if (node_ptr->isLoad() && !node_ptr->isStrictlyOrdered()) {
|
||||||
// If execute succeeded mark its dependents as complete
|
// If execute succeeded mark its dependents as complete
|
||||||
DPRINTF(TraceCPUData, "Node seq. num %lli sent. Waking up "
|
DPRINTF(TraceCPUData, "Node seq. num %lli sent. Waking up "
|
||||||
"dependents..\n", node_ptr->seqNum);
|
"dependents..\n", node_ptr->seqNum);
|
||||||
|
@ -483,7 +483,7 @@ TraceCPU::ElasticDataGen::execute()
|
||||||
while (child_itr != (node_ptr->dependents).end()) {
|
while (child_itr != (node_ptr->dependents).end()) {
|
||||||
// ROB dependency of a store on a load must not be removed
|
// ROB dependency of a store on a load must not be removed
|
||||||
// after load is sent but after response is received
|
// after load is sent but after response is received
|
||||||
if (!(*child_itr)->isStore &&
|
if (!(*child_itr)->isStore() &&
|
||||||
(*child_itr)->removeRobDep(node_ptr->seqNum)) {
|
(*child_itr)->removeRobDep(node_ptr->seqNum)) {
|
||||||
|
|
||||||
// Check if the child node has become dependency free
|
// Check if the child node has become dependency free
|
||||||
|
@ -530,7 +530,7 @@ TraceCPU::ElasticDataGen::execute()
|
||||||
// marked complete. Thus it is safe to delete it. For
|
// marked complete. Thus it is safe to delete it. For
|
||||||
// stores and non load/store nodes all dependencies were
|
// stores and non load/store nodes all dependencies were
|
||||||
// marked complete so it is safe to delete it.
|
// marked complete so it is safe to delete it.
|
||||||
if (!node_ptr->isLoad || node_ptr->isStrictlyOrdered()) {
|
if (!node_ptr->isLoad() || node_ptr->isStrictlyOrdered()) {
|
||||||
// Release all resources occupied by the completed node
|
// Release all resources occupied by the completed node
|
||||||
hwResource.release(node_ptr);
|
hwResource.release(node_ptr);
|
||||||
// clear the dynamically allocated set of dependents
|
// clear the dynamically allocated set of dependents
|
||||||
|
@ -604,7 +604,7 @@ TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr)
|
||||||
// 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
|
||||||
// as if it was succesfully sent.
|
// as if it was succesfully sent.
|
||||||
if (node_ptr->isStrictlyOrdered()) {
|
if (node_ptr->isStrictlyOrdered()) {
|
||||||
node_ptr->isLoad ? ++numSOLoads : ++numSOStores;
|
node_ptr->isLoad() ? ++numSOLoads : ++numSOStores;
|
||||||
DPRINTF(TraceCPUData, "Skipping strictly ordered request %lli.\n",
|
DPRINTF(TraceCPUData, "Skipping strictly ordered request %lli.\n",
|
||||||
node_ptr->seqNum);
|
node_ptr->seqNum);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -630,7 +630,7 @@ TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr)
|
||||||
req->setPC(node_ptr->pc);
|
req->setPC(node_ptr->pc);
|
||||||
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()) {
|
||||||
pkt = Packet::createRead(req);
|
pkt = Packet::createRead(req);
|
||||||
} else {
|
} else {
|
||||||
pkt = Packet::createWrite(req);
|
pkt = Packet::createWrite(req);
|
||||||
|
@ -664,8 +664,7 @@ TraceCPU::ElasticDataGen::checkAndIssue(const GraphNode* node_ptr, bool first)
|
||||||
// If this is the first attempt, print a debug message to indicate this.
|
// If this is the first attempt, print a debug message to indicate this.
|
||||||
if (first) {
|
if (first) {
|
||||||
DPRINTFR(TraceCPUData, "\t\tseq. num %lli(%s) with rob num %lli is now"
|
DPRINTFR(TraceCPUData, "\t\tseq. num %lli(%s) with rob num %lli is now"
|
||||||
" dependency free.\n", node_ptr->seqNum,
|
" dependency free.\n", node_ptr->seqNum, node_ptr->typeToStr(),
|
||||||
node_ptr->isLoad ? "L" : (node_ptr->isStore ? "S" : "C"),
|
|
||||||
node_ptr->robNum);
|
node_ptr->robNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,8 +830,7 @@ TraceCPU::ElasticDataGen::printReadyList() {
|
||||||
auto graph_itr = depGraph.find(itr->seqNum);
|
auto graph_itr = depGraph.find(itr->seqNum);
|
||||||
GraphNode* node_ptr M5_VAR_USED = graph_itr->second;
|
GraphNode* node_ptr M5_VAR_USED = graph_itr->second;
|
||||||
DPRINTFR(TraceCPUData, "\t%lld(%s), %lld\n", itr->seqNum,
|
DPRINTFR(TraceCPUData, "\t%lld(%s), %lld\n", itr->seqNum,
|
||||||
node_ptr->isLoad ? "L" : (node_ptr->isStore ? "S" : "C"),
|
node_ptr->typeToStr(), itr->execTick);
|
||||||
itr->execTick);
|
|
||||||
itr++;
|
itr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -857,9 +855,9 @@ TraceCPU::ElasticDataGen::HardwareResource::occupy(const GraphNode* new_node)
|
||||||
oldestInFlightRobNum = inFlightNodes.begin()->second;
|
oldestInFlightRobNum = inFlightNodes.begin()->second;
|
||||||
|
|
||||||
// Occupy Load/Store Buffer entry for the issued node if applicable
|
// Occupy Load/Store Buffer entry for the issued node if applicable
|
||||||
if (new_node->isLoad) {
|
if (new_node->isLoad()) {
|
||||||
++numInFlightLoads;
|
++numInFlightLoads;
|
||||||
} else if (new_node->isStore) {
|
} else if (new_node->isStore()) {
|
||||||
++numInFlightStores;
|
++numInFlightStores;
|
||||||
} // else if it is a non load/store node, no buffer entry is occupied
|
} // else if it is a non load/store node, no buffer entry is occupied
|
||||||
|
|
||||||
|
@ -894,7 +892,7 @@ TraceCPU::ElasticDataGen::HardwareResource::release(const GraphNode* done_node)
|
||||||
// freed. But it occupies an entry in the Store Buffer until its response
|
// freed. But it occupies an entry in the Store Buffer until its response
|
||||||
// is received. A load is considered complete when a response is received,
|
// is received. A load is considered complete when a response is received,
|
||||||
// thus both ROB and Load Buffer entries can be released.
|
// thus both ROB and Load Buffer entries can be released.
|
||||||
if (done_node->isLoad) {
|
if (done_node->isLoad()) {
|
||||||
assert(numInFlightLoads != 0);
|
assert(numInFlightLoads != 0);
|
||||||
--numInFlightLoads;
|
--numInFlightLoads;
|
||||||
}
|
}
|
||||||
|
@ -902,7 +900,7 @@ TraceCPU::ElasticDataGen::HardwareResource::release(const GraphNode* done_node)
|
||||||
// entry on response. For writes which are strictly ordered, for e.g.
|
// entry on response. For writes which are strictly ordered, for e.g.
|
||||||
// writes to device registers, we do that within release() which is called
|
// writes to device registers, we do that within release() which is called
|
||||||
// when node is executed and taken off from readyList.
|
// when node is executed and taken off from readyList.
|
||||||
if (done_node->isStore && done_node->isStrictlyOrdered()) {
|
if (done_node->isStore() && done_node->isStrictlyOrdered()) {
|
||||||
releaseStoreBuffer();
|
releaseStoreBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -949,10 +947,10 @@ TraceCPU::ElasticDataGen::HardwareResource::isAvailable(
|
||||||
if (num_in_flight_nodes >= sizeROB) {
|
if (num_in_flight_nodes >= sizeROB) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (new_node->isLoad && numInFlightLoads >= sizeLoadBuffer) {
|
if (new_node->isLoad() && numInFlightLoads >= sizeLoadBuffer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (new_node->isStore && numInFlightStores >= sizeStoreBuffer) {
|
if (new_node->isStore() && numInFlightStores >= sizeStoreBuffer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1250,8 +1248,7 @@ TraceCPU::ElasticDataGen::InputStream::read(GraphNode* element)
|
||||||
if (trace.read(pkt_msg)) {
|
if (trace.read(pkt_msg)) {
|
||||||
// Required fields
|
// Required fields
|
||||||
element->seqNum = pkt_msg.seq_num();
|
element->seqNum = pkt_msg.seq_num();
|
||||||
element->isLoad = pkt_msg.load();
|
element->type = pkt_msg.type();
|
||||||
element->isStore = pkt_msg.store();
|
|
||||||
element->compDelay = pkt_msg.comp_delay();
|
element->compDelay = pkt_msg.comp_delay();
|
||||||
|
|
||||||
// Repeated field robDepList
|
// Repeated field robDepList
|
||||||
|
@ -1384,9 +1381,8 @@ void
|
||||||
TraceCPU::ElasticDataGen::GraphNode::writeElementAsTrace() const
|
TraceCPU::ElasticDataGen::GraphNode::writeElementAsTrace() const
|
||||||
{
|
{
|
||||||
DPRINTFR(TraceCPUData, "%lli", seqNum);
|
DPRINTFR(TraceCPUData, "%lli", seqNum);
|
||||||
DPRINTFR(TraceCPUData, ",%s", (isLoad ? "True" : "False"));
|
DPRINTFR(TraceCPUData, ",%s", typeToStr());
|
||||||
DPRINTFR(TraceCPUData, ",%s", (isStore ? "True" : "False"));
|
if (isLoad() || isStore()) {
|
||||||
if (isLoad || isStore) {
|
|
||||||
DPRINTFR(TraceCPUData, ",%i", addr);
|
DPRINTFR(TraceCPUData, ",%i", addr);
|
||||||
DPRINTFR(TraceCPUData, ",%i", size);
|
DPRINTFR(TraceCPUData, ",%i", size);
|
||||||
DPRINTFR(TraceCPUData, ",%i", flags);
|
DPRINTFR(TraceCPUData, ",%i", flags);
|
||||||
|
@ -1414,6 +1410,12 @@ TraceCPU::ElasticDataGen::GraphNode::writeElementAsTrace() const
|
||||||
DPRINTFR(TraceCPUData, "\n");
|
DPRINTFR(TraceCPUData, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
TraceCPU::ElasticDataGen::GraphNode::typeToStr() const
|
||||||
|
{
|
||||||
|
return Record::RecordType_Name(type);
|
||||||
|
}
|
||||||
|
|
||||||
TraceCPU::FixedRetryGen::InputStream::InputStream(const std::string& filename)
|
TraceCPU::FixedRetryGen::InputStream::InputStream(const std::string& filename)
|
||||||
: trace(filename)
|
: trace(filename)
|
||||||
{
|
{
|
||||||
|
|
|
@ -561,6 +561,9 @@ class TraceCPU : public BaseCPU
|
||||||
/** Node ROB number type. */
|
/** Node ROB number type. */
|
||||||
typedef uint64_t NodeRobNum;
|
typedef uint64_t NodeRobNum;
|
||||||
|
|
||||||
|
typedef ProtoMessage::InstDepRecord::RecordType RecordType;
|
||||||
|
typedef ProtoMessage::InstDepRecord Record;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The struct GraphNode stores an instruction in the trace file. The
|
* The struct GraphNode stores an instruction in the trace file. The
|
||||||
* format of the trace file favours constructing a dependency graph of
|
* format of the trace file favours constructing a dependency graph of
|
||||||
|
@ -589,11 +592,8 @@ class TraceCPU : public BaseCPU
|
||||||
/** ROB occupancy number */
|
/** ROB occupancy number */
|
||||||
NodeRobNum robNum;
|
NodeRobNum robNum;
|
||||||
|
|
||||||
/** If instruction is a load */
|
/** Type of the node corresponding to the instruction modelled by it */
|
||||||
bool isLoad;
|
RecordType type;
|
||||||
|
|
||||||
/** If instruction is a store */
|
|
||||||
bool isStore;
|
|
||||||
|
|
||||||
/** The address for the request if any */
|
/** The address for the request if any */
|
||||||
Addr addr;
|
Addr addr;
|
||||||
|
@ -632,6 +632,15 @@ class TraceCPU : public BaseCPU
|
||||||
*/
|
*/
|
||||||
std::vector<GraphNode *> dependents;
|
std::vector<GraphNode *> dependents;
|
||||||
|
|
||||||
|
/** Is the node a load */
|
||||||
|
bool isLoad() const { return (type == Record::LOAD); }
|
||||||
|
|
||||||
|
/** Is the node a store */
|
||||||
|
bool isStore() const { return (type == Record::STORE); }
|
||||||
|
|
||||||
|
/** Is the node a compute (non load/store) node */
|
||||||
|
bool isComp() const { return (type == Record::COMP); }
|
||||||
|
|
||||||
/** Initialize register dependency array to all zeroes */
|
/** Initialize register dependency array to all zeroes */
|
||||||
void clearRegDep();
|
void clearRegDep();
|
||||||
|
|
||||||
|
@ -656,6 +665,9 @@ class TraceCPU : public BaseCPU
|
||||||
* TraceCPUData.
|
* TraceCPUData.
|
||||||
*/
|
*/
|
||||||
void writeElementAsTrace() const;
|
void writeElementAsTrace() const;
|
||||||
|
|
||||||
|
/** Return string specifying the type of the node */
|
||||||
|
std::string typeToStr() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Struct to store a ready-to-execute node and its execution tick. */
|
/** Struct to store a ready-to-execute node and its execution tick. */
|
||||||
|
|
|
@ -50,26 +50,31 @@ message InstDepRecordHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Packet to encapsulate an instruction in the o3cpu data dependency trace.
|
// Packet to encapsulate an instruction in the o3cpu data dependency trace.
|
||||||
// The required fields include the instruction sequence number, whether it
|
// The required fields include the instruction sequence number and the type
|
||||||
// is a load, and whether it is a store. The request related fields are
|
// of the record associated with the instruction e.g. load. The request related
|
||||||
// optional, namely address, size and flags. These exist only if the
|
// fields are optional, namely address, size and flags. The dependency related
|
||||||
// instruction is a load or store. The dependency related information includes
|
// information includes a repeated field for order dependencies and register
|
||||||
// a repeated field for order dependencies, a repeated field for register
|
// dependencies for loads, stores and comp records. There is a field for the
|
||||||
// dependencies and the computational delay with respect to the dependency
|
// computational delay with respect to the dependency that completed last. A
|
||||||
// that completed last. A weight field is used to account for committed
|
// weight field is used to account for committed instruction that were
|
||||||
// instructions that were filtered out before writing the trace and is used
|
// filtered out before writing the trace and is used to estimate ROB
|
||||||
// to estimate ROB occupancy during replay. An optional field is provided for
|
// occupancy during replay. An optional field is provided for the instruction
|
||||||
// the instruction PC.
|
// PC.
|
||||||
message InstDepRecord {
|
message InstDepRecord {
|
||||||
|
enum RecordType {
|
||||||
|
INVALID = 0;
|
||||||
|
LOAD = 1;
|
||||||
|
STORE = 2;
|
||||||
|
COMP = 3;
|
||||||
|
}
|
||||||
required uint64 seq_num = 1;
|
required uint64 seq_num = 1;
|
||||||
required bool load = 2;
|
required RecordType type = 2 [default = INVALID];
|
||||||
required bool store = 3;
|
optional uint64 addr = 3;
|
||||||
optional uint64 addr = 4;
|
optional uint32 size = 4;
|
||||||
optional uint32 size = 5;
|
optional uint32 flags = 5;
|
||||||
optional uint32 flags = 6;
|
repeated uint64 rob_dep = 6;
|
||||||
repeated uint64 rob_dep = 7;
|
required uint64 comp_delay = 7;
|
||||||
required uint64 comp_delay = 8;
|
repeated uint64 reg_dep = 8;
|
||||||
repeated uint64 reg_dep = 9;
|
optional uint32 weight = 9;
|
||||||
optional uint32 weight = 10;
|
optional uint64 pc = 10;
|
||||||
optional uint64 pc = 11;
|
}
|
||||||
}
|
|
|
@ -71,20 +71,23 @@
|
||||||
# graph to ASCII format.
|
# graph to ASCII format.
|
||||||
#
|
#
|
||||||
# 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, load, store,
|
# instruction sequence number, (optional) pc, (optional) weight, type
|
||||||
# (optional) flags, (optional) addr, (optional) size, comp delay,
|
# (optional) flags, (optional) 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,]load,store,[address,size,flags,]comp_delay:[rob_dep]:
|
# seq_num,[pc],[weight,]type,[address,size,flags,]comp_delay:[rob_dep]:
|
||||||
# [reg_dep]
|
# [reg_dep]
|
||||||
# 1,1,False,False,8500::
|
# 1,35652,1,COMP,8500::
|
||||||
# 2,1,False,False,1000:,1:
|
# 2,35656,1,COMP,0:,1:
|
||||||
# 3,1,True,False,831248,4,74,500:,2:
|
# 3,35660,1,LOAD,1748752,4,74,500:,2:
|
||||||
# 4,1,False,False,0:,2:
|
# 4,35660,1,COMP,0:,3:
|
||||||
# 5,1,False,False,500::,4
|
# 5,35664,1,COMP,3000::,4
|
||||||
# 6,1,False,True,831248,4,74,1000:,3:,4,5
|
# 6,35666,1,STORE,1748752,4,74,1000:,3:,4,5
|
||||||
|
# 7,35666,1,COMP,3000::,4
|
||||||
|
# 8,35670,1,STORE,1748748,4,74,0:,6,3:,7
|
||||||
|
# 9,35670,1,COMP,500::,7
|
||||||
|
|
||||||
import protolib
|
import protolib
|
||||||
import sys
|
import sys
|
||||||
|
@ -138,6 +141,13 @@ def main():
|
||||||
|
|
||||||
print "Parsing packets"
|
print "Parsing packets"
|
||||||
|
|
||||||
|
print "Creating enum value,name lookup from proto"
|
||||||
|
enumNames = {}
|
||||||
|
desc = inst_dep_record_pb2.InstDepRecord.DESCRIPTOR
|
||||||
|
for namestr, valdesc in desc.enum_values_by_name.items():
|
||||||
|
print '\t', valdesc.number, namestr
|
||||||
|
enumNames[valdesc.number] = namestr
|
||||||
|
|
||||||
num_packets = 0
|
num_packets = 0
|
||||||
num_regdeps = 0
|
num_regdeps = 0
|
||||||
num_robdeps = 0
|
num_robdeps = 0
|
||||||
|
@ -159,8 +169,14 @@ def main():
|
||||||
ascii_out.write(',%s' % (packet.weight))
|
ascii_out.write(',%s' % (packet.weight))
|
||||||
else:
|
else:
|
||||||
ascii_out.write(',1')
|
ascii_out.write(',1')
|
||||||
# Write to file if it is a load and if it is a store
|
# Write to file the type of the record
|
||||||
ascii_out.write(',%s,%s' % (packet.load, packet.store))
|
try:
|
||||||
|
ascii_out.write(',%s' % enumNames[packet.type])
|
||||||
|
except KeyError:
|
||||||
|
print "Seq. num", packet.seq_num, "has unsupported type", \
|
||||||
|
packet.type
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
|
||||||
# Write to file if it has the optional fields addr, size, flags
|
# Write to file if it has the optional fields addr, size, flags
|
||||||
if packet.HasField('addr'):
|
if packet.HasField('addr'):
|
||||||
|
|
|
@ -71,20 +71,23 @@
|
||||||
# graph to protobuf format.
|
# graph to protobuf format.
|
||||||
#
|
#
|
||||||
# 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, load, store,
|
# instruction sequence number, (optional) pc, (optional) weight, type,
|
||||||
# (optional) flags, (optional) addr, (optional) size, comp delay,
|
# (optional) flags, (optional) 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,]load,store,[address,size,flags,]comp_delay:[rob_dep]:
|
# seq_num,[pc],[weight,]type,[address,size,flags,]comp_delay:[rob_dep]:
|
||||||
# [reg_dep]
|
# [reg_dep]
|
||||||
# 1,1,False,False,8500::
|
# 1,35652,1,COMP,8500::
|
||||||
# 2,1,False,False,1000:,1:
|
# 2,35656,1,COMP,0:,1:
|
||||||
# 3,1,True,False,831248,4,74,500:,2:
|
# 3,35660,1,LOAD,1748752,4,74,500:,2:
|
||||||
# 4,1,False,False,0:,2:
|
# 4,35660,1,COMP,0:,3:
|
||||||
# 5,1,False,False,500::,4
|
# 5,35664,1,COMP,3000::,4
|
||||||
# 6,1,False,True,831248,4,74,1000:,3:,4,5
|
# 6,35666,1,STORE,1748752,4,74,1000:,3:,4,5
|
||||||
|
# 7,35666,1,COMP,3000::,4
|
||||||
|
# 8,35670,1,STORE,1748748,4,74,0:,6,3:,7
|
||||||
|
# 9,35670,1,COMP,500::,7
|
||||||
|
|
||||||
import protolib
|
import protolib
|
||||||
import sys
|
import sys
|
||||||
|
@ -106,6 +109,8 @@ except:
|
||||||
print "Failed to import proto definitions"
|
print "Failed to import proto definitions"
|
||||||
exit(-1)
|
exit(-1)
|
||||||
|
|
||||||
|
DepRecord = inst_dep_record_pb2.InstDepRecord
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if len(sys.argv) != 3:
|
if len(sys.argv) != 3:
|
||||||
print "Usage: ", sys.argv[0], " <ASCII input> <protobuf output>"
|
print "Usage: ", sys.argv[0], " <ASCII input> <protobuf output>"
|
||||||
|
@ -133,34 +138,46 @@ def main():
|
||||||
header.window_size = 120
|
header.window_size = 120
|
||||||
protolib.encodeMessage(proto_out, header)
|
protolib.encodeMessage(proto_out, header)
|
||||||
|
|
||||||
|
print "Creating enum name,value lookup from proto"
|
||||||
|
enumValues = {}
|
||||||
|
for namestr, valdesc in DepRecord.DESCRIPTOR.enum_values_by_name.items():
|
||||||
|
print '\t', namestr, valdesc.number
|
||||||
|
enumValues[namestr] = valdesc.number
|
||||||
|
|
||||||
num_records = 0
|
num_records = 0
|
||||||
# For each line in the ASCII trace, create a packet message and
|
# For each line in the ASCII trace, create a packet message and
|
||||||
# write it to the encoded output
|
# write it to the encoded output
|
||||||
for line in ascii_in:
|
for line in ascii_in:
|
||||||
inst_info_str, rob_dep_str, reg_dep_str = (line.strip()).split(':')
|
inst_info_str, rob_dep_str, reg_dep_str = (line.strip()).split(':')
|
||||||
inst_info_list = inst_info_str.split(',')
|
inst_info_list = inst_info_str.split(',')
|
||||||
dep_record = inst_dep_record_pb2.InstDepRecord()
|
dep_record = DepRecord()
|
||||||
|
|
||||||
dep_record.seq_num = long(inst_info_list[0])
|
dep_record.seq_num = long(inst_info_list[0])
|
||||||
dep_record.pc = long(inst_info_list[1])
|
dep_record.pc = long(inst_info_list[1])
|
||||||
dep_record.weight = long(inst_info_list[2])
|
dep_record.weight = long(inst_info_list[2])
|
||||||
dep_record.load = True if inst_info_list[3] == 'True' else False
|
# If the type is not one of the enum values, it should be a key error
|
||||||
dep_record.store = True if inst_info_list[4] == 'True' else False
|
try:
|
||||||
|
dep_record.type = enumValues[inst_info_list[3]]
|
||||||
|
except KeyError:
|
||||||
|
print "Seq. num", dep_record.seq_num, "has unsupported type", \
|
||||||
|
inst_info_list[3]
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
if dep_record.type == DepRecord.INVALID:
|
||||||
|
print "Seq. num", dep_record.seq_num, "is of INVALID type"
|
||||||
|
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 addr, size flags
|
||||||
# in addition to recording the computation delay
|
# in addition to recording the computation delay
|
||||||
if dep_record.load or dep_record.store:
|
if dep_record.type in [DepRecord.LOAD, DepRecord.STORE]:
|
||||||
addr, size, flags, comp_delay = inst_info_list[5:9]
|
addr, size, flags, comp_delay = inst_info_list[4:8]
|
||||||
dep_record.addr = long(addr)
|
dep_record.addr = long(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)
|
||||||
elif not dep_record.load and not dep_record.store:
|
else:
|
||||||
comp_delay = inst_info_list[4]
|
comp_delay = inst_info_list[4]
|
||||||
dep_record.comp_delay = long(comp_delay)
|
dep_record.comp_delay = long(comp_delay)
|
||||||
else:
|
|
||||||
print "Fatal:", seq_num, "is both load and store"
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
# Parse the register and order dependencies both of which are
|
# Parse the register and order dependencies both of which are
|
||||||
# repeated fields. An empty list is valid.
|
# repeated fields. An empty list is valid.
|
||||||
|
|
Loading…
Reference in a new issue