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 fatal_if(!cpu,
"Manager of %s is not of type O3CPU and thus does not "\
70 "support dependency tracing.\n",
name());
72 fatal_if(depWindowSize == 0,
"depWindowSize parameter must be non-zero. "\
73 "Recommended size is 3x ROB size in the O3CPU.\n");
75 fatal_if(cpu->numThreads > 1,
"numThreads = %i, %s supports tracing for"\
76 "single-threaded workload only", cpu->numThreads,
name());
78 fatal_if(params.instFetchTraceFile ==
"",
"Assign instruction fetch "\
79 "trace file path to instFetchTraceFile");
80 fatal_if(params.dataDepTraceFile ==
"",
"Assign data dependency "\
81 "trace file path to dataDepTraceFile");
83 params.instFetchTraceFile);
88 ProtoMessage::PacketHeader inst_pkt_header;
89 inst_pkt_header.set_obj_id(
name());
91 instTraceStream->write(inst_pkt_header);
94 ProtoMessage::InstDepRecordHeader data_rec_header;
95 data_rec_header.set_obj_id(
name());
97 data_rec_header.set_window_size(depWindowSize);
98 dataTraceStream->write(data_rec_header);
106 inform(
"@%llu: regProbeListeners() called, startTraceInst = %llu",
115 cpu->getContext(0)->scheduleInstCountEvent(
124 inform(
"@%llu: No. of instructions committed = %llu, registering elastic"
125 " probe listeners",
curTick(),
cpu->numSimulatedInsts());
156 req->getPC(), req->getVaddr(), req->getPaddr(),
157 req->getFlags(), req->getSize(),
curTick());
162 inst_fetch_pkt.set_tick(
curTick());
164 inst_fetch_pkt.set_pc(req->getPC());
165 inst_fetch_pkt.set_flags(req->getFlags());
166 inst_fetch_pkt.set_addr(req->getPaddr());
167 inst_fetch_pkt.set_size(req->getSize());
183 has already retired (mostly squashed)", dyn_inst->seqNum);
196 auto itr_exec_info =
tempStore.find(dyn_inst->seqNum);
198 exec_info_ptr = itr_exec_info->second;
201 tempStore[dyn_inst->seqNum] = exec_info_ptr;
216 auto itr_exec_info =
tempStore.find(dyn_inst->seqNum);
219 " skipping.\n", dyn_inst->seqNum);
247 int8_t max_regs = dyn_inst->numSrcRegs();
248 for (
int src_idx = 0; src_idx < max_regs; src_idx++) {
250 const RegId& src_reg = dyn_inst->srcRegIdx(src_idx);
253 PhysRegIdPtr phys_src_reg = dyn_inst->renamedSrcIdx(src_idx);
255 " %i (%s)\n", seq_num,
277 max_regs = dyn_inst->numDestRegs();
278 for (
int dest_idx = 0; dest_idx < max_regs; dest_idx++) {
281 const RegId& dest_reg = dyn_inst->destRegIdx(dest_idx);
286 dyn_inst->renamedDestIdx(dest_idx);
288 " %i (%s)\n", seq_num, phys_dest_reg->
flatIndex(),
301 inst_reg_pair.second);
302 auto itr_regdep_map =
physRegDepMap.find(inst_reg_pair.second);
313 auto itr_exec_info =
tempStore.find(head_inst->seqNum);
325 head_inst->hasRequest() &&
326 head_inst->getFault() ==
NoFault) {
342 if (!head_inst->isNop()) {
348 auto itr_temp_store =
tempStore.find(head_inst->seqNum);
351 "store, skipping.\n", head_inst->seqNum);
371 if (head_inst->getFault() !=
NoFault) {
373 "skip adding it to the trace\n",
374 (head_inst->isMemRef() ?
"Load/store" :
"Comp inst."),
376 }
else if (head_inst->isMemRef() && !head_inst->hasRequest()) {
378 "skip adding it to the trace\n", head_inst->seqNum);
379 }
else if (!head_inst->readPredicate()) {
381 "skip adding it to the trace\n",
382 (head_inst->isMemRef() ?
"Load/store" :
"Comp inst."),
404 new_record->
instNum = head_inst->seqNum;
405 new_record->
commit = commit;
406 new_record->
type = head_inst->isLoad() ? Record::LOAD :
407 (head_inst->isStore() ? Record::STORE :
411 new_record->
reqFlags = head_inst->memReqFlags;
412 new_record->
virtAddr = head_inst->effAddr;
413 new_record->
physAddr = head_inst->physEffAddr;
415 new_record->
size = head_inst->effSize;
416 new_record->
pc = head_inst->pcState().instAddr();
442 if (head_inst->isLoad() && !commit) {
447 std::set<InstSeqNum>::const_iterator dep_set_it;
457 "%lli\n", new_record->
instNum, *dep_set_it);
458 TraceInfo* reg_dep = trace_info_itr->second;
474 "%lli is skipped\n",new_record->
instNum, *dep_set_it);
482 if (head_inst->isStore()) {
503 (commit ?
"committed" :
"squashed"), new_record->
instNum);
524 bool find_load_not_store)
532 uint32_t num_go_back = 0;
537 while (num_go_back <
depWindowSize && from_itr != until_itr) {
538 if (find_load_not_store) {
558 past_record = *from_itr;
572 uint32_t num_go_back = 0;
573 Tick execute_tick = 0;
575 if (new_record->
isLoad()) {
579 }
else if (new_record->
isStore()) {
592 while (num_go_back <
depWindowSize && from_itr != until_itr) {
604 past_record = *from_itr;
627 Tick execute_tick)
const
634 Tick execute_tick)
const
642 Tick execute_tick)
const
651 Tick execute_tick)
const
664 auto itr_exec_info =
tempStore.find(temp_sn);
668 delete exec_info_ptr;
684 int64_t comp_delay = -1;
685 Tick execution_tick = 0, completion_tick = 0;
694 if (past_record->
isLoad()) {
700 }
else if (past_record->
isStore()) {
702 }
else if (past_record->
isComp()){
705 assert(execution_tick >= completion_tick);
706 comp_delay = execution_tick - completion_tick;
709 execution_tick, completion_tick, comp_delay);
728 int64_t comp_delay = -1;
729 Tick execution_tick = 0, completion_tick = 0;
747 assert(execution_tick >= completion_tick);
748 comp_delay = execution_tick - completion_tick;
750 execution_tick, completion_tick, comp_delay);
794 uint16_t num_filtered_nodes = 0;
797 while (num_to_write > 0) {
799 assert(temp_ptr->
type != Record::INVALID);
806 "is as follows:\n", temp_ptr->
instNum);
810 "size %i, flags %i\n", temp_ptr->
physAddr,
818 }
else if (temp_ptr->
isStore()) {
829 ProtoMessage::InstDepRecord dep_pkt;
830 dep_pkt.set_seq_num(temp_ptr->
instNum);
831 dep_pkt.set_type(temp_ptr->
type);
832 dep_pkt.set_pc(temp_ptr->
pc);
834 dep_pkt.set_flags(temp_ptr->
reqFlags);
835 dep_pkt.set_p_addr(temp_ptr->
physAddr);
839 dep_pkt.set_v_addr(temp_ptr->
virtAddr);
840 dep_pkt.set_size(temp_ptr->
size);
842 dep_pkt.set_comp_delay(temp_ptr->
compDelay);
849 dep_pkt.add_rob_dep(temp_ptr->
robDepList.front());
861 if (num_filtered_nodes != 0) {
866 dep_pkt.set_weight(num_filtered_nodes);
867 num_filtered_nodes = 0;
875 ++num_filtered_nodes;
882 depTrace.erase(dep_trace_itr_start, dep_trace_itr);
886 : statistics::
Group(parent),
887 ADD_STAT(numRegDep, statistics::units::Count::get(),
888 "Number of register dependencies recorded during tracing"),
889 ADD_STAT(numOrderDepStores, statistics::units::Count::get(),
890 "Number of commit order (rob) dependencies for a store "
891 "recorded on a past load/store during tracing"),
892 ADD_STAT(numIssueOrderDepLoads, statistics::units::Count::get(),
893 "Number of loads that got assigned issue order dependency "
894 "because they were dependency-free"),
895 ADD_STAT(numIssueOrderDepStores, statistics::units::Count::get(),
896 "Number of stores that got assigned issue order dependency "
897 "because they were dependency-free"),
898 ADD_STAT(numIssueOrderDepOther, statistics::units::Count::get(),
899 "Number of non load/store insts that got assigned issue order "
900 "dependency because they were dependency-free"),
901 ADD_STAT(numFilteredNodes, statistics::units::Count::get(),
902 "No. of nodes filtered out before writing the output trace"),
903 ADD_STAT(maxNumDependents, statistics::units::Count::get(),
904 "Maximum number or dependents on any instruction"),
905 ADD_STAT(maxTempStoreSize, statistics::units::Count::get(),
906 "Maximum size of the temporary store during the run"),
907 ADD_STAT(maxPhysRegDepMapSize, statistics::units::Count::get(),
908 "Maximum size of register dependency map")
915 return Record::RecordType_Name(
type);