From fbb90ef3a76cd6c469782c84668d25c5f3bfdd22 Mon Sep 17 00:00:00 2001 From: Davit Grigoryan Date: Tue, 28 Apr 2026 22:06:08 +0000 Subject: critical fix - add option to have masks for SB entries --- src/gpgpu-sim/scoreboard.cc | 181 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 168 insertions(+), 13 deletions(-) (limited to 'src/gpgpu-sim/scoreboard.cc') 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 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()); + } + } } -- cgit v1.3