From 54519fd51f739c3a37c4ad712b86a353eabbbfec Mon Sep 17 00:00:00 2001 From: Radhika Jagtap Date: Mon, 7 Dec 2015 16:42:16 -0600 Subject: [PATCH] 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. --- src/cpu/o3/probe/ElasticTrace.py | 4 +++- src/cpu/o3/probe/elastic_trace.cc | 21 ++++++++++++----- src/cpu/o3/probe/elastic_trace.hh | 11 +++++++-- src/cpu/trace/trace_cpu.cc | 38 +++++++++++++++++++++++-------- src/cpu/trace/trace_cpu.hh | 8 ++++++- src/mem/request.hh | 9 +++++++- src/proto/inst_dep_record.proto | 4 +++- util/decode_inst_dep_trace.py | 11 +++++---- util/encode_inst_dep_trace.py | 12 +++++----- 9 files changed, 86 insertions(+), 32 deletions(-) diff --git a/src/cpu/o3/probe/ElasticTrace.py b/src/cpu/o3/probe/ElasticTrace.py index fb3093a2c..20057ab97 100644 --- a/src/cpu/o3/probe/ElasticTrace.py +++ b/src/cpu/o3/probe/ElasticTrace.py @@ -59,4 +59,6 @@ class ElasticTrace(ProbeListenerObject): "after which to start tracing. Default " \ "zero means start tracing from first " \ "committed instruction.") - + # Whether to trace virtual addresses for memory accesses + traceVirtAddr = Param.Bool(False, "Set to true if virtual addresses are " \ + "to be traced.") diff --git a/src/cpu/o3/probe/elastic_trace.cc b/src/cpu/o3/probe/elastic_trace.cc index e1a41b696..3332816ca 100644 --- a/src/cpu/o3/probe/elastic_trace.cc +++ b/src/cpu/o3/probe/elastic_trace.cc @@ -57,7 +57,8 @@ ElasticTrace::ElasticTrace(const ElasticTraceParams* params) dataTraceStream(nullptr), instTraceStream(nullptr), startTraceInst(params->startTraceInst), - allProbesReg(false) + allProbesReg(false), + traceVirtAddr(params->traceVirtAddr) { cpu = dynamic_cast*>(params->manager); 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 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. new_record->size = head_inst->effSize; new_record->pc = head_inst->instAddr(); @@ -787,9 +790,9 @@ ElasticTrace::writeDepTrace(uint32_t num_to_write) "is as follows:\n", temp_ptr->instNum); 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); + DPRINTFR(ElasticTrace, "\thas a request with phys addr %i, " + "size %i, flags %i\n", temp_ptr->physAddr, + temp_ptr->size, temp_ptr->reqFlags); } else { 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); if (temp_ptr->isLoad() || temp_ptr->isStore()) { 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_comp_delay(temp_ptr->compDelay); diff --git a/src/cpu/o3/probe/elastic_trace.hh b/src/cpu/o3/probe/elastic_trace.hh index 001dc0e13..584cdf182 100644 --- a/src/cpu/o3/probe/elastic_trace.hh +++ b/src/cpu/o3/probe/elastic_trace.hh @@ -289,8 +289,12 @@ class ElasticTrace : public ProbeListenerObject Addr pc; /* Request flags in case of a load/store instruction */ Request::FlagsType reqFlags; - /* Request address in case of a load/store instruction */ - Addr addr; + /* Request physical address in case of a load/store instruction */ + 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 */ unsigned size; /** Default Constructor */ @@ -366,6 +370,9 @@ class ElasticTrace : public ProbeListenerObject */ 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 */ FullO3CPU* cpu; diff --git a/src/cpu/trace/trace_cpu.cc b/src/cpu/trace/trace_cpu.cc index ffa64014a..f940be2f9 100644 --- a/src/cpu/trace/trace_cpu.cc +++ b/src/cpu/trace/trace_cpu.cc @@ -597,8 +597,9 @@ PacketPtr TraceCPU::ElasticDataGen::executeMemReq(GraphNode* node_ptr) { - DPRINTF(TraceCPUData, "Executing memory request %lli (addr %d, pc %#x, " - "size %d, flags %d).\n", node_ptr->seqNum, node_ptr->addr, + DPRINTF(TraceCPUData, "Executing memory request %lli (phys addr %d, " + "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); // 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 // a request into two. 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)) { node_ptr->size = blk_size - blk_offset; ++numSplitReqs; } // Create a request and the packet containing request - Request* req = new Request(node_ptr->addr, node_ptr->size, node_ptr->flags, - masterID, node_ptr->seqNum, + Request* req = new Request(node_ptr->physAddr, node_ptr->size, + node_ptr->flags, masterID, node_ptr->seqNum, ContextID(0), ThreadID(0)); 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; uint8_t* pkt_data = new uint8_t[req->getSize()]; if (node_ptr->isLoad()) { @@ -1277,10 +1287,20 @@ TraceCPU::ElasticDataGen::InputStream::read(GraphNode* element) } // Optional fields - if (pkt_msg.has_addr()) - element->addr = pkt_msg.addr(); + if (pkt_msg.has_p_addr()) + element->physAddr = pkt_msg.p_addr(); 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()) element->size = pkt_msg.size(); @@ -1383,7 +1403,7 @@ TraceCPU::ElasticDataGen::GraphNode::writeElementAsTrace() const DPRINTFR(TraceCPUData, "%lli", seqNum); DPRINTFR(TraceCPUData, ",%s", typeToStr()); if (isLoad() || isStore()) { - DPRINTFR(TraceCPUData, ",%i", addr); + DPRINTFR(TraceCPUData, ",%i", physAddr); DPRINTFR(TraceCPUData, ",%i", size); DPRINTFR(TraceCPUData, ",%i", flags); } diff --git a/src/cpu/trace/trace_cpu.hh b/src/cpu/trace/trace_cpu.hh index 751321491..bb59c3fab 100644 --- a/src/cpu/trace/trace_cpu.hh +++ b/src/cpu/trace/trace_cpu.hh @@ -596,7 +596,13 @@ class TraceCPU : public BaseCPU RecordType type; /** 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 */ uint32_t size; diff --git a/src/mem/request.hh b/src/mem/request.hh index 177f17de2..287a823ad 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -300,7 +300,7 @@ class Request Addr _pc; /** Sequence number of the instruction that creates the request */ - const InstSeqNum _reqInstSeqNum; + InstSeqNum _reqInstSeqNum; public: @@ -675,6 +675,13 @@ class Request 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 only; setting flags should be done via setFlags(). */ bool isUncacheable() const { return _flags.isSet(UNCACHEABLE); } diff --git a/src/proto/inst_dep_record.proto b/src/proto/inst_dep_record.proto index 98c070efc..f89e51d81 100644 --- a/src/proto/inst_dep_record.proto +++ b/src/proto/inst_dep_record.proto @@ -69,7 +69,7 @@ message InstDepRecord { } required uint64 seq_num = 1; required RecordType type = 2 [default = INVALID]; - optional uint64 addr = 3; + optional uint64 p_addr = 3; optional uint32 size = 4; optional uint32 flags = 5; repeated uint64 rob_dep = 6; @@ -77,4 +77,6 @@ message InstDepRecord { repeated uint64 reg_dep = 8; optional uint32 weight = 9; optional uint64 pc = 10; + optional uint64 v_addr = 11; + optional uint32 asid = 12; } \ No newline at end of file diff --git a/util/decode_inst_dep_trace.py b/util/decode_inst_dep_trace.py index 2e7e6381c..6e4030146 100755 --- a/util/decode_inst_dep_trace.py +++ b/util/decode_inst_dep_trace.py @@ -72,12 +72,12 @@ # # The ASCII trace format uses one line per instruction with the format # 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 # dependencies comma-separated. # # 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] # 1,35652,1,COMP,8500:: # 2,35656,1,COMP,0:,1: @@ -178,9 +178,10 @@ def main(): exit(-1) - # Write to file if it has the optional fields addr, size, flags - if packet.HasField('addr'): - ascii_out.write(',%s' % (packet.addr)) + # Write to file if it has the optional fields physical addr, size, + # flags + if packet.HasField('p_addr'): + ascii_out.write(',%s' % (packet.p_addr)) if packet.HasField('size'): ascii_out.write(',%s' % (packet.size)) if packet.HasField('flags'): diff --git a/util/encode_inst_dep_trace.py b/util/encode_inst_dep_trace.py index 6293fb0ab..e54e82d70 100755 --- a/util/encode_inst_dep_trace.py +++ b/util/encode_inst_dep_trace.py @@ -72,12 +72,12 @@ # # The ASCII trace format uses one line per instruction with the format # 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 # dependencies comma-separated. # # 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] # 1,35652,1,COMP,8500:: # 2,35656,1,COMP,0:,1: @@ -167,11 +167,11 @@ def main(): 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 - # in addition to recording the computation delay + # If the instruction is a load or store record the physical addr, + # size flags in addition to recording the computation delay if dep_record.type in [DepRecord.LOAD, DepRecord.STORE]: - addr, size, flags, comp_delay = inst_info_list[4:8] - dep_record.addr = long(addr) + p_addr, size, flags, comp_delay = inst_info_list[4:8] + dep_record.p_addr = long(p_addr) dep_record.size = int(size) dep_record.flags = int(flags) dep_record.comp_delay = long(comp_delay)