diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/abstract_hardware_model.cc | 52 | ||||
| -rw-r--r-- | src/abstract_hardware_model.h | 17 | ||||
| -rw-r--r-- | src/cuda-sim/cuda-sim.cc | 17 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 139 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 3 |
5 files changed, 224 insertions, 4 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc index f8746e6..72639d4 100644 --- a/src/abstract_hardware_model.cc +++ b/src/abstract_hardware_model.cc @@ -1636,6 +1636,18 @@ void simt_splits_table::update_pc_for_split(unsigned split_id, address_type new_pc) { assert(m_splits_table.find(split_id) != m_splits_table.end()); assert(m_splits_table[split_id].m_valid); + static const bool dbg_pc_enabled = (getenv("MEMCO_DBG_PC") != NULL); + if (dbg_pc_enabled && m_warp_id == 0) { + fprintf(stderr, + "[SPLIT_PC_UPDATE] cycle=%llu warp=%u split_id=%u " + "old_pc=0x%lx new_pc=0x%lx\n", + (unsigned long long)(GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle), + m_warp_id, split_id, + (unsigned long)m_splits_table[split_id].m_pc, + (unsigned long)new_pc); + fflush(stderr); + } m_splits_table[split_id].m_pc = new_pc; } @@ -1886,6 +1898,15 @@ unsigned simt_splits_table::insert_new_entry(simt_splits_table_entry entry, assert(entry_num != (unsigned)-1); m_fifo_queue.push_back( fifo_entry(entry_num, gpgpusim_total_cycles, m_fifo_queue.size())); + static const bool dbg_pc_enabled = (getenv("MEMCO_DBG_PC") != NULL); + if (dbg_pc_enabled && m_warp_id == 0) { + fprintf(stderr, + "[SPLIT_INSERT-A] cycle=%llu warp=%u split_id=%u pc=0x%lx mask=%s\n", + gpgpusim_total_cycles, m_warp_id, entry_num, + (unsigned long)entry.m_pc, + entry.m_active_mask.to_string().c_str()); + fflush(stderr); + } return entry_num; } @@ -1934,6 +1955,14 @@ unsigned simt_splits_table::insert_new_entry( assert(entry != (unsigned)-1); m_fifo_queue.push_back( fifo_entry(entry, gpgpusim_total_cycles, m_fifo_queue.size())); + static const bool dbg_pc_enabled = (getenv("MEMCO_DBG_PC") != NULL); + if (dbg_pc_enabled && m_warp_id == 0) { + fprintf(stderr, + "[SPLIT_INSERT] cycle=%llu warp=%u split_id=%u pc=0x%lx mask=%s\n", + gpgpusim_total_cycles, m_warp_id, entry, + (unsigned long)pc, tmp_active_mask.to_string().c_str()); + fflush(stderr); + } return entry; } @@ -1983,6 +2012,14 @@ unsigned simt_splits_table::insert_new_entry( // call_ret=true: push to front for LIFO ordering m_fifo_queue.push_front( fifo_entry(entry, gpgpusim_total_cycles, m_fifo_queue.size())); + static const bool dbg_pc_enabled = (getenv("MEMCO_DBG_PC") != NULL); + if (dbg_pc_enabled && m_warp_id == 0) { + fprintf(stderr, + "[SPLIT_INSERT-C] cycle=%llu warp=%u split_id=%u pc=0x%lx mask=%s\n", + gpgpusim_total_cycles, m_warp_id, entry, + (unsigned long)pc, tmp_active_mask.to_string().c_str()); + fflush(stderr); + } return entry; } @@ -2691,6 +2728,21 @@ void simt_tables::update(simt_mask_t &thread_done, addr_vector_t &next_pc, address_type top_recvg_pc = m_simt_splits_table->get_rpc(); unsigned top_recvg_entry = m_simt_splits_table->get_rpc_entry(); address_type top_pc = m_simt_splits_table->get_pc(); + if (top_pc != next_inst_pc) { + static const bool dbg_pc_enabled = (getenv("MEMCO_DBG_PC") != NULL); + if (dbg_pc_enabled) { + fprintf(stderr, + "[SIMT_UPDATE_MISMATCH] cycle=%llu warp=%u top_pc=0x%lx " + "next_inst_pc=0x%lx top_mask=%s active_split=%u\n", + (unsigned long long)(GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle), + m_warp_id, (unsigned long)top_pc, + (unsigned long)next_inst_pc, + top_active_mask.to_string().c_str(), + m_simt_splits_table->get_active_split_id()); + fflush(stderr); + } + } assert(top_pc == next_inst_pc); assert(top_active_mask.any()); diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h index 369459b..6ce1871 100644 --- a/src/abstract_hardware_model.h +++ b/src/abstract_hardware_model.h @@ -1508,6 +1508,18 @@ class warp_inst_t : public inst_t { unsigned get_schd_id() const { return m_scheduler_id; } active_mask_t get_warp_active_mask() const { return m_warp_active_mask; } + // Debug-only path tag for the pc==inst.pc assertion investigation. + // 0 = primary issue + // 1 = co-issue intra (same warp, sibling split) + // 2 = co-issue inter (different warp) + // 3 = co-issue MEM (mem-coissue path) + unsigned get_dbg_path() const { return m_dbg_path; } + void set_dbg_path(unsigned p) { m_dbg_path = p; } + int get_dbg_split_id() const { return m_dbg_split_id; } + void set_dbg_split_id(int s) { m_dbg_split_id = s; } + const void *get_dbg_source_inst() const { return m_dbg_source_inst; } + void set_dbg_source_inst(const void *p) { m_dbg_source_inst = p; } + protected: unsigned m_uid; unsigned long long m_streamID; @@ -1550,6 +1562,11 @@ class warp_inst_t : public inst_t { // SIMD lane partitioning data std::vector<simd_set_info> m_simd_sets; + // Debug-only fields for pc==inst.pc assertion investigation + unsigned m_dbg_path = 0; + int m_dbg_split_id = -1; + const void *m_dbg_source_inst = NULL; + // Jin: cdp support public: int m_is_cdp; diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc index 14ae504..fb72f25 100644 --- a/src/cuda-sim/cuda-sim.cc +++ b/src/cuda-sim/cuda-sim.cc @@ -1794,6 +1794,23 @@ void ptx_thread_info::ptx_exec_inst(warp_inst_t &inst, unsigned lane_id) { bool skip = false; int op_classification = 0; addr_t pc = next_instr(); + if (pc != inst.pc) { + static unsigned dump_count = 0; + if (dump_count < 32) { + dump_count++; + fprintf(stderr, + "[PC_ASSERT_DBG #%u] cycle=%llu warp_id=%u lane=%u hw_tid=%u " + "hw_wid=%u thread_pc=0x%lx inst_pc=0x%lx inst_op=%d " + "active_count=%u dbg_path=%u split_id=%d source_inst=%p\n", + dump_count, + (unsigned long long)(m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle), + inst.warp_id(), lane_id, get_hw_tid(), get_hw_wid(), + (unsigned long)pc, (unsigned long)inst.pc, (int)inst.op, + inst.active_count(), inst.get_dbg_path(), + inst.get_dbg_split_id(), inst.get_dbg_source_inst()); + } + fflush(stderr); + } assert(pc == inst.pc); // make sure timing model and functional model are in sync const ptx_instruction *pI = m_func_info->get_instruction(pc); diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index a113ddb..9a1658d 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -1219,6 +1219,17 @@ void shader_core_ctx::fetch() { sec_pc, nbytes, warp_id, 1, sec_split_id, sec_mask); // Assign I-Buffer half 1 to this split m_warp[warp_id]->ibuffer_assign_half(1, sec_split_id, sec_mask); + static const bool dbg_pc_enabled_sec = (getenv("MEMCO_DBG_PC") != NULL); + if (dbg_pc_enabled_sec && warp_id == 0) { + fprintf(stderr, + "[SEC_FETCH_DBG] cycle=%llu warp=%u sec_split_id=%u " + "sec_pc=0x%lx sec_mask=%s\n", + (unsigned long long)(m_gpu->gpu_sim_cycle + + m_gpu->gpu_tot_sim_cycle), + warp_id, sec_split_id, (unsigned long)sec_pc, + sec_mask.to_string().c_str()); + fflush(stderr); + } delete mf; break; // one secondary fetch per cycle } else { @@ -1282,6 +1293,21 @@ warp_inst_t *shader_core_ctx::issue_warp(register_set &pipe_reg_set, active_mask, warp_id, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, m_warp[warp_id]->get_dynamic_warp_id(), sch_id, m_warp[warp_id]->get_streamID()); // dynamic instruction information + (*pipe_reg)->set_dbg_path(0); + (*pipe_reg)->set_dbg_split_id(-1); + (*pipe_reg)->set_dbg_source_inst(next_inst); + static const bool dbg_pc_enabled_pri = (getenv("MEMCO_DBG_PC") != NULL); + if (dbg_pc_enabled_pri && warp_id == 0 && + m_config->model == AWARE_RECONVERGENCE) { + unsigned active_split_id = m_simt_tables[warp_id]->get_active_split_id(); + fprintf(stderr, + "[PRI_ISSUE_DBG] cycle=%llu warp=%u front_split_id=%u " + "inst_pc=0x%lx active_mask=%s\n", + (unsigned long long)(m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle), + warp_id, active_split_id, (unsigned long)next_inst->pc, + active_mask.to_string().c_str()); + fflush(stderr); + } m_stats->shader_cycle_distro[2 + (*pipe_reg)->active_count()]++; // Compute SIMD set assignments before functional execution if (m_config->gpgpu_simd_partitioning) { @@ -1416,6 +1442,55 @@ void shader_core_ctx::co_issue_warp(warp_inst_t *composite, m_gpu->gpu_tot_sim_cycle + m_gpu->gpu_sim_cycle, m_warp[warp_id]->get_dynamic_warp_id(), sch_id, m_warp[warp_id]->get_streamID()); + // Debug path tag: 1=intra (split_id != -1), 2=inter (split_id == -1). + // MEM-coissue (path=3) is set by caller after this if applicable; here + // we use intra/inter based on split_id which the caller passes. + temp_inst.set_dbg_path(split_id != (unsigned)-1 ? 1u : 2u); + temp_inst.set_dbg_split_id(split_id != (unsigned)-1 ? (int)split_id : -1); + temp_inst.set_dbg_source_inst(next_inst); + + // Debug: for intra co-issue, compare cached active_mask (from + // ibuffer slot) against current splits-table mask + warp's + // m_active_threads. Logs only when MEMCO_DBG_PC env var is set, + // and when the cached mask differs from the current split mask + // OR includes any thread no longer in m_active_threads. + static const bool dbg_pc_enabled = (getenv("MEMCO_DBG_PC") != NULL); + if (dbg_pc_enabled && m_config->model == AWARE_RECONVERGENCE && + split_id != (unsigned)-1) { + if (m_simt_tables[warp_id]->is_split_valid(split_id)) { + unsigned cur_pc; + simt_mask_t cur_mask; + m_simt_tables[warp_id]->get_split_info(split_id, &cur_pc, &cur_mask); + bool mask_drift = false; + for (unsigned t = 0; t < MAX_WARP_SIZE; t++) { + if (active_mask.test(t) != cur_mask.test(t)) mask_drift = true; + } + if (mask_drift || cur_pc != next_inst->pc) { + fprintf(stderr, + "[CO_ISSUE_DRIFT] cycle=%llu warp=%u INTRA split=%u " + "next_inst_pc=0x%lx cur_pc=0x%lx cached_mask=%s " + "cur_split_mask=%s drift=%d pc_drift=%d\n", + (unsigned long long)(m_gpu->gpu_sim_cycle + + m_gpu->gpu_tot_sim_cycle), + warp_id, split_id, (unsigned long)next_inst->pc, + (unsigned long)cur_pc, + active_mask.to_string().c_str(), + cur_mask.to_string().c_str(), + mask_drift ? 1 : 0, + (cur_pc != next_inst->pc) ? 1 : 0); + fflush(stderr); + } + } else { + fprintf(stderr, + "[CO_ISSUE_INVALID] cycle=%llu warp=%u INTRA split=%u " + "next_inst_pc=0x%lx cached_mask=%s\n", + (unsigned long long)(m_gpu->gpu_sim_cycle + + m_gpu->gpu_tot_sim_cycle), + warp_id, split_id, (unsigned long)next_inst->pc, + active_mask.to_string().c_str()); + fflush(stderr); + } + } // Compute SIMD sets for the co-issued instruction switch (m_config->gpgpu_compaction_mode) { @@ -2021,7 +2096,17 @@ void scheduler_unit::try_intra_warp_coissue( continue; } - unsigned sec_active = sec_mask.count(); + // Stale-mask guard: see commentary on the same fix in + // try_utilization_max_coissue. Cached `sec_mask` may diverge from + // current `split_mask` (lane re-bucketing or split-ID reuse). Dispatch + // only the intersection — lanes in BOTH masks are guaranteed to have + // their per-thread PC at sec_inst->pc. + active_mask_t sec_mask_eff; + for (unsigned t = 0; t < MAX_WARP_SIZE; t++) { + if (sec_mask.test(t) && split_mask.test(t)) sec_mask_eff.set(t); + } + if (!sec_mask_eff.any()) continue; + unsigned sec_active = sec_mask_eff.count(); unsigned sec_sets_needed = (sec_active + set_width - 1) / set_width; if (sec_sets_needed > available_sets) { m_stats->coissue_denied_by_no_sets[get_sid()]++; @@ -2037,7 +2122,7 @@ void scheduler_unit::try_intra_warp_coissue( get_sid(), m_id, primary_warp_id, sec_split_id, sec_sets_needed); } - m_shader->co_issue_warp(co_issue_composite, sec_inst, sec_mask, + m_shader->co_issue_warp(co_issue_composite, sec_inst, sec_mask_eff, primary_warp_id, m_id, next_free_set, sec_split_id); @@ -2189,6 +2274,33 @@ void scheduler_unit::try_utilization_max_coissue( m_shader->get_split_info(cand_warp_id, sec_split_id, &split_pc, &split_mask); if (split_pc != sec_inst->pc) continue; + + // At most one greedy-pool candidate per warp. Two reasons: + // (a) Dup with primary half: when the FIFO front split moves to + // match a split already cached in this warp's secondary half + // (slots 2/3), primary fetch refills slot 0 with the same + // (split_id, pc) that the secondary slot already holds. The + // inter scan above would have admitted slot 0; admitting the + // secondary slot here too double-issues the same warp/split/pc, + // advancing per-thread PCs twice and tripping + // `pc == inst.pc` in cuda-sim.cc:1797. + // (b) Order-of-operations within the pool: when multiple + // candidates target the same warp, the earlier one's + // co_issue_warp call mutates the warp's splits-table (move, + // update, possibly split-id reuse). The later candidate's + // cached split_id can refer to a different split by then. + // simt_tables::update on the second candidate then asserts + // `top_pc == next_inst_pc` because FRONT.pc has changed. + // Restricting to one candidate per warp keeps the scheduler from + // issuing two AWARE updates against the same warp in one cycle. + bool dup_with_warp = false; + for (unsigned k = 0; k < pool.size(); k++) { + if (pool[k].warp_id == cand_warp_id) { + dup_with_warp = true; + break; + } + } + if (dup_with_warp) continue; if (classify_fu_type(sec_inst) != co_issue_fu_type) { m_stats->coissue_denied_by_fu_mismatch[get_sid()]++; continue; @@ -2219,7 +2331,26 @@ void scheduler_unit::try_utilization_max_coissue( continue; } - unsigned sec_active = sec_mask.count(); + // Stale-mask guard: the cached `sec_mask` is from secondary-fetch + // time and may not match the current splits-table mask. Two + // failure modes: + // 1. AWARE re-bucketing moves lanes out of this split (mask + // shrinks) while keeping the split's PC stable. Cached lanes + // that left have advanced their per-thread PC; dispatching + // them at the cached PC trips cuda-sim.cc:1797. + // 2. Split-ID reuse: the original split was invalidated and the + // ID slot got recycled for a new split that happens to be at + // the same PC. The current mask is from the *new* split; the + // cached mask is stale. + // Both reduce to: trust only lanes present in BOTH masks. The + // ibuffer slot ownership invariant guarantees lanes in `split_mask` + // are at `split_pc == sec_inst->pc`. + active_mask_t sec_mask_eff; + for (unsigned t = 0; t < MAX_WARP_SIZE; t++) { + if (sec_mask.test(t) && split_mask.test(t)) sec_mask_eff.set(t); + } + if (!sec_mask_eff.any()) continue; + unsigned sec_active = sec_mask_eff.count(); unsigned sec_needed = (sec_active + set_width - 1) / set_width; if (sec_needed > available_sets) { m_stats->coissue_denied_by_no_sets[get_sid()]++; @@ -2231,7 +2362,7 @@ void scheduler_unit::try_utilization_max_coissue( c.warp_id = cand_warp_id; c.split_id = sec_split_id; c.inst = sec_inst; - c.mask = sec_mask; + c.mask = sec_mask_eff; c.sec_slot = sec_slot; c.active_count = sec_active; c.sets_needed = sec_needed; diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index ce0c8c4..f25ba0e 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -196,6 +196,9 @@ class shd_warp_t { n_completed++; } bool test_active(unsigned lane) { return m_active_threads.test(lane); } + const std::bitset<MAX_WARP_SIZE> &get_active_threads() const { + return m_active_threads; + } void set_last_fetch(unsigned long long sim_cycle) { m_last_fetch = sim_cycle; |
