summaryrefslogtreecommitdiff
path: root/src/abstract_hardware_model.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/abstract_hardware_model.cc')
-rw-r--r--src/abstract_hardware_model.cc103
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);