📄 iq_seg.cc
字号:
if (segment_number > 0) if (!(*i)->queued && promotable(*i)) enqueue(*i); } } else { // Self-timed... decrement_delay(*i, j); recalc_position = true; // Don't enqueue for segment zero if (segment_number > 0 && !(*i)->queued && promotable(*i)) enqueue(*i); } } else { decrement_delay(*i, j); recalc_position = true; } } if (recalc_position) (*i)->dest_seg = proper_segment(*i); }}voidsegment_t::decrement_delay(iq_iterator i, int op_num){ bool all_zero = true; if (i->idep_info[op_num].delay != 0) { --(i->idep_info[op_num].delay); // if this delay counter just went to zero... if (i->idep_info[op_num].delay == 0) { // check all ideps for zero delay for (int j = 0; j < TheISA::MaxInstSrcRegs; ++j) { if (i->idep_info[j].delay != 0) { all_zero = false; break; } } if (all_zero) i->st_zero_time = curTick; } }}//// Determine if this instruction should be promoted//// Assumes that the queue _forward_of_this_instruction_// is in a consistent state.//boolsegment_t::promotable(iq_iterator &inst){ bool rv = false; unsigned pred_wait; unsigned max_wait=0; int max_wait_index=-1; // We NEVER 'promote' from segment zero if (segment_number == 0) return false; // If this instruction is ready, then hurry it on down... // This shouldn't make any performance difference, but keeps us // from messing around with the code below... if (inst->ops_ready()) return true; // // Figure out which operand we should be waiting for... // // This loop calculates the predicted wait time before each head // instruction should be ready to isssue. We compare these values // in order to determine which chain we should be following. // // for (int i = 0; i < TheISA::MaxInstSrcRegs; ++i) { if (!inst->idep_ready[i]) { if (inst->idep_info[i].chained) { unsigned c_num = inst->idep_info[i].follows_chain; unsigned head_level = (*chain_info)[c_num].head_level; if (head_level == 0) pred_wait = 0 + inst->idep_info[i].delay; else pred_wait = seg_queue->seg_thresholds[head_level - 1] + inst->idep_info[i].delay; } else { pred_wait = inst->idep_info[i].delay; } if (max_wait <= pred_wait) { max_wait = pred_wait; max_wait_index = i; } } } assert(max_wait_index >= 0); IQStation::IDEP_info *idep_info = &inst->idep_info[max_wait_index]; if (idep_info->chained) { unsigned head_level = (*chain_info)[idep_info->follows_chain].head_level; // Be sure not to promote ahead of the chain-head if (head_level < segment_number) { if ((*chain_info)[idep_info->follows_chain].self_timed) { if (idep_info->delay < seg_queue->seg_thresholds[segment_number - 1]) { rv = true; } } else { unsigned head_thresh; unsigned inst_thresh = seg_queue->seg_thresholds[segment_number - 1]; if (head_level == 0) head_thresh = 0; else head_thresh = seg_queue->seg_thresholds[head_level - 1]; // calculate this instructions distance from the head // (the head_level remains at 0 after the head has issued) unsigned dist = inst_thresh - head_thresh; // If this instruction is too far behind the head... if (idep_info->delay < dist) rv = true; } } } else { // Instructions that are not chained don't need to worry about // a chain-head... they just use their built-in delay counter if (idep_info->delay < seg_queue->seg_thresholds[segment_number - 1]) { rv = true; } } return rv;}voidsegment_t::regStats(FullCPU *cpu, std::string &n){ using namespace Stats; number_of_threads = cpu->number_of_threads; stringstream label, desc, formula; string c = cpu->name() + '.'; // Occupancy stats label << n << setw(2) << setfill('0') << segment_number << ":cum_num_insts"; cum_insts .init(cpu->number_of_threads) .name(label.str()) .desc("number of insts in this segment") .flags(total) ; label.str(""); label << n << setw(2) << setfill('0') << segment_number << ":full_cycles"; segment_full .name(label.str()) .desc("number of cycles segment was full") ; label.str(""); label << n << setw(2) << setfill('0') << segment_number << ":empty_cycles"; segment_empty .name(label.str()) .desc("number of cycles segment was empty") ; label.str(""); // Segment promotion stats cum_promotions.init(number_of_threads); if (segment_number != 0) { label << n << setw(2) << setfill('0') << segment_number << ":cum_num_prom"; cum_promotions .name(label.str()) .desc("number of promotions out of this segment") .flags(total) ; label.str(""); } // // Use issue rate to determine residency for segment zero... rest use // promotion rate // if (segment_number == 0) { // // load-counting stats, etc. // cycles_low_ready .name(n+"00:L:cycle_low_ready") .desc("number of cycles segment had < 2 ready insts") ; insts_waiting_for_loads .name(n+"00:L:inst_wait_loads") .desc("number of insts waiting for issued loads") ; insts_waiting_for_unissued .name(n+"00:L:inst_wait_uniss") .desc("number of insts waiting for unissued insts") ; insts_fanout_loads .name(n+"00:L:inst_loads") .desc("number of issued load insts waited on") ; } label << n << setw(2) << setfill('0') << segment_number << ":chained_cum"; cum_chained .init(cpu->number_of_threads) .name(label.str()) .desc("number of chained insts in this segment") .flags(total) ; label.str(""); cum_ops_ready.init(cpu->number_of_threads); if (segment_number != 0) { label << n << setw(2) << setfill('0') << segment_number << ":cum_ops_ready"; cum_ops_ready .name(label.str()) .desc("number of ops-ready insts") ; label.str(""); } if (use_pushdown && segment_number < num_segments - 1 && segment_number > 0) { label << n << setw(2) << setfill('0') << segment_number << ":pd_inst"; seg_queue->pushdown_count[segment_number] .name(label.str()) .desc("number of instructions into this segment") ; label.str(""); label << n << setw(2) << setfill('0') << segment_number << ":pd_events"; seg_queue->pushdown_events[segment_number] .name(label.str()) .desc("number of pushed-down events") ; label.str(""); } // Stats for the ready-queue label.str(""); label << n << setw(2) << setfill('0') << segment_number << ":RQ"; ready_list->regStats(label.str(), cpu->number_of_threads);}voidsegment_t::regFormulas(FullCPU *cpu, std::string &n){ using namespace Stats; stringstream label, desc, formula; string c = cpu->name() + '.'; // Occupancy stats label << n << setw(2) << setfill('0') << segment_number << ":occ_rate"; occ_rate .name(label.str()) .desc("Average segment occupancy") ; occ_rate = cum_insts / cpu->numCycles; label.str(""); label << n << setw(2) << setfill('0') << segment_number << ":full_frac"; full_frac .name(label.str()) .desc("fraction of cycles where segment was full") ; full_frac = 100 * segment_full / cpu->numCycles; label.str(""); label << n << setw(2) << setfill('0') << segment_number << ":empty_frac"; empty_frac .name(label.str()) .desc("fraction of cycles where segment was empty") ; empty_frac = 100 * segment_empty / cpu->numCycles; label.str(""); // Segment promotion stats if (segment_number != 0) { label << n << setw(2) << setfill('0') << segment_number << ":prom_rate"; prom_rate .name(label.str()) .desc("promotions per cycle from this segment") ; prom_rate = cum_promotions / cpu->numCycles; label.str(""); } // // Use issue rate to determine residency for segment zero... rest use // promotion rate // if (segment_number != 0) { label << n << setw(2) << setfill('0') << segment_number << ":residency"; seg_residency .name(label.str()) .desc("segment residency (cycles)") ; seg_residency = occ_rate / prom_rate; label.str(""); } else { seg_residency .name(n+"00:residency") .desc("segment residency (cycles)") ; seg_residency = occ_rate / cpu->issue_rate; rate_loads .name(n+"00:L:rate_loads") .desc("number of issued loads waited on per cycle") ; rate_loads = insts_fanout_loads / cycles_low_ready; rate_wait_loads .name(n+"00:L:rate_wait_loads") .desc("number of insts waiting for issued loads per cycle") ; rate_wait_loads = insts_waiting_for_loads / cycles_low_ready; rate_wait_uniss .name( n+"00:L:rate_wait_uniss") .desc("number of insts waiting for unissued insts per cycle") ; rate_wait_uniss = insts_waiting_for_unissued / cycles_low_ready; avg_wait_load .name(n+"00:L:avg_wait_load") .desc("avg number of insts waiting for each load") ; avg_wait_load = insts_waiting_for_loads / insts_fanout_loads; frac_low_ready .name(n+"00:L:frac_low_ready") .desc("fraction of all cycles with low ready rates") ; frac_low_ready = cycles_low_ready / cpu->numCycles; } label << n << setw(2) << setfill('0') << segment_number << ":chained_frac"; chained_frac .name(label.str()) .desc("fraction of insts chained") ; chained_frac = 100 * cum_chained / cum_insts; label.str(""); if (segment_number != 0) { label << n << setw(2) << setfill('0') << segment_number << ":ops_ready_rate"; ops_ready_rate .name(label.str()) .desc("average number of ops-ready insts") ; ops_ready_rate = cum_ops_ready / cpu->numCycles; label.str(""); } if (use_pushdown && segment_number < num_segments - 1 && segment_number > 0) { label << n << setw(2) << setfill('0') << segment_number << ":pd_rate"; pd_rate .name(label.str()) .desc("average push-down events per cycle") ; pd_rate = seg_queue->pushdown_events[segment_number] / cpu->numCycles; label.str(""); label << n << setw(2) << setfill('0') << segment_number << ":pd_inst_rate"; pd_inst_rate .name(label.str())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -