diff options
| -rw-r--r-- | src/abstract_hardware_model.cc | 1429 | ||||
| -rw-r--r-- | src/abstract_hardware_model.h | 370 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.cc | 21 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 260 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 38 |
5 files changed, 2058 insertions, 60 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc index e8ddf95..dde9d28 100644 --- a/src/abstract_hardware_model.cc +++ b/src/abstract_hardware_model.cc @@ -1227,10 +1227,17 @@ void core_t::updateSIMTStack(unsigned warpId, warp_inst_t *inst) { //! Get the warp to be executed using the data taken form the SIMT stack warp_inst_t core_t::getExecuteWarp(unsigned warpId) { unsigned pc, rpc; - m_simt_stack[warpId]->get_pdom_stack_top_info(&pc, &rpc); - warp_inst_t wi = *(m_gpu->gpgpu_ctx->ptx_fetch_inst(pc)); - wi.set_active(m_simt_stack[warpId]->get_active_mask()); - return wi; + if (m_gpu->simd_model() == POST_DOMINATOR) { + m_simt_stack[warpId]->get_pdom_stack_top_info(&pc, &rpc); + warp_inst_t wi = *(m_gpu->gpgpu_ctx->ptx_fetch_inst(pc)); + wi.set_active(m_simt_stack[warpId]->get_active_mask()); + return wi; + } else { + m_simt_tables[warpId]->get_pdom_active_split_info(&pc, &rpc); + warp_inst_t wi = *(m_gpu->gpgpu_ctx->ptx_fetch_inst(pc)); + wi.set_active(m_simt_tables[warpId]->get_active_mask()); + return wi; + } } void core_t::deleteSIMTStack() { @@ -1251,5 +1258,1417 @@ void core_t::initilizeSIMTStack(unsigned warp_count, unsigned warp_size) { void core_t::get_pdom_stack_top_info(unsigned warpId, unsigned *pc, unsigned *rpc) const { - m_simt_stack[warpId]->get_pdom_stack_top_info(pc, rpc); + if (m_gpu->simd_model() == POST_DOMINATOR) { + m_simt_stack[warpId]->get_pdom_stack_top_info(pc, rpc); + } else { + m_simt_tables[warpId]->get_pdom_active_split_info(pc, rpc); + } +} + +// ── ITS (AWARE Reconvergence) implementations ─────────────────────────────── + +#define MAX_VIRTUAL_ST_ENTRIES 32 +#define MAX_VIRTUAL_RT_ENTRIES 32 + +// ── simt_splits_table ──────────────────────────────────────────────────────── + +simt_splits_table::simt_splits_table(unsigned wid, unsigned warpSize, + const shader_core_config *config, + const struct memory_config *mem_config, + simt_tables *simt_table) { + m_warp_id = wid; + m_warp_size = warpSize; + m_active_split = (unsigned)-1; + m_num_entries = 0; + m_num_physical_entries = 0; + m_num_transient_entries = 0; + m_max_st_size = config->num_st_entries; + m_warp_size = config->warp_size; + m_config = config; + m_mem_config = mem_config; + m_response_st_entry = -1; + m_spill_st_entry = warp_inst_t(config); + m_fill_st_entry = warp_inst_t(config); + m_spill_st_entry.clear(); + m_fill_st_entry.clear(); + m_simt_tables = simt_table; + m_pending_recvg_entry = simt_splits_table_entry(); + reset(); +} + +void simt_splits_table::reset() { + m_splits_table.clear(); + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + m_splits_table[i] = simt_splits_table_entry(); + while (!m_fifo_queue.empty()) m_fifo_queue.pop_front(); + while (!m_invalid_entries.empty()) m_invalid_entries.pop(); + for (int i = MAX_VIRTUAL_ST_ENTRIES - 1; i >= 0; i--) + m_invalid_entries.push(i); + for (int i = m_warp_size; i >= 0; i--) + m_available_v_id.push(i); +} + +void simt_splits_table::launch(address_type start_pc, + const simt_mask_t &active_mask) { + reset(); + assert(!m_splits_table[0].m_valid); + m_splits_table[0].m_pc = start_pc; + m_splits_table[0].m_calldepth = 1; + m_splits_table[0].m_active_mask = active_mask; + m_splits_table[0].m_type = SPLITS_TABLE_TYPE_CALL; + m_splits_table[0].m_valid = true; + assert(m_invalid_entries.top() == 0); + m_invalid_entries.pop(); + m_active_split = 0; + m_num_entries = 1; + m_num_physical_entries = 1; + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + m_fifo_queue.push_back( + fifo_entry(0, gpgpusim_total_cycles, m_fifo_queue.size())); +} + +const simt_mask_t &simt_splits_table::get_active_mask() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + assert(m_splits_table[m_active_split].m_active_mask.any()); + return m_splits_table[m_active_split].m_active_mask; +} + +const simt_mask_t &simt_splits_table::get_active_mask(unsigned num) { + assert(m_splits_table.find(num) != m_splits_table.end()); + return m_splits_table[num].m_active_mask; +} + +void simt_splits_table::get_pdom_splits_entry_info(unsigned num, unsigned *pc, + unsigned *rpc) { + assert((m_splits_table.find(num) != m_splits_table.end()) && + m_splits_table[0].m_valid); + *pc = m_splits_table[num].m_pc; + *rpc = m_splits_table[num].m_recvg_pc; +} + +void simt_splits_table::get_pdom_active_split_info(unsigned *pc, + unsigned *rpc) { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + *pc = m_splits_table[m_active_split].m_pc; + *rpc = m_splits_table[m_active_split].m_recvg_pc; +} + +unsigned simt_splits_table::get_rpc(unsigned num) { + assert(m_splits_table.find(num) != m_splits_table.end()); + return m_splits_table[num].m_recvg_pc; +} + +void simt_splits_table::set_shader(shader_core_ctx *shader) { + m_shader = shader; +} + +bool simt_splits_table::is_virtualized() { + return m_splits_table[m_active_split].m_virtual; +} + +unsigned simt_splits_table::address_to_entry(warp_inst_t inst) { + if (!inst.empty()) { + unsigned wid = inst.warp_id(); + address_type addr = inst.pc; + unsigned entry = (addr - BRU_VIR_START - + (wid * m_config->warp_size) * MAX_BRU_VIR_PER_SPLIT) / + (MAX_BRU_VIR_PER_SPLIT); + return entry; + } + return (unsigned)-1; +} + +bool simt_splits_table::blocked() { + return m_splits_table[m_active_split].m_blocked; +} + +bool simt_splits_table::push_to_st_response_fifo(unsigned entry) { + if (m_response_st_entry == -1) { + m_response_st_entry = entry; + return true; + } + return false; +} + +unsigned simt_splits_table::get_replacement_candidate() { + unsigned entry = (unsigned)-1; + for (unsigned i = m_fifo_queue.size() - 1; i >= 0; i--) { + fifo_entry replacement_candidate = m_fifo_queue[i]; + entry = replacement_candidate.m_st_entry; + if (!m_splits_table[entry].m_virtual) break; + } + assert(entry != (unsigned)-1); + return entry; +} + +bool simt_splits_table::spill_st_entry() { + if (!m_spill_st_entry.empty()) return false; + assert(m_spill_st_entry.empty()); + + unsigned entry_to_replace = get_replacement_candidate(); + assert(!m_splits_table[entry_to_replace].m_virtual); + m_splits_table[entry_to_replace].m_virtual = true; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + + address_type pc = + (m_warp_id * m_warp_size + entry_to_replace) * MAX_BRU_VIR_PER_SPLIT; + address_type ppc = pc + BRU_VIR_START; + unsigned nbytes = 12; + unsigned offset_in_block = + pc & (m_config->m_L1D_config.get_line_sz() - 1); + if ((offset_in_block + nbytes) > m_config->m_L1I_config.get_line_sz()) + nbytes = (m_config->m_L1D_config.get_line_sz() - offset_in_block); + + mem_access_t acc(BRU_ST_SPILL, ppc, nbytes, true, GPGPU_Context()); + m_spill_st_entry.space = memory_space_t(local_space); + m_spill_st_entry.cache_op = CACHE_WRITE_BACK; + m_spill_st_entry.op = STORE_OP; + m_spill_st_entry.mem_op = NOT_TEX; + m_spill_st_entry.memory_op = bru_st_spill_request; + m_spill_st_entry.pc = ppc; + m_spill_st_entry.occupy(); + m_spill_st_entry.set_warp_id(m_warp_id); + m_spill_st_entry.set_active(0); + m_spill_st_entry.inject_mem_acccesses(acc); + return true; +} + +bool simt_splits_table::fill_st_entry(unsigned entry) { + if (!m_fill_st_entry.empty()) return false; + + address_type pc = + (m_warp_id * m_warp_size + entry) * MAX_BRU_VIR_PER_SPLIT; + address_type ppc = pc + BRU_VIR_START; + unsigned nbytes = 12; + unsigned offset_in_block = + pc & (m_config->m_L1D_config.get_line_sz() - 1); + if ((offset_in_block + nbytes) > m_config->m_L1I_config.get_line_sz()) + nbytes = (m_config->m_L1D_config.get_line_sz() - offset_in_block); + + mem_access_t acc(BRU_ST_FILL, ppc, nbytes, false, GPGPU_Context()); + m_fill_st_entry.space = memory_space_t(local_space); + m_fill_st_entry.cache_op = CACHE_ALL; + m_fill_st_entry.op = LOAD_OP; + m_fill_st_entry.mem_op = NOT_TEX; + m_fill_st_entry.memory_op = bru_st_fill_request; + m_fill_st_entry.pc = ppc; + m_fill_st_entry.inject_mem_acccesses(acc); + m_fill_st_entry.occupy(); + m_fill_st_entry.set_warp_id(m_warp_id); + m_fill_st_entry.set_active(0); + m_splits_table[entry].m_transient = true; + m_num_transient_entries++; + return true; +} + +void simt_splits_table::cycle() { + if (!m_spill_st_entry.empty()) { + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; + mem_stage_access_type type; + bool done = m_shader->memory_cycle(m_spill_st_entry, rc_fail, type); + if (done) { + m_spill_st_entry.clear(); + m_spill_st_entry.clear_pending_mem_requests(); + } + } + + if (!m_fill_st_entry.empty()) { + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; + mem_stage_access_type type; + bool done = m_shader->memory_cycle(m_fill_st_entry, rc_fail, type); + if (done) { + m_fill_st_entry.clear(); + m_fill_st_entry.clear_pending_mem_requests(); + } + } + + if (m_response_st_entry != -1) { + if (m_num_physical_entries == m_max_st_size) { + bool spilled = spill_st_entry(); + if (spilled) { + assert(m_num_physical_entries < m_max_st_size); + m_splits_table[m_response_st_entry].m_virtual = false; + m_splits_table[m_response_st_entry].m_transient = false; + m_num_transient_entries--; + m_num_physical_entries++; + m_response_st_entry = -1; + } + } else { + assert(m_num_physical_entries < m_max_st_size); + m_splits_table[m_response_st_entry].m_virtual = false; + m_splits_table[m_response_st_entry].m_transient = false; + m_num_transient_entries--; + m_num_physical_entries++; + m_response_st_entry = -1; + } + } + + if (m_pending_recvg_entry.m_valid) { + unsigned entry = insert_new_entry(m_pending_recvg_entry); + if (entry != (unsigned)-1) m_pending_recvg_entry.m_valid = false; + } + + if (m_splits_table[m_active_split].m_blocked || + (!m_splits_table[m_active_split].m_valid && m_fifo_queue.size() > 0)) + push_back(); + + if (m_splits_table[m_active_split].m_virtual && + !m_splits_table[m_active_split].m_transient) + fill_st_entry(m_active_split); +} + +unsigned simt_splits_table::insert_new_entry(simt_splits_table_entry entry, + bool recvged) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + if (recvged) { + if (m_num_physical_entries == m_max_st_size) { + assert(!m_pending_recvg_entry.m_valid); + m_pending_recvg_entry = entry; + m_pending_recvg_entry.m_valid = true; + m_pending_recvg_entry.m_virtual = false; + m_pending_recvg_entry.m_branch_div_cycle = gpgpusim_total_cycles; + return (unsigned)-1; + } + } else { + if (m_num_physical_entries == m_max_st_size) { + bool spilled = spill_st_entry(); + if (!spilled) return (unsigned)-1; + } + } + assert(m_num_physical_entries < m_max_st_size); + unsigned entry_num = m_invalid_entries.top(); + m_invalid_entries.pop(); + assert(!m_splits_table[entry_num].m_valid); + + AWARE_DPRINTF("Inserting new entry to Splits Table: Entry %d\tPC %d\tRPC %d\n", + entry_num, entry.m_pc, entry.m_recvg_pc); + + m_splits_table[entry_num].m_pc = entry.m_pc; + m_splits_table[entry_num].m_recvg_pc = entry.m_recvg_pc; + m_splits_table[entry_num].m_recvg_entry = entry.m_recvg_entry; + m_splits_table[entry_num].m_active_mask = entry.m_active_mask; + m_splits_table[entry_num].m_valid = true; + m_splits_table[entry_num].m_virtual = false; + m_splits_table[entry_num].m_type = entry.m_type; + m_splits_table[entry_num].m_branch_div_cycle = entry.m_branch_div_cycle; + m_num_entries++; + m_num_physical_entries++; + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); + assert(entry_num != (unsigned)-1); + m_fifo_queue.push_back( + fifo_entry(entry_num, gpgpusim_total_cycles, m_fifo_queue.size())); + return entry_num; +} + +unsigned simt_splits_table::insert_new_entry( + address_type pc, address_type rpc, unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, splits_table_entry_type type, + bool recvged) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + if (recvged) { + if (m_num_physical_entries == m_max_st_size) { + assert(!m_pending_recvg_entry.m_valid); + m_pending_recvg_entry.m_valid = true; + m_pending_recvg_entry.m_pc = pc; + m_pending_recvg_entry.m_recvg_pc = rpc; + m_pending_recvg_entry.m_recvg_entry = rpc_entry; + m_pending_recvg_entry.m_active_mask = tmp_active_mask; + m_pending_recvg_entry.m_virtual = false; + m_pending_recvg_entry.m_type = type; + m_pending_recvg_entry.m_branch_div_cycle = gpgpusim_total_cycles; + return (unsigned)-1; + } + } else { + if (m_num_physical_entries == m_max_st_size) { + bool spilled = spill_st_entry(); + if (!spilled) return (unsigned)-1; + } + } + unsigned entry = m_invalid_entries.top(); + m_invalid_entries.pop(); + assert(!m_splits_table[entry].m_valid); + + AWARE_DPRINTF("Inserting new entry to Splits Table: Entry %d\tPC %d\tRPC %d\n", + entry, pc, rpc); + + m_splits_table[entry].m_pc = pc; + m_splits_table[entry].m_recvg_pc = rpc; + m_splits_table[entry].m_recvg_entry = rpc_entry; + m_splits_table[entry].m_active_mask = tmp_active_mask; + m_splits_table[entry].m_valid = true; + m_splits_table[entry].m_type = type; + m_num_entries++; + m_num_physical_entries++; + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); + assert(entry != (unsigned)-1); + m_fifo_queue.push_back( + fifo_entry(entry, gpgpusim_total_cycles, m_fifo_queue.size())); + return entry; +} + +unsigned simt_splits_table::insert_new_entry( + address_type pc, address_type rpc, unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, splits_table_entry_type type, + bool call_ret, bool recvged) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + if (recvged) { + if (m_num_physical_entries == m_max_st_size) { + assert(!m_pending_recvg_entry.m_valid); + m_pending_recvg_entry.m_valid = true; + m_pending_recvg_entry.m_pc = pc; + m_pending_recvg_entry.m_recvg_pc = rpc; + m_pending_recvg_entry.m_recvg_entry = rpc_entry; + m_pending_recvg_entry.m_active_mask = tmp_active_mask; + m_pending_recvg_entry.m_virtual = false; + m_pending_recvg_entry.m_type = type; + m_pending_recvg_entry.m_branch_div_cycle = gpgpusim_total_cycles; + return (unsigned)-1; + } + } else { + if (m_num_physical_entries == m_max_st_size) { + bool spilled = spill_st_entry(); + if (!spilled) return (unsigned)-1; + } + } + unsigned entry = m_invalid_entries.top(); + m_invalid_entries.pop(); + assert(!m_splits_table[entry].m_valid); + m_splits_table[entry].m_pc = pc; + m_splits_table[entry].m_recvg_pc = rpc; + m_splits_table[entry].m_recvg_entry = rpc_entry; + m_splits_table[entry].m_active_mask = tmp_active_mask; + m_splits_table[entry].m_valid = true; + m_splits_table[entry].m_type = type; + m_num_entries++; + m_num_physical_entries++; + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); + assert(entry != (unsigned)-1); + + AWARE_DPRINTF("Inserting new entry to Splits Table: Entry %d\tPC %d\tRPC %d\n", + entry, pc, rpc); + + // call_ret=true: push to front for LIFO ordering + m_fifo_queue.push_front( + fifo_entry(entry, gpgpusim_total_cycles, m_fifo_queue.size())); + return entry; +} + +void simt_splits_table::push_back() { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + fifo_entry cur_active_split = m_fifo_queue.front(); + assert(cur_active_split.m_st_entry == m_active_split); + m_fifo_queue.pop_front(); + cur_active_split.update_insertion_cycle(gpgpusim_total_cycles, + m_fifo_queue.size()); + m_fifo_queue.push_back(cur_active_split); + fifo_entry new_active_split = m_fifo_queue.front(); + m_active_split = new_active_split.m_st_entry; + + AWARE_DPRINTF("Push current active split %d to back; New active split %d\n", + cur_active_split.m_st_entry, m_active_split); + + if (m_splits_table[m_active_split].m_virtual) { + if (!m_splits_table[m_active_split].m_transient && + !m_splits_table[m_active_split].m_blocked) + fill_st_entry(m_active_split); + } +} + +void simt_splits_table::push_back_once() { + // stub: same as push_back for now + push_back(); +} + +void simt_splits_table::update_active_entry() { + if (m_fifo_queue.size() > 0) { + fifo_entry new_active_entry = m_fifo_queue.front(); + m_active_split = new_active_entry.m_st_entry; + if (new_active_entry.m_blocked || m_splits_table[m_active_split].m_virtual) + push_back(); + assert(m_num_entries > 0); + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + assert(m_splits_table[m_active_split].m_active_mask.any()); + } +} + +void simt_splits_table::invalidate() { + if (!m_splits_table[m_active_split].m_valid) return; + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + assert(m_fifo_queue.front().m_st_entry == m_active_split); + assert(!m_splits_table[m_active_split].m_virtual); + + m_splits_table[m_active_split].m_valid = false; + m_fifo_queue.pop_front(); + m_num_entries--; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + m_invalid_entries.push(m_active_split); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_ST_ENTRIES); +} + +void simt_splits_table::update_pc(address_type new_pc) { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + assert(m_splits_table[m_active_split].m_valid); + assert(m_fifo_queue.front().m_st_entry == m_active_split); + m_splits_table[m_active_split].m_pc = new_pc; +} + +void simt_splits_table::set_to_blocked() { + m_splits_table[m_active_split].m_blocked = true; +} + +void simt_splits_table::unset_blocked() { + m_splits_table[m_active_split].m_blocked = false; +} + +void simt_splits_table::unset_blocked(unsigned entry) { + m_splits_table[entry].m_blocked = false; +} + +void simt_splits_table::release_blocked() { + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) unset_blocked(i); + for (unsigned i = 0; i < m_fifo_queue.size(); i++) + m_fifo_queue[i].m_blocked = false; +} + +bool simt_splits_table::is_blocked_or_virtual() { + bool blocked = true; + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) + blocked &= + (m_splits_table[i].m_blocked || m_splits_table[i].m_virtual); + return (blocked && m_num_entries > 0); +} + +bool simt_splits_table::is_virtual() { + bool virtualized = true; + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) + virtualized &= (m_splits_table[i].m_virtual); + return (virtualized && m_num_entries > 0); +} + +bool simt_splits_table::is_blocked() { + bool blocked = true; + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) + blocked &= (m_splits_table[i].m_blocked); + return (blocked && m_num_entries > 0); +} + +bool simt_splits_table::split_reaches_barrier(address_type pc) { + m_fifo_queue.front().m_blocked = true; + set_to_blocked(); + update_pc(pc); + return is_blocked(); +} + +unsigned simt_splits_table::get_rpc() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_recvg_pc; +} + +unsigned simt_splits_table::get_rpc_entry() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_recvg_entry; +} + +unsigned simt_splits_table::get_pc() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_pc; +} + +splits_table_entry_type simt_splits_table::get_type() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_type; +} + +bool simt_splits_table::valid() { + assert(m_splits_table.find(m_active_split) != m_splits_table.end()); + return m_splits_table[m_active_split].m_valid; +} + +unsigned simt_splits_table::check_simt_splits_table() { + unsigned count = 0; + for (unsigned i = 0; i < MAX_VIRTUAL_ST_ENTRIES; i++) + if (m_splits_table[i].m_valid) + for (unsigned j = 0; j < m_warp_size; j++) + if (m_splits_table[i].m_active_mask.test(j)) count++; + return count; +} + +void simt_splits_table::print(FILE *fout) { + printf("max of physical entries = %u\n", m_max_st_size); + printf("num of physical entries = %u\n", m_num_physical_entries); + printf("isBlocked? %u\n", is_blocked()); + if (!m_fifo_queue.empty()) { + fprintf(fout, "fifo- f: %02d\n", m_fifo_queue.front().m_st_entry); + fprintf(fout, "fifo- b: %02d\n", m_fifo_queue.back().m_st_entry); + fprintf(fout, "fifo-sz: %02lu\n", m_fifo_queue.size()); + } + printf("active entry = %u\n", m_active_split); + printf("Pending Recvg Entry valid: %u\n", m_pending_recvg_entry.m_valid); + printf("Response Entry: %d\n", m_response_st_entry); + for (unsigned k = 0; k < MAX_VIRTUAL_ST_ENTRIES; k++) { + simt_splits_table_entry &ste = m_splits_table[k]; + if (!ste.m_valid) continue; + if (ste.m_virtual) printf("Virtual: "); + if (ste.m_transient) printf("Transient: "); + if (ste.m_blocked) printf("Blocked: "); + fprintf(fout, " %1u ", k); + for (unsigned j = 0; j < m_warp_size; j++) + fprintf(fout, "%c", (ste.m_active_mask.test(j) ? '1' : '0')); + fprintf(fout, " pc: 0x%03x", ste.m_pc); + if (ste.m_recvg_pc == (unsigned)-1) + fprintf(fout, " rp: ---- %s\n", (ste.m_valid ? " V " : " N ")); + else + fprintf(fout, " rp: 0x%03x %s\n", ste.m_recvg_pc, + (ste.m_valid ? " V " : " N ")); + } +} + +// ── simt_reconvergence_table ───────────────────────────────────────────────── + +simt_reconvergence_table::simt_reconvergence_table( + unsigned wid, unsigned warpSize, const shader_core_config *config, + const struct memory_config *mem_config, simt_tables *simt_table) { + m_warp_id = wid; + m_warp_size = warpSize; + m_active_reconvergence = (unsigned)-1; + m_num_entries = 0; + m_num_physical_entries = 0; + m_num_transient_entries = 0; + m_max_rec_size = config->num_rec_entries; + m_simt_tables = simt_table; + m_spill_rec_entry = warp_inst_t(config); + m_fill_rec_entry = warp_inst_t(config); + m_pending_update_entry = simt_reconvergence_table_entry(); + m_response_rec_entry = -1; + m_config = config; + m_mem_config = mem_config; + reset(); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_RT_ENTRIES); +} + +void simt_reconvergence_table::reset() { + m_num_entries = 0; + m_num_physical_entries = 0; + m_recvg_table.clear(); + while (!m_invalid_entries.empty()) m_invalid_entries.pop(); + for (int i = 0; i < MAX_VIRTUAL_RT_ENTRIES; i++) + m_recvg_table[i] = simt_reconvergence_table_entry(); + for (int i = MAX_VIRTUAL_RT_ENTRIES - 1; i >= 0; i--) + m_invalid_entries.push(i); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_RT_ENTRIES); +} + +bool simt_reconvergence_table::push_to_rt_response_fifo(unsigned entry) { + if (m_response_rec_entry == -1) { + m_response_rec_entry = entry; + return true; + } + return false; +} + +unsigned simt_reconvergence_table::get_replacement_candidate() { + unsigned oldest_index = (unsigned)-1; + unsigned long long oldest_update = 0; + for (int i = 0; i < MAX_VIRTUAL_RT_ENTRIES; i++) { + if (m_recvg_table[i].m_valid && !m_recvg_table[i].m_virtual) { + if (oldest_update == 0) { + oldest_index = i; + oldest_update = m_recvg_table[i].m_branch_rec_cycle; + } else if (m_recvg_table[i].m_branch_rec_cycle > oldest_update) { + oldest_index = i; + oldest_update = m_recvg_table[i].m_branch_rec_cycle; + } + } + } + assert(oldest_index != (unsigned)-1); + return oldest_index; +} + +bool simt_reconvergence_table::fill_rec_entry(unsigned entry) { + if (!m_fill_rec_entry.empty()) return false; + + address_type pc = (m_warp_id * m_warp_size + entry) * MAX_BRU_VIR_PER_SPLIT + + (MAX_BRU_VIR_PER_SPLIT / 2); + address_type ppc = pc + BRU_VIR_START; + unsigned nbytes = 16; + unsigned offset_in_block = + pc & (m_config->m_L1D_config.get_line_sz() - 1); + if ((offset_in_block + nbytes) > m_config->m_L1I_config.get_line_sz()) + nbytes = (m_config->m_L1D_config.get_line_sz() - offset_in_block); + + mem_access_t acc(BRU_RT_FILL, ppc, nbytes, false, GPGPU_Context()); + m_fill_rec_entry.space = memory_space_t(local_space); + m_fill_rec_entry.cache_op = CACHE_ALL; + m_fill_rec_entry.op = LOAD_OP; + m_fill_rec_entry.mem_op = NOT_TEX; + m_fill_rec_entry.memory_op = bru_rt_fill_request; + m_fill_rec_entry.pc = ppc; + m_fill_rec_entry.inject_mem_acccesses(acc); + m_fill_rec_entry.occupy(); + m_fill_rec_entry.set_warp_id(m_warp_id); + m_fill_rec_entry.set_active(0); + m_recvg_table[entry].m_transient = true; + m_num_transient_entries++; + return true; +} + +bool simt_reconvergence_table::spill_rec_entry() { + if (!m_spill_rec_entry.empty()) return false; + assert(m_spill_rec_entry.empty()); + + unsigned entry_to_replace = get_replacement_candidate(); + m_recvg_table[entry_to_replace].m_virtual = true; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + + address_type pc = + (m_warp_id * m_warp_size + entry_to_replace) * MAX_BRU_VIR_PER_SPLIT + + (MAX_BRU_VIR_PER_SPLIT / 2); + address_type ppc = pc + BRU_VIR_START; + unsigned nbytes = 16; + unsigned offset_in_block = + pc & (m_config->m_L1D_config.get_line_sz() - 1); + if ((offset_in_block + nbytes) > m_config->m_L1I_config.get_line_sz()) + nbytes = (m_config->m_L1D_config.get_line_sz() - offset_in_block); + + mem_access_t acc(BRU_RT_SPILL, ppc, nbytes, true, GPGPU_Context()); + m_spill_rec_entry.space = memory_space_t(local_space); + m_spill_rec_entry.cache_op = CACHE_WRITE_BACK; + m_spill_rec_entry.op = STORE_OP; + m_spill_rec_entry.mem_op = NOT_TEX; + m_spill_rec_entry.memory_op = bru_rt_spill_request; + m_spill_rec_entry.pc = ppc; + m_spill_rec_entry.occupy(); + m_spill_rec_entry.set_warp_id(m_warp_id); + m_spill_rec_entry.set_active(0); + m_spill_rec_entry.inject_mem_acccesses(acc); + return true; +} + +void simt_reconvergence_table::cycle() { + if (m_pending_update_entry.m_valid && !m_pending_update_entry.m_transient) { + bool sent = fill_rec_entry(m_pending_update_entry.m_recvg_entry); + if (sent) m_pending_update_entry.m_transient = true; + } + + if (!m_spill_rec_entry.empty()) { + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; + mem_stage_access_type type; + bool done = m_shader->memory_cycle(m_spill_rec_entry, rc_fail, type); + if (done) { + m_spill_rec_entry.clear(); + m_spill_rec_entry.clear_pending_mem_requests(); + } + } + + if (!m_fill_rec_entry.empty()) { + enum mem_stage_stall_type rc_fail = NO_RC_FAIL; + mem_stage_access_type type; + bool done = m_shader->memory_cycle(m_fill_rec_entry, rc_fail, type); + if (done) { + m_fill_rec_entry.clear(); + m_fill_rec_entry.clear_pending_mem_requests(); + } + } + + if (m_response_rec_entry != -1) { + if (m_pending_update_entry.m_recvg_entry == + (unsigned)m_response_rec_entry) { + assert(m_pending_update_entry.m_valid); + simt_mask_t test = m_recvg_table[m_response_rec_entry].m_pending_mask & + ~m_pending_update_entry.m_active_mask; + bool converged = !test.any(); + bool spacefound = !m_simt_tables->is_pending_reconvergence() || + m_simt_tables->st_space_available(); + if (m_num_physical_entries == m_max_rec_size) { + bool spilled = spill_rec_entry(); + if (spilled && (!converged || (converged && spacefound))) { + m_recvg_table[m_response_rec_entry].m_virtual = false; + m_recvg_table[m_response_rec_entry].m_transient = false; + m_recvg_table[m_response_rec_entry].m_pending_mask = + m_recvg_table[m_response_rec_entry].m_pending_mask & + ~m_pending_update_entry.m_active_mask; + m_recvg_table[m_response_rec_entry].m_branch_rec_cycle = + m_pending_update_entry.m_branch_rec_cycle; + m_pending_update_entry.m_valid = false; + m_num_transient_entries--; + m_num_physical_entries++; + if (converged) { + simt_mask_t active_mask = + get_active_mask(m_response_rec_entry); + address_type pc = get_pc(m_response_rec_entry); + address_type rpc = get_rpc(m_response_rec_entry); + unsigned rpc_entry = get_rpc_entry(m_response_rec_entry); + splits_table_entry_type type = get_type(m_response_rec_entry); + invalidate(m_response_rec_entry); + m_simt_tables->insert_st_entry(pc, rpc, rpc_entry, active_mask, + type, true); + } + m_response_rec_entry = -1; + } + } else { + if (!converged || (converged && spacefound)) { + m_recvg_table[m_response_rec_entry].m_virtual = false; + m_recvg_table[m_response_rec_entry].m_transient = false; + m_recvg_table[m_response_rec_entry].m_pending_mask = + m_recvg_table[m_response_rec_entry].m_pending_mask & + ~m_pending_update_entry.m_active_mask; + m_recvg_table[m_response_rec_entry].m_branch_rec_cycle = + m_pending_update_entry.m_branch_rec_cycle; + m_pending_update_entry.m_valid = false; + m_num_transient_entries--; + m_num_physical_entries++; + if (converged) { + simt_mask_t active_mask = + get_active_mask(m_response_rec_entry); + address_type pc = get_pc(m_response_rec_entry); + address_type rpc = get_rpc(m_response_rec_entry); + unsigned rpc_entry = get_rpc_entry(m_response_rec_entry); + splits_table_entry_type type = get_type(m_response_rec_entry); + invalidate(m_response_rec_entry); + m_simt_tables->insert_st_entry(pc, rpc, rpc_entry, active_mask, + type, true); + } + m_response_rec_entry = -1; + } + } + } else { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + unsigned long long diff = + gpgpusim_total_cycles - + m_recvg_table[m_response_rec_entry].m_branch_rec_cycle; + if (diff > m_config->rec_time_out) { + const simt_mask_t &reconverged_mask = + (~m_recvg_table[m_response_rec_entry].m_pending_mask) & + (m_recvg_table[m_response_rec_entry].m_active_mask); + address_type pc = m_recvg_table[m_response_rec_entry].m_pc; + address_type rpc = m_recvg_table[m_response_rec_entry].m_recvg_pc; + unsigned rpc_entry = m_recvg_table[m_response_rec_entry].m_recvg_entry; + splits_table_entry_type type = + m_recvg_table[m_response_rec_entry].m_type; + m_simt_tables->insert_st_entry(pc, rpc, rpc_entry, reconverged_mask, + type, true); + update_masks_upon_time_out(m_response_rec_entry, reconverged_mask); + set_rec_cycle(m_response_rec_entry, gpgpusim_total_cycles); + } + } + } +} + +unsigned simt_reconvergence_table::insert_new_entry( + address_type pc, address_type rpc, unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, splits_table_entry_type type) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + if (m_num_physical_entries == m_max_rec_size) { + bool spilled = spill_rec_entry(); + assert(spilled); + } + assert(tmp_active_mask.any()); + int entry_num = m_invalid_entries.top(); + m_invalid_entries.pop(); + assert(!m_recvg_table[entry_num].m_valid); + m_recvg_table[entry_num].m_pc = pc; + m_recvg_table[entry_num].m_recvg_pc = rpc; + m_recvg_table[entry_num].m_recvg_entry = rpc_entry; + m_recvg_table[entry_num].m_active_mask = tmp_active_mask; + m_recvg_table[entry_num].m_pending_mask = tmp_active_mask; + m_recvg_table[entry_num].m_valid = true; + m_recvg_table[entry_num].m_branch_rec_cycle = gpgpusim_total_cycles; + m_recvg_table[entry_num].m_type = type; + m_num_entries++; + m_num_physical_entries++; + assert(entry_num != (unsigned)-1); + + AWARE_DPRINTF("Inserting new entry to Splits Table: Entry %d\tPC %d\tRPC %d\n", + entry_num, pc, rpc); + + return entry_num; +} + +void simt_reconvergence_table::update_masks_upon_time_out( + unsigned recvg_entry, const simt_mask_t &reconverged_mask) { + m_recvg_table[recvg_entry].m_active_mask = + m_recvg_table[recvg_entry].m_pending_mask; +} + +unsigned simt_reconvergence_table::address_to_entry(warp_inst_t inst) { + if (!inst.empty()) { + unsigned wid = inst.warp_id(); + address_type addr = inst.pc; + unsigned entry = + (addr - BRU_VIR_START - + (wid * m_config->warp_size) * MAX_BRU_VIR_PER_SPLIT - + MAX_BRU_VIR_PER_SPLIT / 2) / + (MAX_BRU_VIR_PER_SPLIT); + return entry; + } + return (unsigned)-1; +} + +bool simt_reconvergence_table::update_pending_mask( + unsigned recvg_entry, address_type recvg_pc, + const simt_mask_t &tmp_active_mask, bool &suspended) { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + assert(m_recvg_table[recvg_entry].m_pc == recvg_pc); + assert(m_recvg_table[recvg_entry].m_valid); + assert(m_recvg_table[recvg_entry].m_pending_mask.any()); + + if (m_recvg_table[recvg_entry].m_virtual) { + suspended = true; + assert(!m_pending_update_entry.m_valid); + if (!m_recvg_table[recvg_entry].m_transient) { + m_pending_update_entry.m_valid = true; + m_pending_update_entry.m_active_mask = tmp_active_mask; + m_pending_update_entry.m_branch_rec_cycle = gpgpusim_total_cycles; + m_pending_update_entry.m_recvg_entry = recvg_entry; + m_pending_update_entry.m_transient = false; + } + } else { + m_recvg_table[recvg_entry].m_branch_rec_cycle = gpgpusim_total_cycles; + m_recvg_table[recvg_entry].m_pending_mask = + m_recvg_table[recvg_entry].m_pending_mask & ~tmp_active_mask; + if (!m_recvg_table[recvg_entry].m_pending_mask.any()) { + invalidate(recvg_entry); + return true; + } + } + return false; } + +const simt_mask_t &simt_reconvergence_table::get_active_mask() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_active_mask; +} + +const simt_mask_t &simt_reconvergence_table::get_active_mask(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_active_mask; +} + +simt_reconvergence_table_entry simt_reconvergence_table::get_recvg_entry( + unsigned num) { + return m_recvg_table[num]; +} + +void simt_reconvergence_table::get_recvg_entry_info(unsigned num, unsigned *pc, + unsigned *rpc) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + *pc = m_recvg_table[num].m_pc; + *rpc = m_recvg_table[num].m_recvg_pc; +} + +void simt_reconvergence_table::get_active_recvg_info(unsigned *pc, + unsigned *rpc) { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + *pc = m_recvg_table[m_active_reconvergence].m_pc; + *rpc = m_recvg_table[m_active_reconvergence].m_recvg_pc; +} + +unsigned simt_reconvergence_table::get_rpc_entry() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_recvg_entry; +} + +unsigned simt_reconvergence_table::get_rpc_entry(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_recvg_entry; +} + +splits_table_entry_type simt_reconvergence_table::get_type(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_type; +} + +splits_table_entry_type simt_reconvergence_table::get_type() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_type; +} + +unsigned simt_reconvergence_table::get_rpc() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_recvg_pc; +} + +unsigned simt_reconvergence_table::get_rpc(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_recvg_pc; +} + +unsigned simt_reconvergence_table::get_pc() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end()); + return m_recvg_table[m_active_reconvergence].m_pc; +} + +unsigned simt_reconvergence_table::get_pc(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end()); + return m_recvg_table[num].m_pc; +} + +void simt_reconvergence_table::invalidate() { + assert(m_recvg_table.find(m_active_reconvergence) != m_recvg_table.end() && + m_recvg_table[m_active_reconvergence].m_valid); + m_recvg_table[m_active_reconvergence].m_valid = false; + m_invalid_entries.push(m_active_reconvergence); + m_num_entries--; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_RT_ENTRIES); +} + +void simt_reconvergence_table::invalidate(unsigned num) { + assert(m_recvg_table.find(num) != m_recvg_table.end() && + m_recvg_table[num].m_valid); + m_recvg_table[num].m_valid = false; + m_invalid_entries.push(num); + m_num_entries--; + m_num_physical_entries--; + assert(m_num_physical_entries != (unsigned)-1); + assert((m_num_entries + m_invalid_entries.size()) == MAX_VIRTUAL_RT_ENTRIES); +} + +void simt_reconvergence_table::set_rec_cycle(unsigned rec_entry, + unsigned long long time) { + m_recvg_table[rec_entry].m_branch_rec_cycle = time; +} + +unsigned simt_reconvergence_table::check_simt_reconvergence_table() { + unsigned count = 0; + for (unsigned i = 0; i < MAX_VIRTUAL_RT_ENTRIES; i++) + if (m_recvg_table[i].m_valid) + for (unsigned j = 0; j < m_warp_size; j++) + if (!m_recvg_table[i].m_pending_mask.test(j) && + m_recvg_table[i].m_active_mask.test(j)) + count++; + return count; +} + +void simt_reconvergence_table::print(FILE *fout) { + printf("max of physical entries=%u\n", m_max_rec_size); + printf("num of physical entries=%u\n", m_num_physical_entries); + for (unsigned k = 0; k < MAX_VIRTUAL_RT_ENTRIES; k++) { + simt_reconvergence_table_entry &rte = m_recvg_table[k]; + if (!rte.m_valid) continue; + fprintf(fout, " %1u ", k); + for (unsigned j = 0; j < m_warp_size; j++) + fprintf(fout, "%c", (rte.m_active_mask.test(j) ? '1' : '0')); + fprintf(fout, " "); + for (unsigned j = 0; j < m_warp_size; j++) + fprintf(fout, "%c", (rte.m_pending_mask.test(j) ? '1' : '0')); + fprintf(fout, " pc: 0x%03x", rte.m_pc); + if (rte.m_recvg_pc == (unsigned)-1) + fprintf(fout, " rp: ---- %s\n", (rte.m_valid ? " V " : " N ")); + else + fprintf(fout, " rp: 0x%03x %s\n", rte.m_recvg_pc, + (rte.m_valid ? " V " : " N ")); + } +} + +// ── simt_tables ────────────────────────────────────────────────────────────── + +simt_tables::simt_tables(unsigned wid, unsigned warpSize, + const shader_core_config *config, + const memory_config *mem_config) { + m_warp_id = wid; + m_warp_size = warpSize; + m_simt_splits_table = + new simt_splits_table(wid, warpSize, config, mem_config, this); + m_simt_recvg_table = + new simt_reconvergence_table(wid, warpSize, config, mem_config, this); + m_config = config; + m_mem_config = mem_config; + m_shader = NULL; +} + +void simt_tables::reset() { + m_simt_splits_table->reset(); + m_simt_recvg_table->reset(); + m_simt_splits_table->release_blocked(); +} + +void simt_tables::launch(address_type start_pc, + const simt_mask_t &active_mask) { + m_simt_splits_table->launch(start_pc, active_mask); +} + +void simt_tables::check_simt_tables() { + unsigned running = m_simt_splits_table->check_simt_splits_table(); + unsigned converged = m_simt_recvg_table->check_simt_reconvergence_table(); + if (running + converged > 32) { + printf("running=%u\n", running); + printf("converged=%u\n", converged); + abort(); + } +} + +void simt_tables::check_time_out() { + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + for (unsigned k = 0; k < m_config->num_rec_entries; k++) { + simt_reconvergence_table_entry recvg_table_entry = + m_simt_recvg_table->get_recvg_entry(k); + if (!recvg_table_entry.m_valid) continue; + const simt_mask_t &reconverged_mask = + (~recvg_table_entry.m_pending_mask) & (recvg_table_entry.m_active_mask); + unsigned long long diff = + gpgpusim_total_cycles - recvg_table_entry.m_branch_rec_cycle; + if (diff > (unsigned long long)m_config->rec_time_out) { + if (recvg_table_entry.m_virtual) { + m_simt_recvg_table->fill_rec_entry(k); + } else { + if (reconverged_mask.any()) { + address_type pc = recvg_table_entry.m_pc; + address_type rpc = recvg_table_entry.m_recvg_pc; + unsigned rpc_entry = recvg_table_entry.m_recvg_entry; + splits_table_entry_type type = recvg_table_entry.m_type; + m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, + reconverged_mask, type, true); + m_simt_recvg_table->update_masks_upon_time_out(k, reconverged_mask); + m_simt_recvg_table->set_rec_cycle(k, gpgpusim_total_cycles); + } + } + } + } +} + +void simt_tables::update(simt_mask_t &thread_done, addr_vector_t &next_pc, + address_type recvg_pc, op_type next_inst_op, + unsigned next_inst_size, address_type next_inst_pc, + bool predicated) { + check_simt_tables(); + + simt_mask_t top_active_mask = m_simt_splits_table->get_active_mask(); + simt_mask_t top_active_mask_keep = top_active_mask; + 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(); + assert(top_pc == next_inst_pc); + assert(top_active_mask.any()); + + const address_type null_pc = -1; + bool warp_diverged = false; + address_type new_recvg_pc = null_pc; + unsigned num_divergent_paths = 0; + unsigned new_recvg_entry = top_recvg_entry; + splits_table_entry_type top_type = m_simt_splits_table->get_type(); + + std::map<address_type, simt_mask_t> divergent_paths; + bool do_invalidate = false; + + while (top_active_mask.any()) { + address_type tmp_next_pc = null_pc; + simt_mask_t tmp_active_mask; + for (int i = m_warp_size - 1; i >= 0; i--) { + if (top_active_mask.test(i)) { + if (thread_done.test(i)) { + top_active_mask.reset(i); + } else if (tmp_next_pc == null_pc) { + tmp_next_pc = next_pc[i]; + tmp_active_mask.set(i); + top_active_mask.reset(i); + } else if (tmp_next_pc == next_pc[i]) { + tmp_active_mask.set(i); + top_active_mask.reset(i); + } + } + } + if (tmp_next_pc == null_pc) { + assert(!top_active_mask.any()); + continue; + } + divergent_paths[tmp_next_pc] = tmp_active_mask; + num_divergent_paths++; + } + + address_type not_taken_pc = next_inst_pc + next_inst_size; + assert(num_divergent_paths <= 2); + + for (unsigned i = 0; i < num_divergent_paths; i++) { + address_type tmp_next_pc = null_pc; + simt_mask_t tmp_active_mask; + tmp_active_mask.reset(); + + if (divergent_paths.find(not_taken_pc) != divergent_paths.end()) { + assert(i == 0); + tmp_next_pc = not_taken_pc; + tmp_active_mask = divergent_paths[tmp_next_pc]; + divergent_paths.erase(tmp_next_pc); + } else { + std::map<address_type, simt_mask_t>::iterator it = + divergent_paths.begin(); + tmp_next_pc = it->first; + tmp_active_mask = divergent_paths[tmp_next_pc]; + divergent_paths.erase(tmp_next_pc); + } + + unsigned long long gpgpusim_total_cycles = + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_sim_cycle + + GPGPU_Context()->the_gpgpusim->g_the_gpu->gpu_tot_sim_cycle; + + if (!predicated) { + if (next_inst_op == CALL_OPS) { + assert(num_divergent_paths == 1); + new_recvg_entry = m_simt_recvg_table->insert_new_entry( + top_pc, top_recvg_pc, top_recvg_entry, top_active_mask_keep, + top_type); + assert(new_recvg_entry != (unsigned)-1); + m_simt_splits_table->invalidate(); + m_simt_splits_table->update_active_entry(); + + simt_splits_table_entry new_st_entry; + new_st_entry.m_pc = tmp_next_pc; + new_st_entry.m_recvg_entry = new_recvg_entry; + new_st_entry.m_active_mask = tmp_active_mask; + new_st_entry.m_branch_div_cycle = gpgpusim_total_cycles; + new_st_entry.m_type = SPLITS_TABLE_TYPE_CALL; + m_simt_splits_table->insert_new_entry(new_st_entry); + return; + } else if (next_inst_op == RET_OPS && + top_type == SPLITS_TABLE_TYPE_CALL) { + assert(num_divergent_paths == 1); + top_recvg_entry = m_simt_splits_table->get_rpc_entry(); + m_simt_splits_table->invalidate(); + + simt_mask_t active_mask = + m_simt_recvg_table->get_active_mask(new_recvg_entry); + address_type pc = m_simt_recvg_table->get_pc(new_recvg_entry); + address_type rpc = m_simt_recvg_table->get_rpc(new_recvg_entry); + unsigned rpc_entry = + m_simt_recvg_table->get_rpc_entry(top_recvg_entry); + splits_table_entry_type type = + m_simt_recvg_table->get_type(new_recvg_entry); + m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, active_mask, + type, true, true); + m_simt_splits_table->update_active_entry(); + top_recvg_pc = m_simt_splits_table->get_rpc(); + bool suspended = false; + m_simt_recvg_table->update_pending_mask(top_recvg_entry, pc, + active_mask, suspended); + top_recvg_entry = m_simt_splits_table->get_rpc_entry(); + } + } + + if (tmp_next_pc == top_recvg_pc) { + bool suspended = false; + bool reconverged = m_simt_recvg_table->update_pending_mask( + top_recvg_entry, top_recvg_pc, tmp_active_mask, suspended); + if (reconverged && !suspended) { + simt_mask_t active_mask = + m_simt_recvg_table->get_active_mask(top_recvg_entry); + address_type pc = m_simt_recvg_table->get_pc(top_recvg_entry); + address_type rpc = m_simt_recvg_table->get_rpc(top_recvg_entry); + unsigned rpc_entry = + m_simt_recvg_table->get_rpc_entry(top_recvg_entry); + splits_table_entry_type type = + m_simt_recvg_table->get_type(top_recvg_entry); + m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, active_mask, + type, true); + } + if (num_divergent_paths == 1) { + if (!do_invalidate) { + m_simt_splits_table->invalidate(); + do_invalidate = true; + } + } + continue; + } + + if ((num_divergent_paths > 1) && !warp_diverged) { + warp_diverged = true; + new_recvg_pc = recvg_pc; + if (new_recvg_pc != top_recvg_pc) { + new_recvg_entry = m_simt_recvg_table->insert_new_entry( + new_recvg_pc, top_recvg_pc, top_recvg_entry, top_active_mask_keep, + top_type); + } + } + + if (warp_diverged && tmp_next_pc == new_recvg_pc) { + bool suspended = false; + bool reconverged = m_simt_recvg_table->update_pending_mask( + new_recvg_entry, new_recvg_pc, tmp_active_mask, suspended); + if (reconverged && !suspended) { + simt_mask_t active_mask = + m_simt_recvg_table->get_active_mask(new_recvg_entry); + address_type pc = m_simt_recvg_table->get_pc(new_recvg_entry); + address_type rpc = m_simt_recvg_table->get_rpc(new_recvg_entry); + unsigned rpc_entry = + m_simt_recvg_table->get_rpc_entry(new_recvg_entry); + splits_table_entry_type type = + m_simt_recvg_table->get_type(new_recvg_entry); + m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, active_mask, + type); + } + continue; + } + + if (warp_diverged) { + if (!do_invalidate) { + m_simt_splits_table->invalidate(); + do_invalidate = true; + } + m_simt_splits_table->insert_new_entry(tmp_next_pc, new_recvg_pc, + new_recvg_entry, tmp_active_mask, + top_type); + } else { + m_simt_splits_table->update_pc(tmp_next_pc); + if (tmp_next_pc != not_taken_pc) + m_simt_splits_table->push_back(); + } + } + + if (do_invalidate) m_simt_splits_table->update_active_entry(); + + check_simt_tables(); + + m_shader->update_st_size(m_simt_splits_table->num_entries()); + m_shader->update_rt_size(m_simt_recvg_table->num_entries()); +} + +const simt_mask_t &simt_tables::get_active_mask() { + return m_simt_splits_table->get_active_mask(); +} + +void simt_tables::get_pdom_active_split_info(unsigned *pc, unsigned *rpc) { + m_simt_splits_table->get_pdom_active_split_info(pc, rpc); +} + +unsigned simt_tables::get_rp() { return m_simt_splits_table->get_rpc(); } + +bool simt_tables::split_reaches_barrier(address_type pc) { + return m_simt_splits_table->split_reaches_barrier(pc); +} + +void simt_tables::release_barrier() { + m_simt_splits_table->release_blocked(); +} + +bool simt_tables::is_virtualized() { + return m_simt_splits_table->is_virtualized(); +} + +bool simt_tables::is_pending_reconvergence() { + return m_simt_splits_table->is_pending_reconvergence() && + m_simt_recvg_table->is_pending_update(); +} + +bool simt_tables::st_space_available() { + return m_simt_splits_table->st_space_available(); +} + +bool simt_tables::blocked() { return m_simt_splits_table->blocked(); } + +bool simt_tables::is_blocked() { return m_simt_splits_table->is_blocked(); } + +bool simt_tables::valid() { return m_simt_splits_table->valid(); } + +bool simt_tables::push_to_rt_response_fifo(unsigned entry) { + return m_simt_recvg_table->push_to_rt_response_fifo(entry); +} + +bool simt_tables::push_to_st_response_fifo(unsigned entry) { + return m_simt_splits_table->push_to_st_response_fifo(entry); +} + +void simt_tables::set_shader(shader_core_ctx *shader) { + m_shader = shader; + m_simt_splits_table->set_shader(shader); + m_simt_recvg_table->set_shader(shader); +} + +void simt_tables::push_back() { m_simt_splits_table->push_back(); } + +void simt_tables::print(FILE *fp) { + printf("w%02d\n", m_warp_id); + printf("Splits Table:\n"); + m_simt_splits_table->print(fp); + printf("Reconvergence Table:\n"); + m_simt_recvg_table->print(fp); +} + +// ── core_t ITS methods ─────────────────────────────────────────────────────── + +void core_t::initilizeSIMTDivergenceStructures(unsigned warp_count, + unsigned warp_size) { + if (m_gpu->simd_model() == POST_DOMINATOR) { + m_simt_stack = new simt_stack *[warp_count]; + for (unsigned i = 0; i < warp_count; ++i) + m_simt_stack[i] = new simt_stack(i, warp_size, m_gpu); + } else { + m_simt_tables = new simt_tables *[warp_count]; + for (unsigned i = 0; i < warp_count; ++i) + m_simt_tables[i] = + new simt_tables(i, warp_size, m_gpu->getShaderCoreConfig(), + m_gpu->getMemoryConfig()); + } + m_warp_size = warp_size; + m_warp_count = warp_count; +} + +void core_t::deleteSIMTDivergenceStructures() { + if (m_simt_stack) { + for (unsigned i = 0; i < m_warp_count; ++i) delete m_simt_stack[i]; + delete[] m_simt_stack; + m_simt_stack = NULL; + } + if (m_simt_tables) { + for (unsigned i = 0; i < m_warp_count; ++i) delete m_simt_tables[i]; + delete[] m_simt_tables; + m_simt_tables = NULL; + } +} + +void core_t::updateSIMTDivergenceStructures(unsigned warpId, + warp_inst_t *inst) { + simt_mask_t thread_done; + addr_vector_t next_pc; + unsigned wtid = warpId * m_warp_size; + for (unsigned i = 0; i < m_warp_size; i++) { + if (ptx_thread_done(wtid + i)) { + thread_done.set(i); + next_pc.push_back((address_type)-1); + } else { + if (inst->reconvergence_pc == RECONVERGE_RETURN_PC) + inst->reconvergence_pc = get_return_pc(m_thread[wtid + i]); + next_pc.push_back(m_thread[wtid + i]->get_pc()); + } + } + if (m_gpu->simd_model() == POST_DOMINATOR) { + m_simt_stack[warpId]->update(thread_done, next_pc, inst->reconvergence_pc, + inst->op, inst->isize, inst->pc); + } else { + AWARE_DPRINTF("Updating SIMT tables for Warp %d\n", warpId); + m_simt_tables[warpId]->update(thread_done, next_pc, inst->reconvergence_pc, + inst->op, inst->isize, inst->pc, + inst->pred != -1); + } +} + +// ── End ITS implementations ────────────────────────────────────────────────── diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h index 06c3082..e96ddc4 100644 --- a/src/abstract_hardware_model.h +++ b/src/abstract_hardware_model.h @@ -36,6 +36,10 @@ class gpgpu_sim; class kernel_info_t; class gpgpu_context; +class shader_core_ctx; +class shader_core_config; +struct memory_config; +class simt_tables; // Set a hard limit of 32 CTAs per shader [cuda only has 8] #define MAX_CTA_PER_SHADER 32 @@ -96,6 +100,7 @@ enum AdaptiveCache { FIXED = 0, ADAPTIVE_CACHE = 1 }; #ifdef __cplusplus +#include <stack> #include <stdio.h> #include <string.h> #include <set> @@ -185,7 +190,15 @@ typedef enum operation_pipeline_t operation_pipeline; enum mem_operation_t { NOT_TEX, TEX }; typedef enum mem_operation_t mem_operation; -enum _memory_op_t { no_memory_op = 0, memory_load, memory_store }; +enum _memory_op_t { + no_memory_op = 0, + bru_st_fill_request, + bru_st_spill_request, + bru_rt_fill_request, + bru_rt_spill_request, + memory_load, + memory_store +}; #include <assert.h> #include <stdlib.h> @@ -500,12 +513,16 @@ const unsigned long long TOTAL_SHARED_MEM = MAX_STREAMING_MULTIPROCESSORS * SHARED_MEM_SIZE_MAX; const unsigned long long TOTAL_LOCAL_MEM = MAX_STREAMING_MULTIPROCESSORS * MAX_THREAD_PER_SM * LOCAL_MEM_SIZE_MAX; -const unsigned long long SHARED_GENERIC_START = - GLOBAL_HEAP_START - TOTAL_SHARED_MEM; +// BRU virtualization memory region (carved out between global heap and shared mem) +const unsigned MAX_BRU_VIR_PER_SPLIT = (16 * 2); +const unsigned long long TOTAL_BRU_VIR = + (MAX_STREAMING_MULTIPROCESSORS * MAX_THREAD_PER_SM * MAX_BRU_VIR_PER_SPLIT); +const unsigned long long BRU_VIR_START = (GLOBAL_HEAP_START - TOTAL_BRU_VIR); +const unsigned long long SHARED_GENERIC_START = (BRU_VIR_START - TOTAL_SHARED_MEM); const unsigned long long LOCAL_GENERIC_START = SHARED_GENERIC_START - TOTAL_LOCAL_MEM; const unsigned long long STATIC_ALLOC_LIMIT = - GLOBAL_HEAP_START - (TOTAL_LOCAL_MEM + TOTAL_SHARED_MEM); + GLOBAL_HEAP_START - (TOTAL_LOCAL_MEM + TOTAL_SHARED_MEM + TOTAL_BRU_VIR); #if !defined(__CUDA_RUNTIME_API_H__) @@ -769,12 +786,13 @@ const unsigned SECTOR_SIZE = 32; // sector is 32 bytes width typedef std::bitset<SECTOR_CHUNCK_SIZE> mem_access_sector_mask_t; #define NO_PARTIAL_WRITE (mem_access_byte_mask_t()) -#define MEM_ACCESS_TYPE_TUP_DEF \ - MA_TUP_BEGIN(mem_access_type) \ - MA_TUP(GLOBAL_ACC_R), MA_TUP(LOCAL_ACC_R), MA_TUP(CONST_ACC_R), \ - MA_TUP(TEXTURE_ACC_R), MA_TUP(GLOBAL_ACC_W), MA_TUP(LOCAL_ACC_W), \ - MA_TUP(L1_WRBK_ACC), MA_TUP(L2_WRBK_ACC), MA_TUP(INST_ACC_R), \ - MA_TUP(L1_WR_ALLOC_R), MA_TUP(L2_WR_ALLOC_R), \ +#define MEM_ACCESS_TYPE_TUP_DEF \ + MA_TUP_BEGIN(mem_access_type) \ + MA_TUP(GLOBAL_ACC_R), MA_TUP(LOCAL_ACC_R), MA_TUP(CONST_ACC_R), \ + MA_TUP(TEXTURE_ACC_R), MA_TUP(GLOBAL_ACC_W), MA_TUP(BRU_ST_SPILL), \ + MA_TUP(BRU_ST_FILL), MA_TUP(BRU_RT_SPILL), MA_TUP(BRU_RT_FILL), \ + MA_TUP(LOCAL_ACC_W), MA_TUP(L1_WRBK_ACC), MA_TUP(L2_WRBK_ACC), \ + MA_TUP(INST_ACC_R), MA_TUP(L1_WR_ALLOC_R), MA_TUP(L2_WR_ALLOC_R), \ MA_TUP(NUM_MEM_ACCESS_TYPE) MA_TUP_END(mem_access_type) #define MA_TUP_BEGIN(X) enum X { @@ -971,13 +989,31 @@ class inst_t { virtual void print_insn(FILE *fp) const { fprintf(fp, " [inst @ pc=0x%04llx] ", pc); } + + bool is_bru_st_fill_request() const { + return (op == LOAD_OP && memory_op == bru_st_fill_request); + } + bool is_bru_rt_fill_request() const { + return (op == LOAD_OP && memory_op == bru_rt_fill_request); + } + bool is_bru_st_spill_request() const { + return (op == STORE_OP && memory_op == bru_st_spill_request); + } + bool is_bru_rt_spill_request() const { + return (op == STORE_OP && memory_op == bru_rt_spill_request); + } + bool is_load() const { return (op == LOAD_OP || op == TENSOR_CORE_LOAD_OP || - memory_op == memory_load); + memory_op == memory_load) && + (memory_op != bru_st_fill_request && + memory_op != bru_rt_fill_request); } bool is_store() const { return (op == STORE_OP || op == TENSOR_CORE_STORE_OP || - memory_op == memory_store); + memory_op == memory_store) && + (memory_op != bru_st_spill_request && + memory_op != bru_rt_spill_request); } bool is_fp() const { return ((sp_op == FP__OP)); } // VIJAY @@ -1055,7 +1091,21 @@ class inst_t { virtual void pre_decode() {} }; -enum divergence_support_t { POST_DOMINATOR = 1, NUM_SIMD_MODEL }; +enum splits_replacement_policy_t { + FIFO_BACK = 1, + NUM_ST_REPLACEMENT_POLICIES +}; + +enum reconvergence_replacement_policy_t { + REC_LRU = 1, + NUM_REC_REPLACEMENT_POLICIES +}; + +enum divergence_support_t { + POST_DOMINATOR = 1, + AWARE_RECONVERGENCE = 2, + NUM_SIMD_MODEL +}; const unsigned MAX_ACCESSES_PER_INSN_PER_THREAD = 8; @@ -1178,9 +1228,12 @@ class warp_inst_t : public inst_t { m_per_scalar_thread[lane_id].callback.thread = thread; } void set_active(const active_mask_t &active); + void set_active(unsigned lane_id) { m_warp_active_mask.set(lane_id); } void clear_active(const active_mask_t &inactive); void set_not_active(unsigned lane_id); + void clear_pending_mem_requests() { m_accessq.clear(); } + void inject_mem_acccesses(mem_access_t acc) { m_accessq.push_back(acc); } // accessors virtual void print_insn(FILE *fp) const { @@ -1195,6 +1248,9 @@ class warp_inst_t : public inst_t { return m_warp_issued_mask.count(); } // for instruction counting bool empty() const { return m_empty; } + void occupy() { m_empty = false; } + unsigned get_warp_id() const { return m_warp_id; } + void set_warp_id(unsigned warp_id) { m_warp_id = warp_id; } unsigned warp_id() const { assert(!m_empty); return m_warp_id; @@ -1301,6 +1357,285 @@ class checkpoint { void store_global_mem(class memory_space *mem, char *fname, char *format); unsigned radnom; }; +// Debug print macro for ITS (disabled by default) +#define AWARE_DEBUG_PRINT 1 +#define AWARE_DPRINTF(...) \ + if (AWARE_DEBUG_PRINT) { \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + } + +// ── ITS (AWARE Reconvergence) data structures ────────────────────────────── + +#define MAX_ST_SIZE 33 +#define MAX_RT_SIZE 32 + +enum splits_table_entry_type { + SPLITS_TABLE_ENTRY_TYPE_NORMAL = 0, + SPLITS_TABLE_TYPE_CALL +}; + +struct simt_splits_table_entry { + bool m_valid; + bool m_blocked; + bool m_virtual; + bool m_transient; + bool m_suspended; + address_type m_pc; + unsigned int m_calldepth; + simt_mask_t m_active_mask; + address_type m_recvg_pc; + unsigned int m_recvg_entry; + unsigned long long m_branch_div_cycle; + splits_table_entry_type m_type; + simt_splits_table_entry() + : m_valid(false), m_blocked(false), m_virtual(false), + m_transient(false), m_suspended(false), m_pc(-1), m_calldepth(0), + m_active_mask(), m_recvg_pc(-1), m_branch_div_cycle(0), + m_type(SPLITS_TABLE_ENTRY_TYPE_NORMAL) {} +}; + +struct fifo_entry { + bool m_blocked; + unsigned m_st_entry; + unsigned long long m_insertion_cycle; + unsigned m_insertion_distance; + fifo_entry() : m_blocked(false), m_st_entry(-1) {} + fifo_entry(unsigned num, unsigned long long cycle, unsigned dist) + : m_blocked(false), m_st_entry(num), m_insertion_cycle(cycle), + m_insertion_distance(dist) {} + void update_insertion_cycle(unsigned long long cycle, unsigned dist) { + m_insertion_cycle = cycle; + m_insertion_distance = dist; + } +}; + +struct simt_reconvergence_table_entry { + bool m_valid; + bool m_virtual; + bool m_transient; + address_type m_pc; + unsigned int m_calldepth; + simt_mask_t m_active_mask; + simt_mask_t m_pending_mask; + address_type m_recvg_pc; + unsigned int m_recvg_entry; + unsigned long long m_branch_rec_cycle; + splits_table_entry_type m_type; + simt_reconvergence_table_entry() + : m_valid(false), m_virtual(false), m_transient(false), m_pc(-1), + m_calldepth(0), m_active_mask(), m_recvg_pc(-1), + m_branch_rec_cycle(0), m_type(SPLITS_TABLE_ENTRY_TYPE_NORMAL) {} +}; + +class simt_splits_table { + public: + simt_splits_table(unsigned wid, unsigned warpSize, + const shader_core_config *config, + const struct memory_config *mem_config, + simt_tables *simt_table); + void reset(); + void launch(address_type start_pc, const simt_mask_t &active_mask); + unsigned insert_new_entry(address_type pc, address_type rpc, + unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, + splits_table_entry_type type, bool recvged = false); + unsigned insert_new_entry(address_type pc, address_type rpc, + unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, + splits_table_entry_type type, bool call_ret, + bool recvged); + unsigned insert_new_entry(simt_splits_table_entry entry, bool recvged = false); + bool fill_st_entry(unsigned entry); + bool spill_st_entry(); + void get_pdom_splits_entry_info(unsigned num, unsigned *pc, unsigned *rpc); + void get_pdom_active_split_info(unsigned *pc, unsigned *rpc); + const simt_mask_t &get_active_mask(unsigned num); + const simt_mask_t &get_active_mask(); + unsigned get_rpc(); + unsigned get_pc(); + unsigned get_rpc_entry(); + splits_table_entry_type get_type(); + bool valid(); + unsigned get_rpc(unsigned num); + void invalidate(); + void update_active_entry(); + void update_pc(address_type new_pc); + void set_to_blocked(); + void unset_blocked(); + void unset_blocked(unsigned entry); + void release_blocked(); + bool is_blocked(); + bool is_virtual(); + bool is_blocked_or_virtual(); + bool split_reaches_barrier(address_type pc); + void push_back(); + void push_back_once(); + unsigned check_simt_splits_table(); + unsigned num_entries() { return m_num_entries; } + unsigned getInsertionDist() { return m_fifo_queue.front().m_insertion_distance; } + unsigned long long getInsertionCycle() { return m_fifo_queue.front().m_insertion_cycle; } + void print(FILE *fp); + void cycle(); + bool branch_unit_avail() { return m_spill_st_entry.empty(); } + unsigned get_replacement_candidate(); + void set_shader(shader_core_ctx *shader); + bool push_to_st_response_fifo(unsigned entry); + bool is_virtualized(); + bool is_pending_reconvergence() { return m_pending_recvg_entry.m_valid; } + bool st_space_available() { return m_num_physical_entries < m_max_st_size; } + bool blocked(); + unsigned address_to_entry(warp_inst_t inst); + + protected: + unsigned m_warp_size; + unsigned m_warp_id; + unsigned m_max_st_size; + unsigned m_num_entries; + unsigned m_num_physical_entries; + unsigned m_num_transient_entries; + std::map<unsigned, simt_splits_table_entry> m_splits_table; + std::deque<fifo_entry> m_fifo_queue; + std::stack<int> m_invalid_entries; + std::stack<int> m_available_v_id; + unsigned m_active_split; + warp_inst_t m_spill_st_entry; + warp_inst_t m_fill_st_entry; + int m_response_st_entry; + shader_core_ctx *m_shader; + const shader_core_config *m_config; + const struct memory_config *m_mem_config; + simt_tables *m_simt_tables; + simt_splits_table_entry m_pending_recvg_entry; +}; + +class simt_reconvergence_table { + public: + simt_reconvergence_table(unsigned wid, unsigned warpSize, + const shader_core_config *config, + const struct memory_config *mem_config, + simt_tables *simt_table); + void reset(); + const simt_mask_t &get_active_mask(); + const simt_mask_t &get_active_mask(unsigned num); + void get_recvg_entry_info(unsigned num, unsigned *pc, unsigned *rpc); + void get_active_recvg_info(unsigned *pc, unsigned *rpc); + unsigned get_rpc(unsigned num); + unsigned get_rpc(); + unsigned get_rpc_entry(unsigned num); + splits_table_entry_type get_type(unsigned num); + splits_table_entry_type get_type(); + unsigned get_rpc_entry(); + unsigned get_pc(unsigned num); + unsigned get_pc(); + void invalidate(); + void invalidate(unsigned num); + bool update_pending_mask(unsigned top_recvg_entry, address_type top_recvg_pc, + const simt_mask_t &tmp_active_mask, bool &suspended); + unsigned insert_new_entry(address_type pc, address_type rpc, + unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, + splits_table_entry_type type); + void update_masks_upon_time_out(unsigned k, + const simt_mask_t &reconverged_mask); + void set_rec_cycle(unsigned rec_entry, unsigned long long time); + unsigned check_simt_reconvergence_table(); + simt_reconvergence_table_entry get_recvg_entry(unsigned num); + unsigned num_entries() { return m_num_entries; } + void print(FILE *fout); + void cycle(); + bool branch_unit_avail() { return m_spill_rec_entry.empty(); } + void set_shader(shader_core_ctx *shader) { m_shader = shader; } + bool spill_rec_entry(); + bool fill_rec_entry(unsigned entry); + bool is_pending_update() { return m_pending_update_entry.m_valid; } + bool push_to_rt_response_fifo(unsigned entry); + unsigned get_replacement_candidate(); + unsigned address_to_entry(warp_inst_t inst); + + protected: + unsigned m_warp_id; + unsigned m_warp_size; + unsigned m_num_entries; + unsigned m_num_physical_entries; + unsigned m_num_transient_entries; + unsigned m_max_rec_size; + std::map<int, simt_reconvergence_table_entry> m_recvg_table; + std::stack<int> m_invalid_entries; + unsigned m_active_reconvergence; + const shader_core_config *m_config; + shader_core_ctx *m_shader; + simt_tables *m_simt_tables; + warp_inst_t m_spill_rec_entry; + warp_inst_t m_fill_rec_entry; + int m_response_rec_entry; + simt_reconvergence_table_entry m_pending_update_entry; + const struct memory_config *m_mem_config; +}; + +class simt_tables { + public: + simt_tables(unsigned wid, unsigned warpSize, + const shader_core_config *config, + const memory_config *mem_config); + void reset(); + void launch(address_type start_pc, const simt_mask_t &active_mask); + void update(simt_mask_t &thread_done, addr_vector_t &next_pc, + address_type recvg_pc, op_type next_inst_op, + unsigned next_inst_size, address_type next_inst_pc, + bool predicated); + const simt_mask_t &get_active_mask(); + void get_pdom_active_split_info(unsigned *pc, unsigned *rpc); + unsigned get_rp(); + void check_simt_tables(); + void check_time_out(); + void release_barrier(); + bool split_reaches_barrier(address_type pc); + void print(FILE *fp); + unsigned getSTsize() { return m_simt_splits_table->num_entries(); } + unsigned getInsertionDist() { return m_simt_splits_table->getInsertionDist(); } + unsigned long long getInsertionCycle() { return m_simt_splits_table->getInsertionCycle(); } + unsigned getRTsize() { return m_simt_recvg_table->num_entries(); } + bool branch_unit_avail() { + return m_simt_splits_table->branch_unit_avail() && + m_simt_recvg_table->branch_unit_avail(); + } + bool push_to_st_response_fifo(unsigned entry); + bool push_to_rt_response_fifo(unsigned entry); + void cycle() { + m_simt_splits_table->cycle(); + m_simt_recvg_table->cycle(); + } + void set_shader(shader_core_ctx *shader); + void push_back(); + bool is_virtualized(); + bool is_pending_reconvergence(); + bool st_space_available(); + bool blocked(); + bool valid(); + bool is_blocked(); + bool fill_rec_entry(unsigned entry) { + return m_simt_recvg_table->fill_rec_entry(entry); + } + bool insert_st_entry(address_type pc, address_type rpc, unsigned rpc_entry, + const simt_mask_t &tmp_active_mask, + splits_table_entry_type type, bool recvged = false) { + return m_simt_splits_table->insert_new_entry(pc, rpc, rpc_entry, + tmp_active_mask, type, recvged); + } + + private: + unsigned m_warp_id; + unsigned m_warp_size; + simt_splits_table *m_simt_splits_table; + simt_reconvergence_table *m_simt_recvg_table; + const shader_core_config *m_config; + const struct memory_config *m_mem_config; + shader_core_ctx *m_shader; +}; + +// ── End ITS data structures ───────────────────────────────────────────────── + /* * This abstract class used as a base for functional and performance and * simulation, it has basic functional simulation data structures and @@ -1313,6 +1648,7 @@ class core_t { : m_gpu(gpu), m_kernel(kernel), m_simt_stack(NULL), + m_simt_tables(NULL), m_thread(NULL), m_warp_size(warp_size) { m_warp_count = threads_per_shader / m_warp_size; @@ -1324,7 +1660,7 @@ class core_t { assert(m_warp_count * m_warp_size > 0); m_thread = (ptx_thread_info **)calloc(m_warp_count * m_warp_size, sizeof(ptx_thread_info *)); - initilizeSIMTStack(m_warp_count, m_warp_size); + initilizeSIMTDivergenceStructures(m_warp_count, m_warp_size); for (unsigned i = 0; i < MAX_CTA_PER_SHADER; i++) { for (unsigned j = 0; j < MAX_BARRIERS_PER_CTA; j++) { @@ -1343,8 +1679,11 @@ class core_t { void execute_warp_inst_t(warp_inst_t &inst, unsigned warpId = (unsigned)-1); bool ptx_thread_done(unsigned hw_thread_id) const; virtual void updateSIMTStack(unsigned warpId, warp_inst_t *inst); + virtual void updateSIMTDivergenceStructures(unsigned warpId, warp_inst_t *inst); void initilizeSIMTStack(unsigned warp_count, unsigned warps_size); void deleteSIMTStack(); + void initilizeSIMTDivergenceStructures(unsigned warp_count, unsigned warp_size); + void deleteSIMTDivergenceStructures(); warp_inst_t getExecuteWarp(unsigned warpId); void get_pdom_stack_top_info(unsigned warpId, unsigned *pc, unsigned *rpc) const; @@ -1369,7 +1708,8 @@ class core_t { protected: class gpgpu_sim *m_gpu; kernel_info_t *m_kernel; - simt_stack **m_simt_stack; // pdom based reconvergence context for each warp + simt_stack **m_simt_stack; // pdom based reconvergence context for each warp + simt_tables **m_simt_tables; // ITS (AWARE) reconvergence tables per warp class ptx_thread_info **m_thread; unsigned m_warp_size; unsigned m_warp_count; diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index 9055502..1f7de38 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -327,7 +327,26 @@ void memory_config::reg_options(class OptionParser *opp) { void shader_core_config::reg_options(class OptionParser *opp) { option_parser_register(opp, "-gpgpu_simd_model", OPT_INT32, &model, - "1 = post-dominator", "1"); + "1 = post-dominator, 2 = AWARE reconvergence (ITS)", + "1"); + option_parser_register(opp, "-gpgpu_simd_rec_time_out", OPT_INT32, + &rec_time_out, + "reconvergence timeout (-1 = disabled)", "-1"); + option_parser_register(opp, "-gpgpu_simd_rec_size", OPT_INT32, + &num_rec_entries, + "number of physical reconvergence table entries", + "32"); + option_parser_register(opp, "-gpgpu_simd_st_size", OPT_INT32, + &num_st_entries, + "number of physical splits table entries", "32"); + option_parser_register(opp, "-gpgpu_simd_rec_replacement", OPT_INT32, + &rec_replacement, + "reconvergence table replacement policy (1 = LRU)", + "1"); + option_parser_register(opp, "-gpgpu_simd_st_replacement", OPT_INT32, + &st_replacement, + "splits table replacement policy (1 = FIFO_BACK)", + "1"); option_parser_register( opp, "-gpgpu_shader_core_pipeline", OPT_CSTR, &gpgpu_shader_core_pipeline_opt, diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 7a4ff37..bcf38d3 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -465,6 +465,9 @@ void shader_core_ctx::create_exec_pipeline() { for (unsigned i = 0; i < num_result_bus; i++) { this->m_result_bus.push_back(new std::bitset<MAX_ALU_LATENCY>()); } + + if (m_config->model == AWARE_RECONVERGENCE) + updateSIMTDivergenceStructuresInitialization(); } shader_core_ctx::shader_core_ctx(class gpgpu_sim *gpu, @@ -526,7 +529,11 @@ void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, for (unsigned i = start_thread / m_config->warp_size; i < end_thread / m_config->warp_size; ++i) { m_warp[i]->reset(); - m_simt_stack[i]->reset(); + if (m_config->model == POST_DOMINATOR) { + m_simt_stack[i]->reset(); + } else { + m_simt_tables[i]->reset(); + } } } @@ -535,23 +542,24 @@ void shader_core_ctx::init_warps(unsigned cta_id, unsigned start_thread, int cta_size, kernel_info_t &kernel) { address_type start_pc = next_pc(start_thread); unsigned kernel_id = kernel.get_uid(); - if (m_config->model == POST_DOMINATOR) { - unsigned start_warp = start_thread / m_config->warp_size; - unsigned warp_per_cta = cta_size / m_config->warp_size; - unsigned end_warp = end_thread / m_config->warp_size + - ((end_thread % m_config->warp_size) ? 1 : 0); - for (unsigned i = start_warp; i < end_warp; ++i) { - unsigned n_active = 0; - simt_mask_t active_threads; - for (unsigned t = 0; t < m_config->warp_size; t++) { - unsigned hwtid = i * m_config->warp_size + t; - if (hwtid < end_thread) { - n_active++; - assert(!m_active_threads.test(hwtid)); - m_active_threads.set(hwtid); - active_threads.set(t); - } + unsigned start_warp = start_thread / m_config->warp_size; + unsigned warp_per_cta = cta_size / m_config->warp_size; + unsigned end_warp = end_thread / m_config->warp_size + + ((end_thread % m_config->warp_size) ? 1 : 0); + for (unsigned i = start_warp; i < end_warp; ++i) { + unsigned n_active = 0; + simt_mask_t active_threads; + for (unsigned t = 0; t < m_config->warp_size; t++) { + unsigned hwtid = i * m_config->warp_size + t; + if (hwtid < end_thread) { + n_active++; + assert(!m_active_threads.test(hwtid)); + m_active_threads.set(hwtid); + active_threads.set(t); } + } + + if (m_config->model == POST_DOMINATOR) { m_simt_stack[i]->launch(start_pc, active_threads); if (m_gpu->resume_option == 1 && kernel_id == m_gpu->resume_kernel && @@ -570,13 +578,15 @@ void shader_core_ctx::init_warps(unsigned cta_id, unsigned start_thread, } start_pc = pc; } - - m_warp[i]->init(start_pc, cta_id, i, active_threads, m_dynamic_warp_id, - kernel.get_streamID()); - ++m_dynamic_warp_id; - m_not_completed += n_active; - ++m_active_warps; + } else { + m_simt_tables[i]->launch(start_pc, active_threads); } + + m_warp[i]->init(start_pc, cta_id, i, active_threads, m_dynamic_warp_id, + kernel.get_streamID()); + ++m_dynamic_warp_id; + m_not_completed += n_active; + ++m_active_warps; } } @@ -599,7 +609,11 @@ void gpgpu_sim::get_pdom_stack_top_info(unsigned sid, unsigned tid, void shader_core_ctx::get_pdom_stack_top_info(unsigned tid, unsigned *pc, unsigned *rpc) const { unsigned warp_id = tid / m_config->warp_size; - m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc); + if (m_config->model == POST_DOMINATOR) { + m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc); + } else { + m_simt_tables[warp_id]->get_pdom_active_split_info(pc, rpc); + } } float shader_core_ctx::get_current_occupancy(unsigned long long &active, @@ -879,12 +893,20 @@ void exec_shader_core_ctx::get_pdom_stack_top_info(unsigned warp_id, const warp_inst_t *pI, unsigned *pc, unsigned *rpc) { - m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc); + if (m_config->model == POST_DOMINATOR) { + m_simt_stack[warp_id]->get_pdom_stack_top_info(pc, rpc); + } else { + m_simt_tables[warp_id]->get_pdom_active_split_info(pc, rpc); + } } const active_mask_t &exec_shader_core_ctx::get_active_mask( unsigned warp_id, const warp_inst_t *pI) { - return m_simt_stack[warp_id]->get_active_mask(); + if (m_config->model == POST_DOMINATOR) { + return m_simt_stack[warp_id]->get_active_mask(); + } else { + return m_simt_tables[warp_id]->get_active_mask(); + } } void shader_core_ctx::decode() { @@ -974,7 +996,11 @@ void shader_core_ctx::fetch() { } // this code fetches instructions from the i-cache or generates memory - if (!m_warp[warp_id]->functional_done() && + bool simt_conditions = true; + if (m_config->model == AWARE_RECONVERGENCE) + simt_conditions = !is_virtualized(warp_id); + + if (simt_conditions && !m_warp[warp_id]->functional_done() && !m_warp[warp_id]->imiss_pending() && m_warp[warp_id]->ibuffer_empty()) { address_type pc; @@ -1070,11 +1096,31 @@ void shader_core_ctx::issue_warp(register_set &pipe_reg_set, } } + bool split_reaches_barrier = false; if (next_inst->op == BARRIER_OP) { m_warp[warp_id]->store_info_of_last_inst_at_barrier(*pipe_reg); - m_barriers.warp_reaches_barrier(m_warp[warp_id]->get_cta_id(), warp_id, - const_cast<warp_inst_t *>(next_inst)); - + if (m_config->model == POST_DOMINATOR) { + m_barriers.warp_reaches_barrier(m_warp[warp_id]->get_cta_id(), warp_id, + const_cast<warp_inst_t *>(next_inst)); + } else { + // AWARE_RECONVERGENCE: warp reaches barrier only when all its splits do + split_reaches_barrier = true; + bool warp_reaches_barrier = + m_simt_tables[warp_id]->split_reaches_barrier(next_inst->pc); + if (warp_reaches_barrier) { + split_reaches_barrier = false; + m_barriers.warp_reaches_barrier(m_warp[warp_id]->get_cta_id(), warp_id, + const_cast<warp_inst_t *>(next_inst)); + if (m_barriers.warps_count_at_barrier(m_warp[warp_id]->get_cta_id()) == + 0) { + unsigned n = m_config->n_thread_per_shader / m_config->warp_size; + for (unsigned i = 0; i < n; i++) { + if (m_warp[i]->get_cta_id() == m_warp[warp_id]->get_cta_id()) + m_simt_tables[i]->release_barrier(); + } + } + } + } } else if (next_inst->op == MEMORY_BARRIER_OP) { m_warp[warp_id]->set_membar(); } else if (next_inst->m_is_ldgdepbar) { // Add for LDGDEPBAR @@ -1120,10 +1166,11 @@ void shader_core_ctx::issue_warp(register_set &pipe_reg_set, } } - updateSIMTStack(warp_id, *pipe_reg); + updateSIMTDivergenceStructures(warp_id, *pipe_reg); m_scoreboard->reserveRegisters(*pipe_reg); m_warp[warp_id]->set_next_pc(next_inst->pc + next_inst->isize); + if (split_reaches_barrier) m_simt_tables[warp_id]->push_back(); } void shader_core_ctx::issue() { @@ -1299,9 +1346,17 @@ void scheduler_unit::cycle() { "barrier\n", (*iter)->get_warp_id(), (*iter)->get_dynamic_warp_id()); - while (!warp(warp_id).waiting() && !warp(warp_id).ibuffer_empty() && - (checked < max_issue) && (checked <= issued) && - (issued < max_issue)) { + bool simt_conditions = true; + if (m_shader->m_config->model == AWARE_RECONVERGENCE) { + simt_conditions = warp(warp_id).valid() && + !warp(warp_id).blocked() && + !warp(warp_id).pending_reconvergence() && + !warp(warp_id).virtualized(); + } + + while (simt_conditions && !warp(warp_id).waiting() && + !warp(warp_id).ibuffer_empty() && (checked < max_issue) && + (checked <= issued) && (issued < max_issue)) { const warp_inst_t *pI = warp(warp_id).ibuffer_next_inst(); // Jin: handle cdp latency; if (pI && pI->m_is_cdp && warp(warp_id).m_cdp_latency > 0) { @@ -1415,12 +1470,18 @@ void scheduler_unit::cycle() { } if (execute_on_SP) { + bool bru_avail = true; + if (m_shader->m_config->model == AWARE_RECONVERGENCE && + pI->op == BRANCH_OP) + bru_avail = m_shader->branch_unit_avail(warp_id); + if (bru_avail) { m_shader->issue_warp(*m_sp_out, pI, active_mask, warp_id, m_id); issued++; issued_inst = true; warp_inst_issued = true; previous_issued_inst_exec_type = exec_unit_type_t::SP; + } } else if (execute_on_INT) { m_shader->issue_warp(*m_int_out, pI, active_mask, warp_id, m_id); @@ -1836,6 +1897,14 @@ void shader_core_ctx::execute() { } } } + + // ITS: advance spill/fill state machines for all warps + if (m_config->model == AWARE_RECONVERGENCE) { + for (unsigned i = 0; i < m_warp_count; ++i) { + AWARE_DPRINTF("Cycling SIMT tables for Shader %d: Warp %d...\n", m_sid, i); + m_simt_tables[i]->cycle(); + } + } } void ldst_unit::print_cache_stats(FILE *fp, unsigned &dl1_accesses, @@ -2013,7 +2082,9 @@ mem_stage_stall_type ldst_unit::process_cache_access( if (status == HIT) { assert(!read_sent); inst.accessq_pop_back(); - if (inst.is_load()) { + if (inst.is_bru_st_fill_request() || inst.is_bru_rt_fill_request()) { + release_virtual_entries(inst); + } else if (inst.is_load()) { for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) if (inst.out[r] > 0) m_pending_writes[inst.warp_id()][inst.out[r]]--; @@ -2698,10 +2769,41 @@ void ldst_unit::issue(register_set ®_set) { pipelined_simd_unit::issue(reg_set); } +void ldst_unit::release_virtual_entries(warp_inst_t &inst) { + if (inst.is_bru_st_fill_request()) { + unsigned wid = inst.warp_id(); + address_type addr = inst.pc; + unsigned entry = (addr - BRU_VIR_START - + (wid * m_config->warp_size) * MAX_BRU_VIR_PER_SPLIT) / + MAX_BRU_VIR_PER_SPLIT; + bool done = m_core->push_to_st_response_fifo(wid, entry); + if (done) { + inst.clear(); + inst.clear_pending_mem_requests(); + } + } else { + assert(inst.is_bru_rt_fill_request()); + unsigned wid = inst.warp_id(); + address_type addr = inst.pc; + unsigned entry = (addr - BRU_VIR_START - + (wid * m_config->warp_size) * MAX_BRU_VIR_PER_SPLIT - + MAX_BRU_VIR_PER_SPLIT / 2) / + MAX_BRU_VIR_PER_SPLIT; + bool done = m_core->push_to_rt_response_fifo(wid, entry); + if (done) { + inst.clear(); + inst.clear_pending_mem_requests(); + } + } +} + void ldst_unit::writeback() { // process next instruction that is going to writeback if (!m_next_wb.empty()) { - if (m_operand_collector->writeback(m_next_wb)) { + if (m_next_wb.is_bru_st_fill_request() || + m_next_wb.is_bru_rt_fill_request()) { + release_virtual_entries(m_next_wb); + } else if (m_operand_collector->writeback(m_next_wb)) { bool insn_completed = false; for (unsigned r = 0; r < MAX_OUTPUT_VALUES; r++) { if (m_next_wb.out[r] > 0) { @@ -3357,7 +3459,10 @@ void shader_core_ctx::display_simt_state(FILE *fout, int mask) const { if (nactive == 0) { continue; } - m_simt_stack[i]->print(fout); + if (m_config->model == POST_DOMINATOR) + m_simt_stack[i]->print(fout); + else + m_simt_tables[i]->print(fout); } fprintf(fout, "\n"); } @@ -3673,6 +3778,12 @@ void shader_core_config::set_pipeline_latency() { void shader_core_ctx::cycle() { if (!isactive() && get_not_completed() == 0) return; + if (m_config->model == AWARE_RECONVERGENCE && m_config->rec_time_out > 0) { + unsigned long long total_cycles = + m_gpu->gpu_sim_cycle + m_gpu->gpu_tot_sim_cycle; + if (total_cycles % 10000 == 0) check_time_out(); + } + m_stats->shader_cycles[m_sid]++; writeback(); execute(); @@ -4114,6 +4225,81 @@ bool shd_warp_t::waiting() { return false; } +// ITS (AWARE Reconvergence) warp eligibility helpers +bool shd_warp_t::virtualized() { + return m_shader->is_virtualized(m_warp_id); +} + +bool shd_warp_t::pending_reconvergence() { + return m_shader->pending_reconvergence(m_warp_id); +} + +bool shd_warp_t::blocked() { + return m_shader->warp_blocked(m_warp_id); +} + +bool shd_warp_t::valid() { + return m_shader->warp_valid(m_warp_id); +} + +// ITS (AWARE Reconvergence) shader_core_ctx methods +void shader_core_ctx::updateSIMTDivergenceStructuresInitialization() { + unsigned n = m_config->n_thread_per_shader / m_config->warp_size; + for (unsigned i = 0; i < n; i++) { + m_simt_tables[i]->set_shader(this); + } +} + +bool shader_core_ctx::push_to_st_response_fifo(unsigned wid, unsigned entry) { + return m_simt_tables[wid]->push_to_st_response_fifo(entry); +} + +bool shader_core_ctx::push_to_rt_response_fifo(unsigned wid, unsigned entry) { + return m_simt_tables[wid]->push_to_rt_response_fifo(entry); +} + +bool shader_core_ctx::is_virtualized(unsigned wid) { + return m_simt_tables[wid]->is_virtualized(); +} + +bool shader_core_ctx::pending_reconvergence(unsigned wid) { + return m_simt_tables[wid]->is_pending_reconvergence(); +} + +bool shader_core_ctx::warp_blocked(unsigned wid) { + return m_simt_tables[wid]->blocked(); +} + +bool shader_core_ctx::warp_valid(unsigned wid) { + return m_simt_tables[wid]->valid(); +} + +void shader_core_ctx::update_st_size(unsigned n) { + // Stats not tracked in gpgpu-sim base; no-op. + (void)n; +} + +void shader_core_ctx::update_rt_size(unsigned n) { + // Stats not tracked in gpgpu-sim base; no-op. + (void)n; +} + +bool shader_core_ctx::branch_unit_avail(unsigned wid) { + return m_simt_tables[wid]->branch_unit_avail(); +} + +void shader_core_ctx::check_time_out() { + for (unsigned w = 0; w < m_config->max_warps_per_shader; w++) { + m_simt_tables[w]->check_time_out(); + } +} + +bool shader_core_ctx::memory_cycle(warp_inst_t &inst, + mem_stage_stall_type &rc_fail, + mem_stage_access_type &fail_type) { + return m_ldst_unit->memory_cycle(inst, rc_fail, fail_type); +} + void shd_warp_t::print(FILE *fout) const { if (!done_exit()) { fprintf(fout, diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index 5922d24..bb2ac33 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -177,6 +177,12 @@ class shd_warp_t { bool waiting(); // not const due to membar bool hardware_done() const; + // ITS (AWARE Reconvergence) warp eligibility helpers + bool virtualized(); + bool pending_reconvergence(); + bool blocked(); + bool valid(); + bool done_exit() const { return m_done_exit; } void set_done_exit() { m_done_exit = true; } @@ -1081,6 +1087,12 @@ class barrier_set_t { // assertions bool warp_waiting_at_barrier(unsigned warp_id) const; + // ITS: count warps from a given CTA that are at barrier + unsigned warps_count_at_barrier(int cta_id) { + warp_set_t t = m_cta_to_warps[cta_id] & m_warp_at_barrier; + return t.count(); + } + // debug void dump(); @@ -1371,6 +1383,9 @@ class ldst_unit : public pipelined_simd_unit { void flush(); void invalidate(); void writeback(); + void release_virtual_entries(warp_inst_t &inst); + bool memory_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail, + mem_stage_access_type &fail_type); // accessors virtual unsigned clock_multiplier() const; @@ -1429,8 +1444,6 @@ class ldst_unit : public pipelined_simd_unit { mem_stage_access_type &fail_type); bool texture_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type); - bool memory_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail, - mem_stage_access_type &fail_type); virtual mem_stage_stall_type process_cache_access( cache_t *cache, new_addr_type address, warp_inst_t &inst, @@ -1622,6 +1635,12 @@ class shader_core_config : public core_config { bool gpgpu_clock_gated_reg_file; bool gpgpu_clock_gated_lanes; enum divergence_support_t model; + // ITS (AWARE Reconvergence) config + int rec_time_out; // -1 = no reconvergence timeout + int num_rec_entries; // physical entries in reconvergence table + int num_st_entries; // physical entries in splits table + int rec_replacement; // reconvergence table replacement policy + int st_replacement; // splits table replacement policy unsigned n_thread_per_shader; unsigned n_regfile_gating_group; unsigned max_warps_per_shader; @@ -2423,6 +2442,21 @@ class shader_core_ctx : public core_t { } bool check_if_non_released_reduction_barrier(warp_inst_t &inst); + // ITS (AWARE Reconvergence) methods + bool is_virtualized(unsigned wid); + bool pending_reconvergence(unsigned wid); + bool warp_blocked(unsigned wid); + bool warp_valid(unsigned wid); + bool push_to_st_response_fifo(unsigned wid, unsigned entry); + bool push_to_rt_response_fifo(unsigned wid, unsigned entry); + void update_st_size(unsigned n); + void update_rt_size(unsigned n); + void check_time_out(); + bool branch_unit_avail(unsigned wid); + bool memory_cycle(warp_inst_t &inst, mem_stage_stall_type &rc_fail, + mem_stage_access_type &fail_type); + void updateSIMTDivergenceStructuresInitialization(); + protected: unsigned inactive_lanes_accesses_sfu(unsigned active_count, double latency) { return (((32 - active_count) >> 1) * latency) + |
