45 #include "debug/ElasticTrace.hh"
59 depWindowSize(params.depWindowSize),
60 dataTraceStream(
nullptr),
61 instTraceStream(
nullptr),
62 startTraceInst(params.startTraceInst),
64 traceVirtAddr(params.traceVirtAddr),
67 cpu =
dynamic_cast<CPU *
>(params.manager);
69 cpu->getContext(0)->getIsaPtr()->regClasses();
72 fatal_if(!cpu,
"Manager of %s is not of type O3CPU and thus does not "\
73 "support dependency tracing.\n",
name());
75 fatal_if(depWindowSize == 0,
"depWindowSize parameter must be non-zero. "\
76 "Recommended size is 3x ROB size in the O3CPU.\n");
78 fatal_if(cpu->numThreads > 1,
"numThreads = %i, %s supports tracing for"\
79 "single-threaded workload only", cpu->numThreads,
name());
81 fatal_if(params.instFetchTraceFile ==
"",
"Assign instruction fetch "\
82 "trace file path to instFetchTraceFile");
83 fatal_if(params.dataDepTraceFile ==
"",
"Assign data dependency "\
84 "trace file path to dataDepTraceFile");
86 params.instFetchTraceFile);
91 ProtoMessage::PacketHeader inst_pkt_header;
92 inst_pkt_header.set_obj_id(
name());
94 instTraceStream->write(inst_pkt_header);
97 ProtoMessage::InstDepRecordHeader data_rec_header;
98 data_rec_header.set_obj_id(
name());
100 data_rec_header.set_window_size(depWindowSize);
101 dataTraceStream->write(data_rec_header);
109 inform(
"@%llu: regProbeListeners() called, startTraceInst = %llu",
127 inform(
"@%llu: No. of instructions committed = %llu, registering elastic"
159 req->getPC(), req->getVaddr(), req->getPaddr(),
160 req->getFlags(), req->getSize(),
curTick());
165 inst_fetch_pkt.set_tick(
curTick());
167 inst_fetch_pkt.set_pc(req->getPC());
168 inst_fetch_pkt.set_flags(req->getFlags());
169 inst_fetch_pkt.set_addr(req->getPaddr());
170 inst_fetch_pkt.set_size(req->getSize());
186 has already retired (mostly squashed)", dyn_inst->seqNum);
199 auto itr_exec_info =
tempStore.find(dyn_inst->seqNum);
201 exec_info_ptr = itr_exec_info->second;
204 tempStore[dyn_inst->seqNum] = exec_info_ptr;
219 auto itr_exec_info =
tempStore.find(dyn_inst->seqNum);
222 " skipping.\n", dyn_inst->seqNum);
250 int8_t max_regs = dyn_inst->numSrcRegs();
251 for (
int src_idx = 0; src_idx < max_regs; src_idx++) {
253 const RegId& src_reg = dyn_inst->srcRegIdx(src_idx);
257 PhysRegIdPtr phys_src_reg = dyn_inst->regs.renamedSrcIdx(src_idx);
259 " %i (%s)\n", seq_num,
281 max_regs = dyn_inst->numDestRegs();
282 for (
int dest_idx = 0; dest_idx < max_regs; dest_idx++) {
285 const RegId& dest_reg = dyn_inst->destRegIdx(dest_idx);
291 dyn_inst->regs.renamedDestIdx(dest_idx);
293 " %i (%s)\n", seq_num, phys_dest_reg->
flatIndex(),
306 inst_reg_pair.second);
307 auto itr_regdep_map =
physRegDepMap.find(inst_reg_pair.second);
318 auto itr_exec_info =
tempStore.find(head_inst->seqNum);
330 head_inst->hasRequest() &&
331 head_inst->getFault() ==
NoFault) {
347 if (!head_inst->isNop()) {
353 auto itr_temp_store =
tempStore.find(head_inst->seqNum);
356 "store, skipping.\n", head_inst->seqNum);
376 if (head_inst->getFault() !=
NoFault) {
378 "skip adding it to the trace\n",
379 (head_inst->isMemRef() ?
"Load/store" :
"Comp inst."),
381 }
else if (head_inst->isMemRef() && !head_inst->hasRequest()) {
383 "skip adding it to the trace\n", head_inst->seqNum);
384 }
else if (!head_inst->readPredicate()) {
386 "skip adding it to the trace\n",
387 (head_inst->isMemRef() ?
"Load/store" :
"Comp inst."),
409 new_record->
instNum = head_inst->seqNum;
410 new_record->
commit = commit;
411 new_record->
type = head_inst->isLoad() ? Record::LOAD :
412 (head_inst->isStore() ? Record::STORE :
416 new_record->
reqFlags = head_inst->memReqFlags;
417 new_record->
virtAddr = head_inst->effAddr;
418 new_record->
physAddr = head_inst->physEffAddr;
420 new_record->
size = head_inst->effSize;
421 new_record->
pc = head_inst->instAddr();
447 if (head_inst->isLoad() && !commit) {
452 std::set<InstSeqNum>::const_iterator dep_set_it;
462 "%lli\n", new_record->
instNum, *dep_set_it);
463 TraceInfo* reg_dep = trace_info_itr->second;
479 "%lli is skipped\n",new_record->
instNum, *dep_set_it);
487 if (head_inst->isStore()) {
508 (commit ?
"committed" :
"squashed"), new_record->
instNum);
529 bool find_load_not_store)
537 uint32_t num_go_back = 0;
542 while (num_go_back <
depWindowSize && from_itr != until_itr) {
543 if (find_load_not_store) {
563 past_record = *from_itr;
577 uint32_t num_go_back = 0;
578 Tick execute_tick = 0;
580 if (new_record->
isLoad()) {
584 }
else if (new_record->
isStore()) {
597 while (num_go_back <
depWindowSize && from_itr != until_itr) {
609 past_record = *from_itr;
632 Tick execute_tick)
const
639 Tick execute_tick)
const
647 Tick execute_tick)
const
656 Tick execute_tick)
const
669 auto itr_exec_info =
tempStore.find(temp_sn);
673 delete exec_info_ptr;
689 int64_t comp_delay = -1;
690 Tick execution_tick = 0, completion_tick = 0;
699 if (past_record->
isLoad()) {
705 }
else if (past_record->
isStore()) {
707 }
else if (past_record->
isComp()){
710 assert(execution_tick >= completion_tick);
711 comp_delay = execution_tick - completion_tick;
714 execution_tick, completion_tick, comp_delay);
733 int64_t comp_delay = -1;
734 Tick execution_tick = 0, completion_tick = 0;
752 assert(execution_tick >= completion_tick);
753 comp_delay = execution_tick - completion_tick;
755 execution_tick, completion_tick, comp_delay);
799 uint16_t num_filtered_nodes = 0;
802 while (num_to_write > 0) {
804 assert(temp_ptr->
type != Record::INVALID);
811 "is as follows:\n", temp_ptr->
instNum);
815 "size %i, flags %i\n", temp_ptr->
physAddr,
823 }
else if (temp_ptr->
isStore()) {
834 ProtoMessage::InstDepRecord dep_pkt;
835 dep_pkt.set_seq_num(temp_ptr->
instNum);
836 dep_pkt.set_type(temp_ptr->
type);
837 dep_pkt.set_pc(temp_ptr->
pc);
839 dep_pkt.set_flags(temp_ptr->
reqFlags);
840 dep_pkt.set_p_addr(temp_ptr->
physAddr);
844 dep_pkt.set_v_addr(temp_ptr->
virtAddr);
845 dep_pkt.set_size(temp_ptr->
size);
847 dep_pkt.set_comp_delay(temp_ptr->
compDelay);
854 dep_pkt.add_rob_dep(temp_ptr->
robDepList.front());
866 if (num_filtered_nodes != 0) {
871 dep_pkt.set_weight(num_filtered_nodes);
872 num_filtered_nodes = 0;
880 ++num_filtered_nodes;
887 depTrace.erase(dep_trace_itr_start, dep_trace_itr);
891 : statistics::
Group(parent),
892 ADD_STAT(numRegDep, statistics::units::Count::get(),
893 "Number of register dependencies recorded during tracing"),
894 ADD_STAT(numOrderDepStores, statistics::units::Count::get(),
895 "Number of commit order (rob) dependencies for a store "
896 "recorded on a past load/store during tracing"),
897 ADD_STAT(numIssueOrderDepLoads, statistics::units::Count::get(),
898 "Number of loads that got assigned issue order dependency "
899 "because they were dependency-free"),
900 ADD_STAT(numIssueOrderDepStores, statistics::units::Count::get(),
901 "Number of stores that got assigned issue order dependency "
902 "because they were dependency-free"),
903 ADD_STAT(numIssueOrderDepOther, statistics::units::Count::get(),
904 "Number of non load/store insts that got assigned issue order "
905 "dependency because they were dependency-free"),
906 ADD_STAT(numFilteredNodes, statistics::units::Count::get(),
907 "No. of nodes filtered out before writing the output trace"),
908 ADD_STAT(maxNumDependents, statistics::units::Count::get(),
909 "Maximum number or dependents on any instruction"),
910 ADD_STAT(maxTempStoreSize, statistics::units::Count::get(),
911 "Maximum size of the temporary store during the run"),
912 ADD_STAT(maxPhysRegDepMapSize, statistics::units::Count::get(),
913 "Maximum size of register dependency map")
920 return Record::RecordType_Name(
type);