diff options
| author | Davit Grigoryan <[email protected]> | 2026-04-14 03:06:42 +0000 |
|---|---|---|
| committer | Davit Grigoryan <[email protected]> | 2026-04-14 03:06:42 +0000 |
| commit | 305c5ea8fed5bca224377c1bdd8c726fac0f926f (patch) | |
| tree | 549f408023103f33d6b074293e7f25f467590fc1 /src/gpgpu-sim | |
| parent | 2c3524751b9b175514970c768637266bbed08767 (diff) | |
create separate scoreboard for I-Buf's second slot; fix other minor issues
Diffstat (limited to 'src/gpgpu-sim')
| -rw-r--r-- | src/gpgpu-sim/scoreboard.cc | 31 | ||||
| -rw-r--r-- | src/gpgpu-sim/scoreboard.h | 9 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 70 |
3 files changed, 102 insertions, 8 deletions
diff --git a/src/gpgpu-sim/scoreboard.cc b/src/gpgpu-sim/scoreboard.cc index 44a9980..de71807 100644 --- a/src/gpgpu-sim/scoreboard.cc +++ b/src/gpgpu-sim/scoreboard.cc @@ -38,6 +38,7 @@ Scoreboard::Scoreboard(unsigned sid, unsigned n_warps, class gpgpu_t* gpu) // Initialize size of table reg_table.resize(n_warps); longopregs.resize(n_warps); + sec_reg_table.resize(n_warps); m_gpu = gpu; } @@ -152,3 +153,33 @@ bool Scoreboard::checkCollision(unsigned wid, const class inst_t* inst) const { bool Scoreboard::pendingWrites(unsigned wid) const { return !reg_table[wid].empty(); } + +// Secondary scoreboard methods for intra-warp co-issue + +void Scoreboard::reserveRegisterSecondary(unsigned wid, unsigned regnum) { + // No abort on duplicate — secondary may share register names with primary + sec_reg_table[wid].insert(regnum); +} + +void Scoreboard::releaseRegisterSecondary(unsigned wid, unsigned regnum) { + sec_reg_table[wid].erase(regnum); +} + +bool Scoreboard::checkCollisionSecondary(unsigned wid, + const inst_t *inst) 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 it = inst_regs.begin(); it != inst_regs.end(); it++) + if (sec_reg_table[wid].find(*it) != sec_reg_table[wid].end()) + return true; + return false; +} + +void Scoreboard::clearSecondary(unsigned wid) { + sec_reg_table[wid].clear(); +} diff --git a/src/gpgpu-sim/scoreboard.h b/src/gpgpu-sim/scoreboard.h index 1fe0923..9bf51e6 100644 --- a/src/gpgpu-sim/scoreboard.h +++ b/src/gpgpu-sim/scoreboard.h @@ -50,6 +50,12 @@ class Scoreboard { void printContents() const; const bool islongop(unsigned warp_id, unsigned regnum); + // Secondary scoreboard for intra-warp co-issue (split-level tracking) + void reserveRegisterSecondary(unsigned wid, unsigned regnum); + void releaseRegisterSecondary(unsigned wid, unsigned regnum); + bool checkCollisionSecondary(unsigned wid, const inst_t *inst) const; + void clearSecondary(unsigned wid); + private: void reserveRegister(unsigned wid, unsigned regnum); int get_sid() const { return m_sid; } @@ -62,6 +68,9 @@ class Scoreboard { // Register that depend on a long operation (global, local or tex memory) std::vector<std::set<unsigned> > longopregs; + // Secondary path register tracking (for I-Buffer half 1, intra-warp co-issue) + std::vector<std::set<unsigned> > sec_reg_table; + class gpgpu_t *m_gpu; }; diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 43e86b6..bf6c9c0 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -1350,10 +1350,16 @@ void shader_core_ctx::co_issue_warp(warp_inst_t *composite, if (split_id == (unsigned)-1) { // Inter-warp co-issue: different warp_id, always safe to reserve m_scoreboard->reserveRegisters(&temp_inst); + } else { + // Intra-warp co-issue: reserve on secondary scoreboard to track + // dependencies within the secondary split's instruction stream. + // Cannot use primary scoreboard (would abort on duplicate register names). + for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { + if (temp_inst.out[r] > 0) { + m_scoreboard->reserveRegisterSecondary(warp_id, temp_inst.out[r]); + } + } } - // For intra-warp: we skip reservation. The primary's reservation covers - // shared registers, and non-shared registers will still be released at - // writeback (the release tolerates releasing non-reserved registers). // Set next PC for the co-issued warp m_warp[warp_id]->set_next_pc(next_inst->pc + next_inst->isize); @@ -1363,6 +1369,11 @@ void shader_core_ctx::co_issue_warp(warp_inst_t *composite, // Merge the co-issued instruction's valid sets into the composite composite->merge_simd_sets(temp_inst.get_simd_sets()); + + // Use max latency across all co-issued instructions for result bus reservation + if (temp_inst.latency > composite->latency) { + composite->latency = temp_inst.latency; + } } void shader_core_ctx::issue() { @@ -1584,6 +1595,7 @@ void scheduler_unit::cycle() { // control hazard warp(warp_id).set_next_pc(pc); warp(warp_id).ibuffer_flush(); + m_scoreboard->clearSecondary(warp_id); } else { valid_inst = true; if (!m_scoreboard->checkCollision(warp_id, pI)) { @@ -1800,6 +1812,7 @@ void scheduler_unit::cycle() { (*iter)->get_warp_id(), (*iter)->get_dynamic_warp_id()); warp(warp_id).set_next_pc(pc); warp(warp_id).ibuffer_flush(); + m_scoreboard->clearSecondary(warp_id); } if (warp_inst_issued) { SCHED_DPRINTF( @@ -2008,6 +2021,7 @@ void scheduler_unit::cycle() { // Verify the split is still valid in the splits table if (!m_shader->is_split_valid(primary_warp_id, sec_split_id)) { warp(primary_warp_id).ibuffer_flush_half(1); + m_scoreboard->clearSecondary(primary_warp_id); break; } @@ -2018,6 +2032,7 @@ void scheduler_unit::cycle() { &split_mask); if (split_pc != sec_inst->pc) { warp(primary_warp_id).ibuffer_flush_half(1); + m_scoreboard->clearSecondary(primary_warp_id); break; } @@ -2052,6 +2067,10 @@ void scheduler_unit::cycle() { } if (sec_fu_type != co_issue_fu_type) continue; + // Secondary scoreboard check: dependencies within secondary stream + if (m_scoreboard->checkCollisionSecondary(primary_warp_id, sec_inst)) + continue; + // Compute sets needed unsigned sec_active = sec_mask.count(); unsigned sec_sets_needed = (sec_active + set_width - 1) / set_width; @@ -2080,6 +2099,7 @@ void scheduler_unit::cycle() { if (!m_shader->is_split_valid(primary_warp_id, sec_split_id)) { // Split was invalidated by the update — flush the entire secondary half warp(primary_warp_id).ibuffer_flush_half(1); + m_scoreboard->clearSecondary(primary_warp_id); break; } } @@ -2541,8 +2561,14 @@ void shader_core_ctx::writeback() { co_issued_warps_decremented.insert(sets[s].warp_id); } } else { - // Intra-warp: dec once for the co-issued split (same warp_id) + // Intra-warp: release from secondary scoreboard and dec once if (!intra_warp_decremented) { + for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { + if (sets[s].source_inst->out[r] > 0) { + m_scoreboard->releaseRegisterSecondary( + sets[s].warp_id, sets[s].source_inst->out[r]); + } + } m_warp[warp_id]->dec_inst_in_pipeline(); intra_warp_decremented = true; } @@ -2554,6 +2580,35 @@ void shader_core_ctx::writeback() { } warp_inst_complete(*pipe_reg); + + // Count additional co-issued instructions (not counted by warp_inst_complete) + if (m_config->gpgpu_simd_partitioning && pipe_reg->has_simd_sets()) { + const std::vector<simd_set_info> &sets = pipe_reg->get_simd_sets(); + // Accumulate active threads per unique co-issued warp/split + std::map<unsigned, unsigned> inter_warp_threads; // warp_id -> thread count + unsigned intra_threads = 0; + for (unsigned s = 0; s < sets.size(); s++) { + if (!sets[s].valid || sets[s].source_inst == NULL) continue; + if (sets[s].warp_id != warp_id) { + inter_warp_threads[sets[s].warp_id] += sets[s].num_active_threads; + } else { + intra_threads += sets[s].num_active_threads; + } + } + // Inter-warp: one warp-instruction per unique co-issued warp + for (auto &entry : inter_warp_threads) { + m_stats->m_num_sim_winsn[m_sid]++; + m_gpu->gpu_sim_insn += entry.second; + m_stats->m_num_sim_insn[m_sid] += entry.second; + } + // Intra-warp: one warp-instruction for the co-issued split + if (intra_threads > 0) { + m_stats->m_num_sim_winsn[m_sid]++; + m_gpu->gpu_sim_insn += intra_threads; + m_stats->m_num_sim_insn[m_sid] += intra_threads; + } + } + m_gpu->gpu_sim_insn_last_update_sid = m_sid; m_gpu->gpu_sim_insn_last_update = m_gpu->gpu_sim_cycle; m_last_inst_gpu_sim_cycle = m_gpu->gpu_sim_cycle; @@ -4985,8 +5040,7 @@ bool opndcoll_rfu_t::writeback(warp_inst_t &inst) { const std::vector<simd_set_info> &sets = inst.get_simd_sets(); for (unsigned s = 0; s < sets.size(); s++) { if (!sets[s].valid) continue; - if (sets[s].warp_id == inst.warp_id()) continue; - if (sets[s].source_inst == NULL) continue; + if (sets[s].source_inst == NULL) continue; // primary sets have NULL source_inst for (unsigned op = 0; op < MAX_REG_OPERANDS; op++) { int reg_num = sets[s].source_inst->arch_reg.dst[op]; @@ -5213,8 +5267,7 @@ bool opndcoll_rfu_t::collector_unit_t::allocate(register_set *pipeline_reg_set, (*pipeline_reg)->get_simd_sets(); for (unsigned s = 0; s < sets.size(); s++) { if (!sets[s].valid) continue; - if (sets[s].warp_id == m_warp_id) continue; - if (sets[s].source_inst == NULL) continue; + if (sets[s].source_inst == NULL) continue; // primary sets have NULL source_inst std::vector<int> set_prev_regs; for (unsigned op = 0; op < MAX_REG_OPERANDS && op_idx < MAX_REG_OPERANDS * 2; op++) { @@ -5702,6 +5755,7 @@ void exec_shader_core_ctx::checkExecutionStatusAndUpdate(warp_inst_t &inst, if (ptx_thread_done(tid)) { m_warp[inst.warp_id()]->set_completed(t); m_warp[inst.warp_id()]->ibuffer_flush(); + m_scoreboard->clearSecondary(inst.warp_id()); } // PC-Histogram Update |
