summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/abstract_hardware_model.cc46
-rw-r--r--src/abstract_hardware_model.h6
-rw-r--r--src/gpgpu-sim/gpu-sim.cc17
-rw-r--r--src/gpgpu-sim/shader.cc136
-rw-r--r--src/gpgpu-sim/shader.h61
5 files changed, 223 insertions, 43 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc
index 9262a92..86427ad 100644
--- a/src/abstract_hardware_model.cc
+++ b/src/abstract_hardware_model.cc
@@ -129,6 +129,52 @@ void warp_inst_t::compute_simd_sets_compacted(unsigned num_sets,
}
}
+void warp_inst_t::compute_simd_sets_xor_static(unsigned num_sets,
+ unsigned set_width,
+ unsigned start_set) {
+ // start_set is unused for XOR-static: the lane permutation is fully
+ // determined by warp_id. Accepted for signature compatibility with
+ // compute_simd_sets_compacted.
+ (void)start_set;
+
+ m_simd_sets.resize(num_sets);
+ for (unsigned s = 0; s < num_sets; s++) {
+ simd_set_info &info = m_simd_sets[s];
+ info.set_id = s;
+ info.warp_id = m_warp_id;
+ info.set_active_mask.reset();
+ info.active_mask_in_warp.reset();
+ info.num_active_threads = 0;
+ }
+
+ // xor_key = reverse of the low log2(warp_size) bits of m_warp_id
+ unsigned warp_size = m_config->warp_size;
+ unsigned bits = 0;
+ while ((1u << bits) < warp_size) bits++;
+ unsigned xor_key = 0;
+ for (unsigned i = 0; i < bits; i++) {
+ if (m_warp_id & (1u << i)) xor_key |= (1u << (bits - 1 - i));
+ }
+
+ // Physical lane P runs logical thread T = P ^ xor_key.
+ for (unsigned P = 0; P < warp_size; P++) {
+ unsigned T = P ^ xor_key;
+ unsigned s = P / set_width;
+ unsigned lane = P % set_width;
+ simd_set_info &info = m_simd_sets[s];
+ info.thread_ids[lane] = T;
+ if (m_warp_active_mask.test(T)) {
+ info.set_active_mask.set(lane);
+ info.active_mask_in_warp.set(T);
+ info.num_active_threads++;
+ }
+ }
+
+ for (unsigned s = 0; s < num_sets; s++) {
+ m_simd_sets[s].valid = (m_simd_sets[s].num_active_threads > 0);
+ }
+}
+
unsigned warp_inst_t::num_active_simd_sets() const {
unsigned count = 0;
for (unsigned i = 0; i < m_simd_sets.size(); i++) {
diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h
index 4a655b3..3f7eac3 100644
--- a/src/abstract_hardware_model.h
+++ b/src/abstract_hardware_model.h
@@ -1185,6 +1185,12 @@ class warp_inst_t : public inst_t {
void compute_simd_sets(unsigned num_sets, unsigned set_width);
void compute_simd_sets_compacted(unsigned num_sets, unsigned set_width,
unsigned start_set = 0);
+ // Fixed per-warp lane permutation: lane P -> thread (P XOR reverse_bits(warp_id)).
+ // Does NOT repack — only reshuffles lane assignment. start_set is accepted
+ // for API symmetry with compute_simd_sets_compacted but is ignored (XOR
+ // placement is fixed by warp_id).
+ void compute_simd_sets_xor_static(unsigned num_sets, unsigned set_width,
+ unsigned start_set = 0);
const std::vector<simd_set_info> &get_simd_sets() const {
return m_simd_sets;
}
diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc
index 7b186aa..dd3bba7 100644
--- a/src/gpgpu-sim/gpu-sim.cc
+++ b/src/gpgpu-sim/gpu-sim.cc
@@ -685,6 +685,23 @@ void shader_core_config::reg_options(class OptionParser *opp) {
opp, "-gpgpu_enable_compaction", OPT_BOOL, &gpgpu_enable_compaction,
"Enable thread compaction into fewer SIMD sets (default = disabled)",
"0");
+ option_parser_register(
+ opp, "-gpgpu_compaction_mode", OPT_UINT32, &gpgpu_compaction_mode,
+ "Compaction mode: 0=none, 1=xor-static, 2=full. "
+ "Supersedes -gpgpu_enable_compaction (kept as deprecated alias).",
+ "0");
+ option_parser_register(
+ opp, "-gpgpu_opndcoll_read_latency", OPT_UINT32,
+ &gpgpu_opndcoll_read_latency,
+ "Extra cycles from operand-read grant to operand arriving at "
+ "collector unit (default 0 = combinational, current behavior).",
+ "0");
+ option_parser_register(
+ opp, "-gpgpu_co_issue_priority", OPT_UINT32,
+ &gpgpu_co_issue_priority,
+ "Co-issue scheduler: 0=greedy (utilization-max), 1=intra-first, "
+ "2=inter-first, 3=fewest-lanes, 4=same-PC (default 0).",
+ "0");
for (unsigned j = 0; j < SPECIALIZED_UNIT_NUM; ++j) {
std::stringstream ss;
diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc
index bf6c9c0..ffbb0c6 100644
--- a/src/gpgpu-sim/shader.cc
+++ b/src/gpgpu-sim/shader.cc
@@ -1192,12 +1192,20 @@ warp_inst_t *shader_core_ctx::issue_warp(register_set &pipe_reg_set,
m_stats->shader_cycle_distro[2 + (*pipe_reg)->active_count()]++;
// Compute SIMD set assignments before functional execution
if (m_config->gpgpu_simd_partitioning) {
- if (m_config->gpgpu_enable_compaction)
- (*pipe_reg)->compute_simd_sets_compacted(
- m_config->gpgpu_num_simd_sets, m_config->simd_set_width, 0);
- else
- (*pipe_reg)->compute_simd_sets(m_config->gpgpu_num_simd_sets,
- m_config->simd_set_width);
+ switch (m_config->gpgpu_compaction_mode) {
+ case 1: // xor-static
+ (*pipe_reg)->compute_simd_sets_xor_static(
+ m_config->gpgpu_num_simd_sets, m_config->simd_set_width, 0);
+ break;
+ case 2: // full
+ (*pipe_reg)->compute_simd_sets_compacted(
+ m_config->gpgpu_num_simd_sets, m_config->simd_set_width, 0);
+ break;
+ default: // 0 = none
+ (*pipe_reg)->compute_simd_sets(m_config->gpgpu_num_simd_sets,
+ m_config->simd_set_width);
+ break;
+ }
}
func_exec_inst(**pipe_reg);
@@ -1317,12 +1325,22 @@ void shader_core_ctx::co_issue_warp(warp_inst_t *composite,
m_warp[warp_id]->get_streamID());
// Compute SIMD sets for the co-issued instruction
- if (m_config->gpgpu_enable_compaction)
- temp_inst.compute_simd_sets_compacted(m_config->gpgpu_num_simd_sets,
- m_config->simd_set_width, start_set);
- else
- temp_inst.compute_simd_sets(m_config->gpgpu_num_simd_sets,
- m_config->simd_set_width);
+ switch (m_config->gpgpu_compaction_mode) {
+ case 1: // xor-static
+ temp_inst.compute_simd_sets_xor_static(m_config->gpgpu_num_simd_sets,
+ m_config->simd_set_width,
+ start_set);
+ break;
+ case 2: // full
+ temp_inst.compute_simd_sets_compacted(m_config->gpgpu_num_simd_sets,
+ m_config->simd_set_width,
+ start_set);
+ break;
+ default: // 0 = none
+ temp_inst.compute_simd_sets(m_config->gpgpu_num_simd_sets,
+ m_config->simd_set_width);
+ break;
+ }
// Functional execution for the co-issued warp's threads
func_exec_inst(temp_inst);
@@ -1951,18 +1969,27 @@ void scheduler_unit::cycle() {
unsigned cand_sets_needed;
bool can_co_issue;
- if (m_shader->m_config->gpgpu_enable_compaction) {
- // With compaction: just count sets needed, no overlap check
+ if (m_shader->m_config->gpgpu_compaction_mode == 2) {
+ // Full compaction: just count sets needed, no overlap check.
+ // Compacted placement uses start_set, so no two sets ever alias.
unsigned cand_active = cand_mask.count();
cand_sets_needed = (cand_active + set_width - 1) / set_width;
can_co_issue = (cand_sets_needed <= available_sets);
} else {
- // Without compaction: build temp sets and check overlap
+ // No compaction or XOR-static: build temp sets with the selected
+ // mapping and check set-level overlap vs. primary.
warp_inst_t cand_temp(m_shader->m_config);
cand_temp = *cand_inst;
cand_temp.issue(cand_mask, cand_warp_id, 0, 0, 0, 0);
- cand_temp.compute_simd_sets(m_shader->m_config->gpgpu_num_simd_sets,
- m_shader->m_config->simd_set_width);
+ if (m_shader->m_config->gpgpu_compaction_mode == 1) {
+ cand_temp.compute_simd_sets_xor_static(
+ m_shader->m_config->gpgpu_num_simd_sets,
+ m_shader->m_config->simd_set_width);
+ } else {
+ cand_temp.compute_simd_sets(
+ m_shader->m_config->gpgpu_num_simd_sets,
+ m_shader->m_config->simd_set_width);
+ }
can_co_issue =
!warp_inst_t::simd_sets_overlap(
co_issue_composite->get_simd_sets(),
@@ -5152,6 +5179,39 @@ void opndcoll_rfu_t::allocate_cu(unsigned port_num) {
}
}
+void opndcoll_rfu_t::deliver_operand(op_t &op) {
+ unsigned cu = op.get_oc_id();
+ unsigned operand = op.get_operand();
+ m_cu[cu]->collect_operand(operand);
+ if (m_shader->get_config()->gpgpu_clock_gated_reg_file) {
+ unsigned active_count = 0;
+ for (unsigned i = 0; i < m_shader->get_config()->warp_size;
+ i = i + m_shader->get_config()->n_regfile_gating_group) {
+ for (unsigned j = 0;
+ j < m_shader->get_config()->n_regfile_gating_group; j++) {
+ if (op.get_active_mask().test(i + j)) {
+ active_count += m_shader->get_config()->n_regfile_gating_group;
+ break;
+ }
+ }
+ }
+ m_shader->incregfile_reads(active_count);
+ } else {
+ m_shader->incregfile_reads(
+ m_shader->get_config()->warp_size); // op.get_active_count();
+ }
+}
+
+void opndcoll_rfu_t::drain_pending_operands() {
+ unsigned long long now = m_shader->get_gpu()->gpu_sim_cycle +
+ m_shader->get_gpu()->gpu_tot_sim_cycle;
+ while (!m_pending_operands.empty() &&
+ m_pending_operands.front().cycle_ready <= now) {
+ deliver_operand(m_pending_operands.front().op);
+ m_pending_operands.pop_front();
+ }
+}
+
void opndcoll_rfu_t::allocate_reads() {
// process read requests that do not have conflicts
std::list<op_t> allocated = m_arbiter.allocate_reads();
@@ -5166,28 +5226,26 @@ void opndcoll_rfu_t::allocate_reads() {
m_arbiter.allocate_for_read(bank, rr);
read_ops[bank] = rr;
}
- std::map<unsigned, op_t>::iterator r;
- for (r = read_ops.begin(); r != read_ops.end(); ++r) {
- op_t &op = r->second;
- unsigned cu = op.get_oc_id();
- unsigned operand = op.get_operand();
- m_cu[cu]->collect_operand(operand);
- if (m_shader->get_config()->gpgpu_clock_gated_reg_file) {
- unsigned active_count = 0;
- for (unsigned i = 0; i < m_shader->get_config()->warp_size;
- i = i + m_shader->get_config()->n_regfile_gating_group) {
- for (unsigned j = 0; j < m_shader->get_config()->n_regfile_gating_group;
- j++) {
- if (op.get_active_mask().test(i + j)) {
- active_count += m_shader->get_config()->n_regfile_gating_group;
- break;
- }
- }
- }
- m_shader->incregfile_reads(active_count);
- } else {
- m_shader->incregfile_reads(
- m_shader->get_config()->warp_size); // op.get_active_count());
+
+ const unsigned latency =
+ m_shader->get_config()->gpgpu_opndcoll_read_latency;
+ if (latency == 0) {
+ // Current behavior: deliver immediately, no queue. Bit-identical
+ // to the pre-Change-3 tip.
+ for (std::map<unsigned, op_t>::iterator r = read_ops.begin();
+ r != read_ops.end(); ++r) {
+ deliver_operand(r->second);
+ }
+ } else {
+ // Enqueue; drain will deliver on `now + latency` or later.
+ unsigned long long now = m_shader->get_gpu()->gpu_sim_cycle +
+ m_shader->get_gpu()->gpu_tot_sim_cycle;
+ for (std::map<unsigned, op_t>::iterator r = read_ops.begin();
+ r != read_ops.end(); ++r) {
+ pending_operand_t pend;
+ pend.op = r->second;
+ pend.cycle_ready = now + latency;
+ m_pending_operands.push_back(pend);
}
}
}
diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h
index d8103ac..3d1aea9 100644
--- a/src/gpgpu-sim/shader.h
+++ b/src/gpgpu-sim/shader.h
@@ -751,6 +751,7 @@ class opndcoll_rfu_t { // operand collector based register file unit
void step() {
dispatch_ready_cu();
+ drain_pending_operands();
allocate_reads();
for (unsigned p = 0; p < m_in_ports.size(); p++) allocate_cu(p);
process_banks();
@@ -771,13 +772,22 @@ class opndcoll_rfu_t { // operand collector based register file unit
private:
void process_banks() { m_arbiter.reset_alloction(); }
+ // types (forward-declared so member function signatures below can
+ // reference nested types defined later in this class body)
+ class op_t;
+ class collector_unit_t;
+
void dispatch_ready_cu();
void allocate_cu(unsigned port);
void allocate_reads();
-
- // types
-
- class collector_unit_t;
+ // Deliver one allocated operand to its collector unit and bump the
+ // regfile-read stat. Shared by allocate_reads (latency=0 fast path)
+ // and drain_pending_operands (latency>0).
+ void deliver_operand(op_t &op);
+ // Drain any pending-operand queue entries whose cycle_ready has
+ // elapsed; called from step() between dispatch_ready_cu and
+ // allocate_reads so delivered operands dispatch on the *next* cycle.
+ void drain_pending_operands();
class op_t {
public:
@@ -1183,6 +1193,15 @@ class opndcoll_rfu_t { // operand collector based register file unit
// port_to_du_t m_dispatch_units;
// std::map<warp_inst_t**,std::list<collector_unit_t*> > m_free_cu;
shader_core_ctx *m_shader;
+
+ // Delay queue for modeling operand-collector read pipelining when
+ // `-gpgpu_opndcoll_read_latency > 0`. allocate_reads() pushes here;
+ // drain_pending_operands() pops at the top of step().
+ struct pending_operand_t {
+ op_t op;
+ unsigned long long cycle_ready;
+ };
+ std::deque<pending_operand_t> m_pending_operands;
};
class barrier_set_t {
@@ -1716,6 +1735,37 @@ class shader_core_config : public core_config {
simd_set_width = warp_size;
}
+ // --- Compaction-mode back-compat shim (Change 1) ---
+ // Old flag -gpgpu_enable_compaction maps to mode=2 (full).
+ // New flag -gpgpu_compaction_mode=2 re-asserts the old bool so
+ // the three existing call sites that still read the old flag
+ // continue to work unchanged. Change 2 will migrate the call
+ // sites to read gpgpu_compaction_mode directly.
+ if (gpgpu_compaction_mode > 2) {
+ fprintf(stderr,
+ "GPGPU-Sim: invalid -gpgpu_compaction_mode %u; must be "
+ "0, 1, or 2\n",
+ gpgpu_compaction_mode);
+ abort();
+ }
+ if (gpgpu_co_issue_priority > 4) {
+ fprintf(stderr,
+ "GPGPU-Sim: invalid -gpgpu_co_issue_priority %u; must be "
+ "in [0,4]\n",
+ gpgpu_co_issue_priority);
+ abort();
+ }
+ if (gpgpu_enable_compaction && gpgpu_compaction_mode == 0) {
+ gpgpu_compaction_mode = 2;
+ }
+ if (gpgpu_compaction_mode == 2) {
+ gpgpu_enable_compaction = true;
+ }
+ // Mode 1 (xor-static) has no existing-call-site equivalent yet;
+ // Change 2 wires it up. Until then, selecting mode=1 produces
+ // identity SIMD-set layout (compute_simd_sets) because
+ // gpgpu_enable_compaction is left as whatever the user set.
+
set_pipeline_latency();
m_L1I_config.init(m_L1I_config.m_config_string, FuncCachePreferNone);
@@ -1863,6 +1913,9 @@ class shader_core_config : public core_config {
unsigned gpgpu_num_simd_sets;
unsigned simd_set_width; // derived: warp_size / num_simd_sets
bool gpgpu_enable_compaction;
+ unsigned gpgpu_compaction_mode; // 0=none, 1=xor-static, 2=full
+ unsigned gpgpu_opndcoll_read_latency; // extra cycles to collector
+ unsigned gpgpu_co_issue_priority; // 0=greedy..4=same-PC
unsigned n_simt_cores_per_cluster;
unsigned n_simt_clusters;