diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cpu/o3/probe/elastic_trace.cc | 70 | ||||
-rw-r--r-- | src/cpu/o3/probe/elastic_trace.hh | 22 | ||||
-rw-r--r-- | src/cpu/trace/trace_cpu.cc | 44 | ||||
-rw-r--r-- | src/cpu/trace/trace_cpu.hh | 22 | ||||
-rw-r--r-- | src/proto/inst_dep_record.proto | 47 |
5 files changed, 122 insertions, 83 deletions
diff --git a/src/cpu/o3/probe/elastic_trace.cc b/src/cpu/o3/probe/elastic_trace.cc index a7a0403f9..e1a41b696 100644 --- a/src/cpu/o3/probe/elastic_trace.cc +++ b/src/cpu/o3/probe/elastic_trace.cc @@ -384,9 +384,10 @@ ElasticTrace::addDepTraceRecord(const DynInstPtr &head_inst, // Assign fields from the instruction new_record->instNum = head_inst->seqNum; - new_record->load = head_inst->isLoad(); - new_record->store = head_inst->isStore(); 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 new_record->reqFlags = head_inst->memReqFlags; @@ -503,7 +504,7 @@ void ElasticTrace::updateCommitOrderDep(TraceInfo* new_record, bool find_load_not_store) { - assert(new_record->store); + assert(new_record->isStore()); // Iterate in reverse direction to search for the last committed // load/store that completed earlier than the new record depTraceRevItr from_itr(depTrace.end()); @@ -552,11 +553,11 @@ ElasticTrace::updateIssueOrderDep(TraceInfo* new_record) uint32_t num_go_back = 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 execute_tick = new_record->executeTick; ++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 execute_tick = curTick(); ++numIssueOrderDepStores; @@ -589,10 +590,8 @@ ElasticTrace::updateIssueOrderDep(TraceInfo* new_record) void ElasticTrace::assignRobDep(TraceInfo* past_record, TraceInfo* new_record) { DPRINTF(ElasticTrace, "%s %lli has ROB dependency on %lli\n", - new_record->load ? "Load" : (new_record->store ? "Store" : - "Non load/store"), - new_record->instNum, past_record->instNum); - + new_record->typeToStr(), new_record->instNum, + past_record->instNum); // Add dependency on past record new_record->robDepList.push_back(past_record->instNum); // Update new_record's compute delay with respect to the past record @@ -608,14 +607,14 @@ bool ElasticTrace::hasStoreCommitted(TraceInfo* past_record, Tick execute_tick) const { - return (past_record->store && past_record->commitTick <= execute_tick); + return (past_record->isStore() && past_record->commitTick <= execute_tick); } bool ElasticTrace::hasLoadCompleted(TraceInfo* past_record, Tick execute_tick) const { - return(past_record->load && past_record->commit && + return(past_record->isLoad() && past_record->commit && past_record->toCommitTick <= execute_tick); } @@ -624,7 +623,7 @@ ElasticTrace::hasLoadBeenSent(TraceInfo* past_record, Tick execute_tick) const { // 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); } @@ -632,8 +631,7 @@ bool ElasticTrace::hasCompCompleted(TraceInfo* past_record, Tick execute_tick) const { - return(!past_record->store && !past_record->load && - past_record->toCommitTick <= execute_tick); + return(past_record->isComp() && past_record->toCommitTick <= execute_tick); } void @@ -674,15 +672,15 @@ ElasticTrace::compDelayRob(TraceInfo* past_record, TraceInfo* new_record) // computation delay execution_tick = new_record->getExecuteTick(); - if (past_record->load) { - if (new_record->store) { + if (past_record->isLoad()) { + if (new_record->isStore()) { completion_tick = past_record->toCommitTick; } else { completion_tick = past_record->executeTick; } - } else if (past_record->store) { + } else if (past_record->isStore()) { completion_tick = past_record->commitTick; - } else { + } else if (past_record->isComp()){ completion_tick = past_record->toCommitTick; } 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, // that is toCommitTick. In case, of a store updating a destination // register, this is approximated to commitTick instead - if (past_record->store) { + if (past_record->isStore()) { completion_tick = past_record->commitTick; } else { completion_tick = past_record->toCommitTick; @@ -745,11 +743,11 @@ ElasticTrace::compDelayPhysRegDep(TraceInfo* past_record, Tick ElasticTrace::TraceInfo::getExecuteTick() const { - if (load) { + if (isLoad()) { // Execution tick for a load instruction is when the request was sent, // that is executeTick. return executeTick; - } else if (store) { + } else if (isStore()) { // Execution tick for a store instruction is when the request was sent, // that is commitTick. return commitTick; @@ -779,27 +777,26 @@ ElasticTrace::writeDepTrace(uint32_t num_to_write) depTraceItr dep_trace_itr_start = dep_trace_itr; while (num_to_write > 0) { TraceInfo* temp_ptr = *dep_trace_itr; - // If no node dependends on a non load/store node then there is - // no reason to track it in the dependency graph. We filter out such + assert(temp_ptr->type != Record::INVALID); + // 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 // 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 " "is as follows:\n", temp_ptr->instNum); - if (temp_ptr->load || temp_ptr->store) { - DPRINTFR(ElasticTrace, "\tis a %s\n", - (temp_ptr->load ? "Load" : "Store")); + if (temp_ptr->isLoad() || temp_ptr->isStore()) { + DPRINTFR(ElasticTrace, "\tis a %s\n", temp_ptr->typeToStr()); DPRINTFR(ElasticTrace, "\thas a request with addr %i, size %i," " flags %i\n", temp_ptr->addr, temp_ptr->size, temp_ptr->reqFlags); } 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 (temp_ptr->load) { + if (temp_ptr->isLoad()) { temp_ptr->compDelay = temp_ptr->executeTick; - } else if (temp_ptr->store) { + } else if (temp_ptr->isStore()) { temp_ptr->compDelay = temp_ptr->commitTick; } else { 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 ProtoMessage::InstDepRecord dep_pkt; dep_pkt.set_seq_num(temp_ptr->instNum); - dep_pkt.set_load(temp_ptr->load); - dep_pkt.set_store(temp_ptr->store); + dep_pkt.set_type(temp_ptr->type); 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_addr(temp_ptr->addr); 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 ElasticTrace::name() const { diff --git a/src/cpu/o3/probe/elastic_trace.hh b/src/cpu/o3/probe/elastic_trace.hh index 5dd2949e8..001dc0e13 100644 --- a/src/cpu/o3/probe/elastic_trace.hh +++ b/src/cpu/o3/probe/elastic_trace.hh @@ -92,6 +92,10 @@ class ElasticTrace : public ProbeListenerObject typedef typename O3CPUImpl::DynInstPtr DynInstPtr; 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 */ ElasticTrace(const ElasticTraceParams *params); @@ -260,14 +264,16 @@ class ElasticTrace : public ProbeListenerObject */ /* Instruction sequence number. */ InstSeqNum instNum; + /** The type of trace record for the instruction node */ + RecordType type; /* Tick when instruction was in execute stage. */ Tick executeTick; /* Tick when instruction was marked ready and sent to commit stage. */ Tick toCommitTick; /* Tick when instruction was committed. */ Tick commitTick; - /* If instruction was a load, a store, committed. */ - bool load, store, commit; + /* If instruction was committed, as against squashed. */ + bool commit; /* List of order dependencies. */ std::list<InstSeqNum> robDepList; /* List of physical register RAW dependencies. */ @@ -287,6 +293,18 @@ class ElasticTrace : public ProbeListenerObject Addr addr; /* Request size in case of a load/store instruction */ 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; /** @} */ /** diff --git a/src/cpu/trace/trace_cpu.cc b/src/cpu/trace/trace_cpu.cc index 2e989f6ff..ffa64014a 100644 --- a/src/cpu/trace/trace_cpu.cc +++ b/src/cpu/trace/trace_cpu.cc @@ -453,7 +453,7 @@ TraceCPU::ElasticDataGen::execute() ++numRetrySucceeded; 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 // case of a load or store node. If the send fails, executeMemReq() // 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 // to mark ROB dependencies of load and non load/store nodes which // 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 DPRINTF(TraceCPUData, "Node seq. num %lli sent. Waking up " "dependents..\n", node_ptr->seqNum); @@ -483,7 +483,7 @@ TraceCPU::ElasticDataGen::execute() while (child_itr != (node_ptr->dependents).end()) { // ROB dependency of a store on a load must not be removed // after load is sent but after response is received - if (!(*child_itr)->isStore && + if (!(*child_itr)->isStore() && (*child_itr)->removeRobDep(node_ptr->seqNum)) { // 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 // stores and non load/store nodes all dependencies were // 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 hwResource.release(node_ptr); // 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 // as if it was succesfully sent. if (node_ptr->isStrictlyOrdered()) { - node_ptr->isLoad ? ++numSOLoads : ++numSOStores; + node_ptr->isLoad() ? ++numSOLoads : ++numSOStores; DPRINTF(TraceCPUData, "Skipping strictly ordered request %lli.\n", node_ptr->seqNum); return nullptr; @@ -630,7 +630,7 @@ TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr) req->setPC(node_ptr->pc); PacketPtr pkt; uint8_t* pkt_data = new uint8_t[req->getSize()]; - if (node_ptr->isLoad) { + if (node_ptr->isLoad()) { pkt = Packet::createRead(req); } else { 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 (first) { DPRINTFR(TraceCPUData, "\t\tseq. num %lli(%s) with rob num %lli is now" - " dependency free.\n", node_ptr->seqNum, - node_ptr->isLoad ? "L" : (node_ptr->isStore ? "S" : "C"), + " dependency free.\n", node_ptr->seqNum, node_ptr->typeToStr(), node_ptr->robNum); } @@ -831,8 +830,7 @@ TraceCPU::ElasticDataGen::printReadyList() { auto graph_itr = depGraph.find(itr->seqNum); GraphNode* node_ptr M5_VAR_USED = graph_itr->second; DPRINTFR(TraceCPUData, "\t%lld(%s), %lld\n", itr->seqNum, - node_ptr->isLoad ? "L" : (node_ptr->isStore ? "S" : "C"), - itr->execTick); + node_ptr->typeToStr(), itr->execTick); itr++; } } @@ -857,9 +855,9 @@ TraceCPU::ElasticDataGen::HardwareResource::occupy(const GraphNode* new_node) oldestInFlightRobNum = inFlightNodes.begin()->second; // Occupy Load/Store Buffer entry for the issued node if applicable - if (new_node->isLoad) { + if (new_node->isLoad()) { ++numInFlightLoads; - } else if (new_node->isStore) { + } else if (new_node->isStore()) { ++numInFlightStores; } // 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 // is received. A load is considered complete when a response is received, // thus both ROB and Load Buffer entries can be released. - if (done_node->isLoad) { + if (done_node->isLoad()) { assert(numInFlightLoads != 0); --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. // writes to device registers, we do that within release() which is called // when node is executed and taken off from readyList. - if (done_node->isStore && done_node->isStrictlyOrdered()) { + if (done_node->isStore() && done_node->isStrictlyOrdered()) { releaseStoreBuffer(); } } @@ -949,10 +947,10 @@ TraceCPU::ElasticDataGen::HardwareResource::isAvailable( if (num_in_flight_nodes >= sizeROB) { return false; } - if (new_node->isLoad && numInFlightLoads >= sizeLoadBuffer) { + if (new_node->isLoad() && numInFlightLoads >= sizeLoadBuffer) { return false; } - if (new_node->isStore && numInFlightStores >= sizeStoreBuffer) { + if (new_node->isStore() && numInFlightStores >= sizeStoreBuffer) { return false; } return true; @@ -1250,8 +1248,7 @@ TraceCPU::ElasticDataGen::InputStream::read(GraphNode* element) if (trace.read(pkt_msg)) { // Required fields element->seqNum = pkt_msg.seq_num(); - element->isLoad = pkt_msg.load(); - element->isStore = pkt_msg.store(); + element->type = pkt_msg.type(); element->compDelay = pkt_msg.comp_delay(); // Repeated field robDepList @@ -1384,9 +1381,8 @@ void TraceCPU::ElasticDataGen::GraphNode::writeElementAsTrace() const { DPRINTFR(TraceCPUData, "%lli", seqNum); - DPRINTFR(TraceCPUData, ",%s", (isLoad ? "True" : "False")); - DPRINTFR(TraceCPUData, ",%s", (isStore ? "True" : "False")); - if (isLoad || isStore) { + DPRINTFR(TraceCPUData, ",%s", typeToStr()); + if (isLoad() || isStore()) { DPRINTFR(TraceCPUData, ",%i", addr); DPRINTFR(TraceCPUData, ",%i", size); DPRINTFR(TraceCPUData, ",%i", flags); @@ -1414,6 +1410,12 @@ TraceCPU::ElasticDataGen::GraphNode::writeElementAsTrace() const DPRINTFR(TraceCPUData, "\n"); } +std::string +TraceCPU::ElasticDataGen::GraphNode::typeToStr() const +{ + return Record::RecordType_Name(type); +} + TraceCPU::FixedRetryGen::InputStream::InputStream(const std::string& filename) : trace(filename) { diff --git a/src/cpu/trace/trace_cpu.hh b/src/cpu/trace/trace_cpu.hh index 3a869ebe0..751321491 100644 --- a/src/cpu/trace/trace_cpu.hh +++ b/src/cpu/trace/trace_cpu.hh @@ -561,6 +561,9 @@ class TraceCPU : public BaseCPU /** Node ROB number type. */ typedef uint64_t NodeRobNum; + typedef ProtoMessage::InstDepRecord::RecordType RecordType; + typedef ProtoMessage::InstDepRecord Record; + /** * The struct GraphNode stores an instruction in the trace file. The * format of the trace file favours constructing a dependency graph of @@ -589,11 +592,8 @@ class TraceCPU : public BaseCPU /** ROB occupancy number */ NodeRobNum robNum; - /** If instruction is a load */ - bool isLoad; - - /** If instruction is a store */ - bool isStore; + /** Type of the node corresponding to the instruction modelled by it */ + RecordType type; /** The address for the request if any */ Addr addr; @@ -632,6 +632,15 @@ class TraceCPU : public BaseCPU */ 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 */ void clearRegDep(); @@ -656,6 +665,9 @@ class TraceCPU : public BaseCPU * TraceCPUData. */ 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. */ diff --git a/src/proto/inst_dep_record.proto b/src/proto/inst_dep_record.proto index 7035bfc74..98c070efc 100644 --- a/src/proto/inst_dep_record.proto +++ b/src/proto/inst_dep_record.proto @@ -50,26 +50,31 @@ message InstDepRecordHeader { } // Packet to encapsulate an instruction in the o3cpu data dependency trace. -// The required fields include the instruction sequence number, whether it -// is a load, and whether it is a store. The request related fields are -// optional, namely address, size and flags. These exist only if the -// instruction is a load or store. The dependency related information includes -// a repeated field for order dependencies, a repeated field for register -// dependencies and the computational delay with respect to the dependency -// that completed last. A weight field is used to account for committed -// instructions that were filtered out before writing the trace and is used -// to estimate ROB occupancy during replay. An optional field is provided for -// the instruction PC. +// The required fields include the instruction sequence number and the type +// of the record associated with the instruction e.g. load. The request related +// fields are optional, namely address, size and flags. The dependency related +// information includes a repeated field for order dependencies and register +// dependencies for loads, stores and comp records. There is a field for the +// computational delay with respect to the dependency that completed last. A +// weight field is used to account for committed instruction that were +// filtered out before writing the trace and is used to estimate ROB +// occupancy during replay. An optional field is provided for the instruction +// PC. message InstDepRecord { + enum RecordType { + INVALID = 0; + LOAD = 1; + STORE = 2; + COMP = 3; + } required uint64 seq_num = 1; - required bool load = 2; - required bool store = 3; - optional uint64 addr = 4; - optional uint32 size = 5; - optional uint32 flags = 6; - repeated uint64 rob_dep = 7; - required uint64 comp_delay = 8; - repeated uint64 reg_dep = 9; - optional uint32 weight = 10; - optional uint64 pc = 11; -} + required RecordType type = 2 [default = INVALID]; + optional uint64 addr = 3; + optional uint32 size = 4; + optional uint32 flags = 5; + repeated uint64 rob_dep = 6; + required uint64 comp_delay = 7; + repeated uint64 reg_dep = 8; + optional uint32 weight = 9; + optional uint64 pc = 10; +}
\ No newline at end of file |