diff options
Diffstat (limited to 'src/abstract_hardware_model.cc')
| -rw-r--r-- | src/abstract_hardware_model.cc | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc index 68efd4d..efe0e36 100644 --- a/src/abstract_hardware_model.cc +++ b/src/abstract_hardware_model.cc @@ -43,6 +43,109 @@ #include "gpgpusim_entrypoint.h" #include "option_parser.h" +// Forward declarations needed by compute_unified_shared_cycles below. +new_addr_type line_size_based_tag_func(new_addr_type address, + new_addr_type line_size); + +// MEMCO v3 Model B diagnostic globals: count how often the unified shared +// bank-conflict computation fired and the cumulative delta vs the per-set +// max model. Printed at gpgpu_sim termination. +unsigned long long g_memcov3_shared_unified_invocations = 0; +unsigned long long g_memcov3_shared_unified_cycles_unified = 0; +unsigned long long g_memcov3_shared_unified_cycles_perset_max = 0; + +void warp_inst_t::compute_unified_shared_cycles() { + static const bool enabled = (getenv("MEMCOV3_SHARED_UNIFIED") != NULL); + if (!enabled) return; + if (empty()) return; + if (op != LOAD_OP && op != STORE_OP) return; + if (!m_per_scalar_thread_valid) return; + + // Determine whether any shared work is present in this composite. + bool primary_shared = (space.get_type() == shared_space || + space.get_type() == sstarr_space); + bool any_shared_set = false; + for (unsigned s = 0; s < m_simd_sets.size(); s++) { + if (!m_simd_sets[s].valid || m_simd_sets[s].source_inst == NULL) continue; + enum _memory_space_t sp = m_simd_sets[s].source_inst->space.get_type(); + if (sp == shared_space || sp == sstarr_space) { + any_shared_set = true; + break; + } + } + if (!primary_shared && !any_shared_set) return; + + // Build a unified bank → word → count map across all participating + // active lanes (primary + shared-source coissuer sets). No subwarp + // subdivision: Model B assumes a single bank arbiter sees all lanes + // concurrently. Bank conflicts are counted across the union. + std::map<unsigned, std::map<new_addr_type, unsigned> > bank_accs; + + if (primary_shared) { + for (unsigned t = 0; t < m_config->warp_size; t++) { + if (!active(t)) continue; + new_addr_type addr = m_per_scalar_thread[t].memreqaddr[0]; + unsigned bank = m_config->shmem_bank_func(addr); + new_addr_type word = line_size_based_tag_func(addr, m_config->WORD_SIZE); + bank_accs[bank][word]++; + } + } + for (unsigned s = 0; s < m_simd_sets.size(); s++) { + const simd_set_info &si = m_simd_sets[s]; + if (!si.valid || si.source_inst == NULL) continue; + enum _memory_space_t sp = si.source_inst->space.get_type(); + if (sp != shared_space && sp != sstarr_space) continue; + if (si.per_thread_addrs.empty()) continue; + for (unsigned lane = 0; lane < si.per_thread_addrs.size(); lane++) { + if (!si.set_active_mask.test(lane)) continue; + new_addr_type addr = si.per_thread_addrs[lane].memreqaddr[0]; + unsigned bank = m_config->shmem_bank_func(addr); + new_addr_type word = line_size_based_tag_func(addr, m_config->WORD_SIZE); + bank_accs[bank][word]++; + } + } + + // Find the bank with the most distinct words — that's the unified + // bank-conflict cycle count for this composite. + unsigned unified_cycles = 0; + for (std::map<unsigned, std::map<new_addr_type, unsigned> >::iterator b = + bank_accs.begin(); + b != bank_accs.end(); ++b) { + if (b->second.size() > unified_cycles) unified_cycles = b->second.size(); + } + if (unified_cycles == 0) return; // no active lanes after all + + // Compute the per-set-max model's value for diagnostic comparison. + unsigned perset_max = 0; + if (primary_shared && cycles > perset_max) perset_max = cycles; + for (unsigned s = 0; s < m_simd_sets.size(); s++) { + const simd_set_info &si = m_simd_sets[s]; + if (!si.valid || si.source_inst == NULL) continue; + enum _memory_space_t sp = si.source_inst->space.get_type(); + if (sp != shared_space && sp != sstarr_space) continue; + if (si.cycles > perset_max) perset_max = si.cycles; + } + + g_memcov3_shared_unified_invocations++; + g_memcov3_shared_unified_cycles_unified += unified_cycles; + g_memcov3_shared_unified_cycles_perset_max += perset_max; + + set_unified_shared_cycles(unified_cycles); + + // Zero out the per-set + primary cycles so other paths (e.g. Stage 6 + // early-release in ldst_unit::cycle, which checks has_dispatch_delay + // per set) see "drained" — we'll consume the unified counter in + // shared_cycle instead. This avoids per-set cycles staying stuck + // nonzero (since shared_cycle no longer decrements them). + if (primary_shared) cycles = 0; + for (unsigned s = 0; s < m_simd_sets.size(); s++) { + simd_set_info &si = m_simd_sets[s]; + if (!si.valid || si.source_inst == NULL) continue; + enum _memory_space_t sp = si.source_inst->space.get_type(); + if (sp == shared_space || sp == sstarr_space) si.cycles = 0; + } +} + void mem_access_t::init(gpgpu_context *ctx) { gpgpu_ctx = ctx; m_uid = ++(gpgpu_ctx->sm_next_access_uid); |
