diff options
Diffstat (limited to 'src/gpgpu-sim/shader.cc')
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 116 |
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; |
