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.cc181
1 files changed, 168 insertions, 13 deletions
diff --git a/src/gpgpu-sim/scoreboard.cc b/src/gpgpu-sim/scoreboard.cc
index 6cdcaf5..70e6ac1 100644
--- a/src/gpgpu-sim/scoreboard.cc
+++ b/src/gpgpu-sim/scoreboard.cc
@@ -33,13 +33,16 @@
#include "shader_trace.h"
// Constructor
-Scoreboard::Scoreboard(unsigned sid, unsigned n_warps, class gpgpu_t* gpu)
+Scoreboard::Scoreboard(unsigned sid, unsigned n_warps, class gpgpu_t* gpu,
+ unsigned mode)
: longopregs() {
m_sid = sid;
+ m_mode = mode;
// Initialize size of table
reg_table.resize(n_warps);
longopregs.resize(n_warps);
sec_reg_table.resize(n_warps);
+ mask_reg_table.resize(n_warps);
m_gpu = gpu;
@@ -55,6 +58,11 @@ Scoreboard::Scoreboard(unsigned sid, unsigned n_warps, class gpgpu_t* gpu)
m_sec_total_duration_cycles = 0;
m_sec_completed_reservations = 0;
m_sec_max_duration_cycles = 0;
+ m_mask_reserve_inserts = 0;
+ m_mask_reserve_inc_refcount = 0;
+ m_mask_release_match = 0;
+ m_mask_release_nomatch = 0;
+ m_mask_release_erase = 0;
}
// Print scoreboard contents
@@ -111,15 +119,26 @@ const bool Scoreboard::islongop(unsigned warp_id, unsigned regnum) {
}
void Scoreboard::reserveRegisters(const class warp_inst_t* inst) {
- for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
- if (inst->out[r] > 0) {
- reserveRegister(inst->warp_id(), inst->out[r]);
- SHADER_DPRINTF(SCOREBOARD, "Reserved register - warp:%d, reg: %d\n",
- inst->warp_id(), inst->out[r]);
+ if (m_mode == 1) {
+ // Mask-aware: insert (reg, inst's active mask, ref_count++) per output.
+ const active_mask_t &mask = inst->get_active_mask();
+ for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
+ if (inst->out[r] > 0) {
+ reserveRegisterMask(inst->warp_id(), inst->out[r], mask);
+ }
+ }
+ } else {
+ for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
+ if (inst->out[r] > 0) {
+ reserveRegister(inst->warp_id(), inst->out[r]);
+ SHADER_DPRINTF(SCOREBOARD, "Reserved register - warp:%d, reg: %d\n",
+ inst->warp_id(), inst->out[r]);
+ }
}
}
- // Keep track of long operations
+ // Keep track of long operations (longopregs is mode-agnostic — used as a
+ // hint by issue eligibility, not for hazard tracking)
if (inst->is_load() && (inst->space.get_type() == global_space ||
inst->space.get_type() == local_space ||
inst->space.get_type() == param_space_kernel ||
@@ -138,12 +157,22 @@ void Scoreboard::reserveRegisters(const class warp_inst_t* inst) {
// Release registers for an instruction
void Scoreboard::releaseRegisters(const class warp_inst_t* inst) {
- for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
- if (inst->out[r] > 0) {
- SHADER_DPRINTF(SCOREBOARD, "Register Released - warp:%d, reg: %d\n",
- inst->warp_id(), inst->out[r]);
- releaseRegister(inst->warp_id(), inst->out[r]);
- longopregs[inst->warp_id()].erase(inst->out[r]);
+ if (m_mode == 1) {
+ const active_mask_t &mask = inst->get_active_mask();
+ for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
+ if (inst->out[r] > 0) {
+ releaseRegisterMask(inst->warp_id(), inst->out[r], mask);
+ longopregs[inst->warp_id()].erase(inst->out[r]);
+ }
+ }
+ } else {
+ for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) {
+ if (inst->out[r] > 0) {
+ SHADER_DPRINTF(SCOREBOARD, "Register Released - warp:%d, reg: %d\n",
+ inst->warp_id(), inst->out[r]);
+ releaseRegister(inst->warp_id(), inst->out[r]);
+ longopregs[inst->warp_id()].erase(inst->out[r]);
+ }
}
}
}
@@ -180,9 +209,14 @@ bool Scoreboard::checkCollision(unsigned wid, const class inst_t* inst) const {
}
bool Scoreboard::pendingWrites(unsigned wid) const {
+ if (m_mode == 1) return !mask_reg_table[wid].empty();
return !reg_table[wid].empty();
}
+bool Scoreboard::pendingWritesAny(unsigned wid) const {
+ return pendingWrites(wid);
+}
+
// Secondary scoreboard methods for intra-warp co-issue
void Scoreboard::reserveRegisterSecondary(unsigned wid, unsigned regnum) {
@@ -237,6 +271,88 @@ void Scoreboard::clearSecondary(unsigned wid) {
sec_reg_table[wid].clear();
}
+// =====================================================================
+// Mode 1: mask-aware scoreboard
+// =====================================================================
+//
+// Each reservation is a (reg, active_mask, ref_count) tuple. Identical
+// (reg, mask) reservations are coalesced into one entry with ref_count
+// incremented. Hazard detection is mask intersection — an instruction
+// with active_mask M collides on register R iff there exists an entry
+// (R, M', _) with (M & M').any().
+//
+// Release is idempotent: matching entry decrements ref_count and is
+// erased when ref_count hits zero; mismatch is silently ignored (so
+// the existing per-set release loops, which call release once per valid
+// set, work without dedup).
+
+void Scoreboard::reserveRegisterMask(unsigned wid, unsigned reg,
+ const active_mask_t &mask) {
+ for (auto &e : mask_reg_table[wid]) {
+ if (e.reg == reg && e.mask == mask) {
+ e.ref_count++;
+ m_mask_reserve_inc_refcount++;
+ 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;
+ mask_reg_table[wid].push_back(e);
+ m_mask_reserve_inserts++;
+}
+
+void Scoreboard::releaseRegisterMask(unsigned wid, unsigned reg,
+ const active_mask_t &mask) {
+ for (auto it = mask_reg_table[wid].begin();
+ it != mask_reg_table[wid].end(); ++it) {
+ if (it->reg == reg && it->mask == mask) {
+ assert(it->ref_count > 0);
+ it->ref_count--;
+ m_mask_release_match++;
+ if (it->ref_count == 0) {
+ mask_reg_table[wid].erase(it);
+ m_mask_release_erase++;
+ }
+ return;
+ }
+ }
+ m_mask_release_nomatch++;
+ // No matching entry — idempotent no-op (mirrors legacy releaseRegister).
+}
+
+void Scoreboard::releaseSetReg(unsigned wid, unsigned reg,
+ const active_mask_t &mask,
+ bool is_intra_legacy) {
+ if (m_mode == 1) {
+ releaseRegisterMask(wid, reg, mask);
+ } else if (is_intra_legacy) {
+ releaseRegisterSecondary(wid, reg);
+ } else {
+ releaseRegister(wid, reg);
+ }
+}
+
+bool Scoreboard::checkCollisionMask(unsigned wid, const class inst_t *inst,
+ const active_mask_t &mask) const {
+ 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 : mask_reg_table[wid]) {
+ if (e.reg == (unsigned)reg && (e.mask & mask).any()) return true;
+ }
+ }
+ return false;
+}
+
// End-of-run accounting dump.
void Scoreboard::dumpAccounting(FILE* out) const {
unsigned long long primary_remaining = 0;
@@ -268,6 +384,34 @@ void Scoreboard::dumpAccounting(FILE* out) const {
m_sec_release_calls, sec_remaining, m_sec_completed_reservations,
sec_avg_dur, m_sec_max_duration_cycles, m_sec_clear_calls,
m_sec_clear_regs_dropped);
+ // Mode 1 mask-aware scoreboard accounting.
+ unsigned long long mask_remaining_entries = 0;
+ unsigned long long mask_remaining_refcount = 0;
+ for (unsigned w = 0; w < mask_reg_table.size(); w++) {
+ mask_remaining_entries += mask_reg_table[w].size();
+ for (const auto &e : mask_reg_table[w]) mask_remaining_refcount += e.ref_count;
+ }
+ fprintf(out,
+ "mask_scoreboard_accounting sid=%u inserts=%llu inc_refcount=%llu "
+ "release_match=%llu release_nomatch=%llu erase=%llu "
+ "remaining_entries=%llu remaining_refcount=%llu\n",
+ 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);
+ // If anything is leaked, dump per-warp leak details.
+ if (mask_remaining_entries > 0) {
+ for (unsigned w = 0; w < mask_reg_table.size(); w++) {
+ if (mask_reg_table[w].empty()) continue;
+ fprintf(out, " mask_leak sid=%u wid=%u entries=%zu:\n", m_sid, w,
+ mask_reg_table[w].size());
+ for (const auto &e : mask_reg_table[w]) {
+ fprintf(out,
+ " reg=%u ref_count=%u resv_cycle=%llu mask_count=%lu mask=%s\n",
+ e.reg, e.ref_count, e.resv_cycle, e.mask.count(),
+ e.mask.to_string().c_str());
+ }
+ }
+ }
}
// Read-only diagnostic. Prints the primary and secondary scoreboard
@@ -290,4 +434,15 @@ void Scoreboard::dump_warp_state(FILE *out, unsigned wid) const {
for (auto r : longopregs[wid]) fprintf(out, " r%u", r);
fprintf(out, "\n");
}
+ // Mode 1: mask_reg_table for this warp.
+ if (wid < mask_reg_table.size() && !mask_reg_table[wid].empty()) {
+ fprintf(out, " mask_reg_table[%u] (size=%zu):\n", wid,
+ mask_reg_table[wid].size());
+ for (const auto &e : mask_reg_table[wid]) {
+ fprintf(out,
+ " reg=%u ref_count=%u resv_cycle=%llu mask_count=%lu mask=%s\n",
+ e.reg, e.ref_count, e.resv_cycle, e.mask.count(),
+ e.mask.to_string().c_str());
+ }
+ }
}