summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/abstract_hardware_model.cc52
-rw-r--r--src/abstract_hardware_model.h17
-rw-r--r--src/cuda-sim/cuda-sim.cc17
-rw-r--r--src/gpgpu-sim/shader.cc139
-rw-r--r--src/gpgpu-sim/shader.h3
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;