summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/scoreboard.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpgpu-sim/scoreboard.cc')
-rw-r--r--src/gpgpu-sim/scoreboard.cc144
1 files changed, 138 insertions, 6 deletions
diff --git a/src/gpgpu-sim/scoreboard.cc b/src/gpgpu-sim/scoreboard.cc
index 09bb5b7..4c270b9 100644
--- a/src/gpgpu-sim/scoreboard.cc
+++ b/src/gpgpu-sim/scoreboard.cc
@@ -44,6 +44,7 @@ Scoreboard::Scoreboard(unsigned sid, unsigned n_warps, class gpgpu_t* gpu,
sec_reg_table.resize(n_warps);
mask_reg_table.resize(n_warps);
slot_reg_table.resize(n_warps);
+ m_xslot_shadow_mask_table.resize(n_warps);
m_gpu = gpu;
@@ -132,9 +133,12 @@ void Scoreboard::reserveRegisters(const class warp_inst_t* inst) {
// Slot-pinned: insert into the inst's owning ibuffer half's table.
unsigned slot = inst->get_ibuffer_half_id();
assert(slot < NUM_SLOTS);
+ const active_mask_t &shadow_mask = inst->get_active_mask();
for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
if (inst->out[r] > 0) {
reserveRegisterSlot(inst->warp_id(), slot, inst->out[r]);
+ // Mask-aware shadow for diag (sb=1-equivalent ground truth).
+ reserveShadowMask(inst->warp_id(), inst->out[r], shadow_mask);
}
}
} else {
@@ -178,9 +182,12 @@ void Scoreboard::releaseRegisters(const class warp_inst_t* inst) {
} else if (m_mode == 2) {
unsigned slot = inst->get_ibuffer_half_id();
assert(slot < NUM_SLOTS);
+ const active_mask_t &shadow_mask = inst->get_active_mask();
for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
if (inst->out[r] > 0) {
releaseRegisterSlot(inst->warp_id(), slot, inst->out[r]);
+ // Mask-aware shadow release.
+ releaseShadowMask(inst->warp_id(), inst->out[r], shadow_mask);
longopregs[inst->warp_id()].erase(inst->out[r]);
}
}
@@ -350,6 +357,8 @@ void Scoreboard::releaseSetReg(unsigned wid, unsigned reg,
releaseRegisterMask(wid, reg, mask);
} else if (m_mode == 2) {
releaseRegisterSlot(wid, slot_id, reg);
+ // Mask-aware shadow release (per-set writeback path).
+ releaseShadowMask(wid, reg, mask);
} else if (is_intra_legacy) {
releaseRegisterSecondary(wid, reg);
} else {
@@ -364,17 +373,118 @@ void Scoreboard::releaseSetReg(unsigned wid, unsigned reg,
void Scoreboard::reserveRegisterSlot(unsigned wid, unsigned slot,
unsigned regnum) {
assert(slot < NUM_SLOTS);
- // Idempotent insert: same slot may try to reserve same reg if a
- // back-to-back write to the same dest is co-issued by the same split
- // through this slot. Mode 2 keeps it as a flat set (not ref-counted)
- // for simplicity — relies on writeback's idempotent erase semantics.
- slot_reg_table[wid][slot].insert(regnum);
+ // Ref-counted: each pending write to (slot, reg) increments. Two
+ // back-to-back writes to the same reg from the same slot must both
+ // be tracked — the prior set-based impl's idempotent insert lost the
+ // second write's pending state when the first retired (same-slot
+ // RAW miss). Each releaseRegisterSlot decrements; entry erased at 0.
+ slot_reg_table[wid][slot][regnum]++;
}
void Scoreboard::releaseRegisterSlot(unsigned wid, unsigned slot,
unsigned regnum) {
assert(slot < NUM_SLOTS);
- slot_reg_table[wid][slot].erase(regnum);
+ auto it = slot_reg_table[wid][slot].find(regnum);
+ if (it == slot_reg_table[wid][slot].end()) return; // idempotent
+ if (it->second > 1) {
+ it->second--;
+ } else {
+ slot_reg_table[wid][slot].erase(it);
+ }
+}
+
+// =====================================================================
+// Mode 2 mask-aware shadow table (diagnostic only — not used for any
+// hazard-detection or stalling decision). Mirrors mask_reg_table's
+// semantics so we can compare slot-pinned check vs sb=1 ground truth
+// at issue eligibility sites.
+// =====================================================================
+void Scoreboard::reserveShadowMask(unsigned wid, unsigned reg,
+ const active_mask_t &mask) {
+ if (m_mode != 2) return;
+ for (auto &e : m_xslot_shadow_mask_table[wid]) {
+ if (e.reg == reg && e.mask == mask) {
+ e.ref_count++;
+ return;
+ }
+ }
+ mask_resv e;
+ e.reg = reg;
+ e.mask = mask;
+ e.ref_count = 1;
+ e.resv_cycle = m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle;
+ m_xslot_shadow_mask_table[wid].push_back(e);
+}
+
+void Scoreboard::releaseShadowMask(unsigned wid, unsigned reg,
+ const active_mask_t &mask) {
+ if (m_mode != 2) return;
+ for (auto it = m_xslot_shadow_mask_table[wid].begin();
+ it != m_xslot_shadow_mask_table[wid].end(); ++it) {
+ if (it->reg == reg && it->mask == mask) {
+ assert(it->ref_count > 0);
+ it->ref_count--;
+ if (it->ref_count == 0) {
+ m_xslot_shadow_mask_table[wid].erase(it);
+ }
+ return;
+ }
+ }
+ // Idempotent no-op on no match — mirrors releaseRegisterMask.
+}
+
+bool Scoreboard::checkCollisionShadow(unsigned wid,
+ const class inst_t *inst,
+ const active_mask_t &mask) const {
+ if (m_mode != 2) return false;
+ std::set<int> inst_regs;
+ for (unsigned i = 0; i < inst->outcount; i++) inst_regs.insert(inst->out[i]);
+ for (unsigned j = 0; j < inst->incount; j++) inst_regs.insert(inst->in[j]);
+ if (inst->pred > 0) inst_regs.insert(inst->pred);
+ if (inst->ar1 > 0) inst_regs.insert(inst->ar1);
+ if (inst->ar2 > 0) inst_regs.insert(inst->ar2);
+ for (auto reg : inst_regs) {
+ if (reg <= 0) continue;
+ for (const auto &e : m_xslot_shadow_mask_table[wid]) {
+ if (e.reg == (unsigned)reg && (e.mask & mask).any()) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void Scoreboard::dumpShadowOverlap(unsigned wid, const class inst_t *inst,
+ const active_mask_t &mask, FILE *out,
+ const char *site,
+ unsigned long long cyc) const {
+ if (m_mode != 2) return;
+ std::set<int> inst_regs;
+ for (unsigned i = 0; i < inst->outcount; i++) inst_regs.insert(inst->out[i]);
+ for (unsigned j = 0; j < inst->incount; j++) inst_regs.insert(inst->in[j]);
+ if (inst->pred > 0) inst_regs.insert(inst->pred);
+ if (inst->ar1 > 0) inst_regs.insert(inst->ar1);
+ if (inst->ar2 > 0) inst_regs.insert(inst->ar2);
+ for (auto reg : inst_regs) {
+ if (reg <= 0) continue;
+ for (const auto &e : m_xslot_shadow_mask_table[wid]) {
+ if (e.reg == (unsigned)reg && (e.mask & mask).any()) {
+ // Lookup which slot has the reg (or both / neither).
+ auto it0 = slot_reg_table[wid][0].find((unsigned)reg);
+ auto it1 = slot_reg_table[wid][1].find((unsigned)reg);
+ unsigned cnt0 = (it0 == slot_reg_table[wid][0].end()) ? 0u : it0->second;
+ unsigned cnt1 = (it1 == slot_reg_table[wid][1].end()) ? 0u : it1->second;
+ fprintf(out,
+ "[XSLOT_RAW] cyc=%llu site=%s sid=%u wid=%u reg=%d "
+ "issue_mask=%s entry_mask=%s entry_resv_cyc=%llu "
+ "issue_count=%lu entry_count=%lu intersection_count=%lu "
+ "slot0_cnt=%u slot1_cnt=%u\n",
+ cyc, site, m_sid, wid, reg, mask.to_string().c_str(),
+ e.mask.to_string().c_str(), e.resv_cycle, mask.count(),
+ e.mask.count(), (e.mask & mask).count(), cnt0, cnt1);
+ }
+ }
+ }
}
bool Scoreboard::checkCollisionSlot(unsigned wid, unsigned slot,
@@ -459,6 +569,28 @@ void Scoreboard::dumpAccounting(FILE* out) const {
m_sid, m_mask_reserve_inserts, m_mask_reserve_inc_refcount,
m_mask_release_match, m_mask_release_nomatch, m_mask_release_erase,
mask_remaining_entries, mask_remaining_refcount);
+ // Mode 2 (slot-pinned) cross-slot hazard diagnostics.
+ // _would_stall : unmasked slot=1 reg-name match (over-counts; lane-disjoint
+ // cross-slot writes count too).
+ // _real_would_stall : mask-aware shadow-table check (sb=1 ground truth);
+ // counts only true RAWs that sb=2 missed.
+ unsigned long long shadow_remaining = 0;
+ for (unsigned w = 0; w < m_xslot_shadow_mask_table.size(); w++) {
+ shadow_remaining += m_xslot_shadow_mask_table[w].size();
+ }
+ fprintf(out,
+ "xslot_hazard_diag sid=%u primary_checks=%llu primary_would_stall=%llu "
+ "primary_real_would_stall=%llu "
+ "inter_checks=%llu inter_would_stall=%llu inter_real_would_stall=%llu "
+ "intra_checks=%llu intra_would_stall=%llu "
+ "shadow_remaining_entries=%llu\n",
+ m_sid, m_xslot_primary_issue_checks,
+ m_xslot_primary_issue_would_stall,
+ m_xslot_primary_issue_real_would_stall,
+ m_xslot_inter_coissue_checks, m_xslot_inter_coissue_would_stall,
+ m_xslot_inter_coissue_real_would_stall,
+ m_xslot_intra_coissue_checks, m_xslot_intra_coissue_would_stall,
+ shadow_remaining);
// If anything is leaked, dump per-warp leak details.
if (mask_remaining_entries > 0) {
for (unsigned w = 0; w < mask_reg_table.size(); w++) {