summaryrefslogtreecommitdiff
path: root/src/gpgpu-sim/shader.cc
diff options
context:
space:
mode:
authorDavit Grigoryan <[email protected]>2026-04-28 09:50:44 +0000
committerDavit Grigoryan <[email protected]>2026-04-28 09:50:44 +0000
commit3d4d274eb3a6a23a5924b557d010590e219c5256 (patch)
tree451bc70a5292e9cc055645f2d7365c3332df8385 /src/gpgpu-sim/shader.cc
parent2e2f1c89a6b296c9cb28c8e8b0fabb670b4ba3f7 (diff)
fix atomic counters; add more dbg prints
Diffstat (limited to 'src/gpgpu-sim/shader.cc')
-rw-r--r--src/gpgpu-sim/shader.cc116
1 files changed, 115 insertions, 1 deletions
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index 9a1658d..a2a77a7 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -6469,6 +6469,15 @@ void shader_core_ctx::set_max_cta(const kernel_info_t &kernel) {
}
void shader_core_ctx::decrement_atomic_count(unsigned wid, unsigned n) {
+ static const bool dbg =
+ (getenv("MEMCO_DBG_DEADLOCK") != NULL);
+ if (dbg) {
+ fprintf(stdout,
+ "[ATOMIC_DEC] sid=%u wid=%u dec=%u prev=%u new=%u\n",
+ m_sid, wid, n, m_warp[wid]->get_n_atomic(),
+ m_warp[wid]->get_n_atomic() - n);
+ fflush(stdout);
+ }
assert(m_warp[wid]->get_n_atomic() >= n);
m_warp[wid]->dec_n_atomic(n);
}
@@ -7189,6 +7198,95 @@ void simt_core_cluster::print_not_completed(FILE *fp) const {
}
}
+// Read-only diagnostic — dispatches a per-warp state dump for every core
+// in this cluster that still has un-completed threads. Called from
+// gpu-sim.cc::deadlock_check() under MEMCO_DBG_DEADLOCK env var.
+void simt_core_cluster::dump_warps_at_deadlock(FILE *fp) {
+ for (unsigned i = 0; i < m_config->n_simt_cores_per_cluster; i++) {
+ if (m_core[i]->get_not_completed() == 0) continue;
+ m_core[i]->dump_warps_at_deadlock(fp);
+ }
+}
+
+// Read-only diagnostic — for each warp on this core, prints flags,
+// ibuffer slots, simt-table state, and scoreboard reservations. Helps
+// pinpoint which warp is stuck and why when the deadlock detector fires.
+// No state mutation: only invokes accessors.
+void shader_core_ctx::dump_warps_at_deadlock(FILE *fout) {
+ fprintf(fout, "[DEADLOCK_DUMP] === core sid=%u not_completed=%u ===\n",
+ m_sid, get_not_completed());
+ for (unsigned wid = 0; wid < m_warp.size(); wid++) {
+ if (m_warp[wid] == NULL) continue;
+ shd_warp_t *w = m_warp[wid];
+ bool valid_f = w->valid();
+ bool done = w->done_exit();
+ bool waiting = w->waiting();
+ bool blocked = w->blocked();
+ bool prec = w->pending_reconvergence();
+ bool virt = w->virtualized();
+ bool ib_empty = w->ibuffer_empty();
+ // Skip warps with nothing interesting (done or fully empty + no
+ // scoreboard activity). The stuck warp will have ib_empty=false OR
+ // active scoreboard regs — keep those prominent.
+ if (done && ib_empty) continue;
+ fprintf(fout,
+ "[DEADLOCK_DUMP] wid=%u valid=%d done_exit=%d waiting=%d "
+ "blocked=%d pending_rec=%d virt=%d ibuf_empty=%d active_split=%u\n",
+ wid, (int)valid_f, (int)done, (int)waiting, (int)blocked,
+ (int)prec, (int)virt, (int)ib_empty,
+ (m_simt_tables && m_simt_tables[wid])
+ ? m_simt_tables[wid]->get_active_split_id()
+ : 0);
+ // Why is waiting() true? Show each branch's contribution.
+ if (waiting) {
+ bool fdone = w->functional_done();
+ bool wb = warp_waiting_at_barrier(wid);
+ bool wmb = warp_waiting_at_mem_barrier(wid);
+ unsigned natomic = w->get_n_atomic();
+ fprintf(fout,
+ "[DEADLOCK_DUMP] waiting_reason: functional_done=%d "
+ "barrier=%d mem_barrier=%d n_atomic=%u\n",
+ (int)fdone, (int)wb, (int)wmb, natomic);
+ }
+ // ibuffer slots 0..3 (IBUFFER_SIZE=4, hardcoded since the constant is
+ // private to shd_warp_t)
+ for (unsigned slot = 0; slot < 4; slot++) {
+ if (!w->ibuffer_slot_valid(slot)) {
+ fprintf(fout, "[DEADLOCK_DUMP] ibuffer[%u]: <empty>\n", slot);
+ continue;
+ }
+ const warp_inst_t *pI = w->ibuffer_slot_inst(slot);
+ unsigned split_id = w->ibuffer_slot_split_id(slot);
+ const active_mask_t &mask = w->ibuffer_slot_split_mask(slot);
+ fprintf(fout,
+ "[DEADLOCK_DUMP] ibuffer[%u]: pc=0x%lx op=%d "
+ "split_id=%d mask_count=%u\n",
+ slot, pI ? (unsigned long)pI->pc : 0ul,
+ pI ? (int)pI->op : -1, (int)split_id,
+ (unsigned)mask.count());
+ }
+ // simt_tables summary — use safe accessors only (full print() can
+ // segfault on corrupted state, which is likely with a stuck warp).
+ if (m_simt_tables && m_simt_tables[wid]) {
+ simt_tables *st = m_simt_tables[wid];
+ unsigned active_pc = 0, active_rpc = 0;
+ st->get_pdom_active_split_info(&active_pc, &active_rpc);
+ fprintf(fout,
+ "[DEADLOCK_DUMP] simt: active_split_id=%u active_pc=0x%lx "
+ "active_rpc=0x%lx ST_size=%u RT_size=%u blocked=%d "
+ "pending_recvg=%d virt=%d valid=%d\n",
+ st->get_active_split_id(),
+ (unsigned long)active_pc, (unsigned long)active_rpc,
+ st->getSTsize(), st->getRTsize(),
+ (int)st->blocked(), (int)st->is_pending_reconvergence(),
+ (int)st->is_virtualized(), (int)st->valid());
+ }
+ // scoreboard
+ if (m_scoreboard) m_scoreboard->dump_warp_state(fout, wid);
+ }
+ fflush(fout);
+}
+
float simt_core_cluster::get_current_occupancy(
unsigned long long &active, unsigned long long &total) const {
float aggregate = 0.f;
@@ -7569,7 +7667,23 @@ void simt_core_cluster::get_L1T_sub_stats(struct cache_sub_stats &css) const {
void exec_shader_core_ctx::checkExecutionStatusAndUpdate(warp_inst_t &inst,
unsigned t,
unsigned tid) {
- if (inst.isatomic()) m_warp[inst.warp_id()]->inc_n_atomic();
+ if (inst.isatomic()) {
+ static const bool dbg =
+ (getenv("MEMCO_DBG_DEADLOCK") != NULL);
+ unsigned wid = inst.warp_id();
+ if (dbg) {
+ fprintf(stdout,
+ "[ATOMIC_INC] sid=%u wid=%u pc=0x%lx tid=%u prev=%u new=%u "
+ "dbg_path=%u space=%d\n",
+ m_sid, wid, (unsigned long)inst.pc, tid,
+ m_warp[wid]->get_n_atomic(),
+ m_warp[wid]->get_n_atomic() + 1,
+ inst.get_dbg_path(),
+ (int)inst.space.get_type());
+ fflush(stdout);
+ }
+ m_warp[wid]->inc_n_atomic();
+ }
if (inst.space.is_local() && (inst.is_load() || inst.is_store())) {
new_addr_type localaddrs[MAX_ACCESSES_PER_INSN_PER_THREAD];
unsigned num_addrs;