diff options
| author | Tor Aamodt <[email protected]> | 2010-10-05 13:34:47 -0800 |
|---|---|---|
| committer | Tor Aamodt <[email protected]> | 2010-10-05 13:34:47 -0800 |
| commit | e0f1b4359832ba2952ddcff3a400cd7e1e3d02b5 (patch) | |
| tree | 12f3dbd8366e15b4a9a299b0368df6fafea11847 | |
| parent | d859e08188eb5863888a9b018cf4aec6d0419c40 (diff) | |
broken change list: builds, but does not run, yet
refactoring: create warp_inst_t that provides notion of a group of scalar instructions
traveling down the pipeline.
delete DWF
delete MIMD
delete warp_tracker
delete old writeback stage, replace it with a stub that just writes back everything
delete old pipeline model
current status: MSHR's need to change to deal with the new structure
[git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 7814]
| -rw-r--r-- | src/abstract_hardware_model.cc | 11 | ||||
| -rw-r--r-- | src/abstract_hardware_model.h | 147 | ||||
| -rw-r--r-- | src/cuda-sim/cuda-sim.cc | 102 | ||||
| -rw-r--r-- | src/cuda-sim/cuda-sim.h | 11 | ||||
| -rw-r--r-- | src/cuda-sim/instructions.cc | 11 | ||||
| -rw-r--r-- | src/cuda-sim/ptx_ir.cc | 2 | ||||
| -rw-r--r-- | src/cuda-sim/ptx_ir.h | 2 | ||||
| -rw-r--r-- | src/cuda-sim/ptx_sim.h | 2 | ||||
| -rw-r--r-- | src/debug.cc | 8 | ||||
| -rw-r--r-- | src/gpgpu-sim/dwf.cc | 2606 | ||||
| -rw-r--r-- | src/gpgpu-sim/dwf.h | 121 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.cc | 137 | ||||
| -rw-r--r-- | src/gpgpu-sim/gpu-sim.h | 11 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_fetch.cc | 8 | ||||
| -rw-r--r-- | src/gpgpu-sim/mem_latency_stat.cc | 6 | ||||
| -rw-r--r-- | src/gpgpu-sim/scoreboard.cc | 3 | ||||
| -rw-r--r-- | src/gpgpu-sim/scoreboard.h | 2 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.cc | 1601 | ||||
| -rw-r--r-- | src/gpgpu-sim/shader.h | 186 | ||||
| -rw-r--r-- | src/gpgpu-sim/warp_tracker.cc | 271 | ||||
| -rw-r--r-- | src/gpgpu-sim/warp_tracker.h | 261 | ||||
| -rw-r--r-- | src/intersim/interconnect_interface.cpp | 2 |
22 files changed, 411 insertions, 5100 deletions
diff --git a/src/abstract_hardware_model.cc b/src/abstract_hardware_model.cc new file mode 100644 index 0000000..f5149eb --- /dev/null +++ b/src/abstract_hardware_model.cc @@ -0,0 +1,11 @@ +#include "abstract_hardware_model.h" + +void move_warp( warp_inst_t *&dst, warp_inst_t *&src ) +{ + assert( dst->empty() ); + warp_inst_t* temp = dst; + dst = src; + src = temp; + src->clear(); +} + diff --git a/src/abstract_hardware_model.h b/src/abstract_hardware_model.h index 5d73da7..02d58c2 100644 --- a/src/abstract_hardware_model.h +++ b/src/abstract_hardware_model.h @@ -47,7 +47,11 @@ enum _memory_op_t { #ifdef __cplusplus +#include <bitset> #include <list> +#include <vector> +#include <assert.h> +#include <stdlib.h> #if !defined(__VECTOR_TYPES_H__) struct dim3 { @@ -190,9 +194,10 @@ private: #define MAX_REG_OPERANDS 8 struct dram_callback_t { - void (*function)(void* pI, void* gOldGThread); - void* instruction; - void* thread; + dram_callback_t() { function=NULL; instruction=NULL; thread=NULL; } + void (*function)(const class inst_t*, class ptx_thread_info*); + const class inst_t* instruction; + class ptx_thread_info *thread; }; class inst_t { @@ -200,26 +205,16 @@ public: inst_t() { m_decoded=false; - pc = (address_type)-1; + pc=(address_type)-1; op=NO_OP; memset(out, 0, sizeof(unsigned)); memset(in, 0, sizeof(unsigned)); is_vectorin=0; is_vectorout=0; - memreqaddr=0; - hw_thread_id=-1; - wlane=-1; - uid = (unsigned)-1; - warp_active_mask = 0; - issue_cycle = 0; - cache_miss = false; space = memory_space_t(); cycles = 0; for( unsigned i=0; i < MAX_REG_OPERANDS; i++ ) arch_reg[i]=-1; - callback.function = NULL; - callback.instruction = NULL; - callback.thread = NULL; isize=0; } bool valid() const { return m_decoded; } @@ -228,37 +223,139 @@ public: fprintf(fp," [inst @ pc=0x%04x] ", pc ); } - unsigned uid; // unique id (for debugging) address_type pc; // program counter address of instruction unsigned isize; // size of instruction in bytes op_type op; // opcode (uarch visible) - _memory_op_t memory_op; // ptxplus - short hw_thread_id; // scalar hardware thread id - short wlane; // SIMT lane + _memory_op_t memory_op; // memory_op used by ptxplus - unsigned warp_active_mask; - unsigned long long issue_cycle; - unsigned out[4]; unsigned in[4]; unsigned char is_vectorin; unsigned char is_vectorout; - int pred; + int pred; // predicate register number int ar1, ar2; int arch_reg[MAX_REG_OPERANDS]; // register number for bank conflict evaluation unsigned cycles; // 1/throughput for instruction - unsigned long long int memreqaddr; // effective address unsigned data_size; // what is the size of the word being operated on? memory_space_t space; - dram_callback_t callback; - bool cache_miss; protected: bool m_decoded; virtual void pre_decode() {} }; +#define MAX_WARP_SIZE 32 + +class warp_inst_t: public inst_t { +public: + // constructors + warp_inst_t( unsigned warp_size ) + { + assert(warp_size<=MAX_WARP_SIZE); + m_warp_size=warp_size; + m_empty=true; + m_isatomic=false; + m_per_scalar_thread_valid=false; + } + + // modifiers + void do_atomic() + { + assert( m_isatomic && !m_empty ); + std::vector<per_thread_info>::iterator t; + for( t=m_per_scalar_thread.begin(); t != m_per_scalar_thread.end(); ++t ) { + dram_callback_t &cb = t->callback; + if( cb.thread ) + cb.function(cb.instruction, cb.thread); + } + } + void clear() + { + m_empty=true; + } + void issue( unsigned mask, unsigned warp_id, unsigned long long cycle ) + { + for (int i=(int)m_warp_size-1; i>=0; i--) { + if( mask & (1<<i) ) + warp_active_mask.set(i); + } + m_warp_id = warp_id; + issue_cycle = cycle; + m_empty=false; + } + void set_addr( unsigned n, new_addr_type addr ) + { + if( !m_per_scalar_thread_valid ) { + m_per_scalar_thread.resize(m_warp_size); + m_per_scalar_thread_valid=true; + } + m_per_scalar_thread[n].memreqaddr = addr; + } + void add_callback( unsigned lane_id, + void (*function)(const class inst_t*, class ptx_thread_info*), + const inst_t *inst, + class ptx_thread_info *thread ) + { + if( !m_per_scalar_thread_valid ) { + m_per_scalar_thread.resize(m_warp_size); + m_per_scalar_thread_valid=true; + m_isatomic=true; + } + m_per_scalar_thread[lane_id].callback.function = function; + m_per_scalar_thread[lane_id].callback.instruction = inst; + m_per_scalar_thread[lane_id].callback.thread = thread; + } + + // accessors + virtual void print_insn(FILE *fp) const + { + fprintf(fp," [inst @ pc=0x%04x] ", pc ); + for (int i=(int)m_warp_size-1; i>=0; i--) + fprintf(fp, "%c", ((warp_active_mask[i])?'1':'0') ); + } + bool active( unsigned thread ) const { return warp_active_mask.test(thread); } + bool empty() const { return m_empty; } + unsigned warp_id() const + { + assert( !m_empty ); + return m_warp_id; + } + bool has_callback( unsigned n ) const + { + return warp_active_mask[n] && m_per_scalar_thread_valid && + (m_per_scalar_thread[n].callback.function!=NULL); + } + new_addr_type get_addr( unsigned n ) const + { + assert( m_per_scalar_thread_valid ); + return m_per_scalar_thread[n].memreqaddr; + } + + bool isatomic() const { return m_isatomic; } + +protected: + bool m_empty; + unsigned long long issue_cycle; + bool m_isatomic; + unsigned m_warp_id; + unsigned m_warp_size; + std::bitset<MAX_WARP_SIZE> warp_active_mask; + + struct per_thread_info { + per_thread_info() { + cache_miss=false; + memreqaddr=0; + } + dram_callback_t callback; + new_addr_type memreqaddr; // effective address + bool cache_miss; + }; + bool m_per_scalar_thread_valid; + std::vector<per_thread_info> m_per_scalar_thread; +}; + +void move_warp( warp_inst_t *&dst, warp_inst_t *&src ); size_t get_kernel_code_size( class function_info *entry ); diff --git a/src/cuda-sim/cuda-sim.cc b/src/cuda-sim/cuda-sim.cc index c28f1a0..dcf1fd4 100644 --- a/src/cuda-sim/cuda-sim.cc +++ b/src/cuda-sim/cuda-sim.cc @@ -463,71 +463,6 @@ void gpgpu_ptx_sim_memset( size_t dst_start_addr, int c, size_t count ) fflush(stdout); } -const char * ptx_get_fname( unsigned PC ) -{ - static const char *null_ptr = "<null finfo ptr>"; - std::map<unsigned,function_info*>::iterator f=g_pc_to_finfo.find(PC); - if( f== g_pc_to_finfo.end() ) - return null_ptr; - return f->second->get_name().c_str(); -} - -unsigned ptx_thread_donecycle( void *thr ) -{ - ptx_thread_info *the_thread = (ptx_thread_info *) thr; - if( the_thread == NULL ) - return 0; - return the_thread->donecycle(); -} - -void* ptx_thread_get_next_finfo( void *thd ) -{ - ptx_thread_info *the_thread = (ptx_thread_info *) thd; - if ( the_thread == NULL ) - return NULL; - return the_thread->get_finfo(); // finfo should already be updatd to next PC at this point (was set in shader_decode() last time thread ran) -} - -int ptx_thread_at_barrier( void *thd ) -{ - ptx_thread_info *the_thread = (ptx_thread_info *) thd; - if ( the_thread == NULL ) - return 0; - return the_thread->is_at_barrier(); -} - -int ptx_thread_all_at_barrier( void *thd ) -{ - ptx_thread_info *the_thread = (ptx_thread_info *) thd; - if ( the_thread == NULL ) - return 0; - return the_thread->all_at_barrier()?1:0; -} - -unsigned long long ptx_thread_get_cta_uid( void *thd ) -{ - ptx_thread_info *the_thread = (ptx_thread_info *) thd; - if ( the_thread == NULL ) - return 0; - return the_thread->get_cta_uid(); -} - -void ptx_thread_reset_barrier( void *thd ) -{ - ptx_thread_info *the_thread = (ptx_thread_info *) thd; - if ( the_thread == NULL ) - return; - the_thread->clear_barrier(); -} - -void ptx_thread_release_barrier( void *thd ) -{ - ptx_thread_info *the_thread = (ptx_thread_info *) thd; - if ( the_thread == NULL ) - return; - the_thread->release_barrier(); -} - void ptx_print_insn( address_type pc, FILE *fp ) { std::map<unsigned,function_info*>::iterator f = g_pc_to_finfo.find(pc); @@ -919,9 +854,7 @@ void init_inst_classification_stat() g_inst_op_classification_stat[g_ptx_kernel_count] = StatCreate(kernelname,1,100); } -unsigned g_warp_active_mask; - -void ptx_thread_info::ptx_exec_inst( inst_t &inst ) +void ptx_thread_info::ptx_exec_inst( warp_inst_t &inst, unsigned lane_id ) { inst.memory_op = no_memory_op; bool skip = false; @@ -956,7 +889,6 @@ void ptx_thread_info::ptx_exec_inst( inst_t &inst ) skip = !pred_lookup(pI->get_pred_mod(), pred_value.pred & 0x000F); } } - g_warp_active_mask = inst.warp_active_mask; if( !skip ) { switch ( pI->get_opcode() ) { #define OP_DEF(OP,FUNC,STR,DST,CLASSIFICATION) case OP: FUNC(pI,this); op_classification = CLASSIFICATION; break; @@ -1014,21 +946,13 @@ void ptx_thread_info::ptx_exec_inst( inst_t &inst ) if ( pI->get_opcode() == ATOM_OP ) { insn_memaddr = last_eaddr(); insn_space = last_space(); - inst.callback.function = last_callback().function; - inst.callback.instruction = last_callback().instruction; - inst.callback.thread = this; - + inst.add_callback( lane_id, last_callback().function, last_callback().instruction, this ); unsigned to_type = pI->get_type(); insn_data_size = datatype2size(to_type); - } else { - // make sure that the callback isn't set - inst.callback.function = NULL; - inst.callback.instruction = NULL; - inst.callback.thread = NULL; } if (pI->get_opcode() == TEX_OP) { - inst.memreqaddr = last_eaddr(); + inst.set_addr(lane_id, last_eaddr() ); inst.space = last_space(); unsigned to_type = pI->get_type(); @@ -1106,11 +1030,10 @@ void ptx_thread_info::ptx_exec_inst( inst_t &inst ) // "Return values" if(!skip) { inst.space = insn_space; - inst.memreqaddr = insn_memaddr; + inst.set_addr(lane_id, insn_memaddr); inst.data_size = insn_data_size; inst.memory_op = insn_memory_op; } else { - inst.memreqaddr = 0xFEEBDAED; inst.space = undefined_space; inst.memory_op = no_memory_op; } @@ -1137,7 +1060,7 @@ const struct gpgpu_ptx_sim_kernel_info* ptx_sim_kernel_info(function_info *kerne return kernel->get_kernel_info(); } -const inst_t *ptx_fetch_inst( address_type pc ) +const warp_inst_t *ptx_fetch_inst( address_type pc ) { return function_info::pc_to_instruction(pc); } @@ -1550,10 +1473,7 @@ void gpgpu_cuda_ptx_sim_main_func( kernel_info_t kernel, dim3 gridDim, dim3 bloc break; } - inst_t inst; - inst.warp_active_mask = (unsigned)-1; // vote instruction with diverged warps won't execute correctly - // in functional simulation mode - thread->ptx_exec_inst( inst ); + abort(); // need to exec. inst } } } @@ -1685,8 +1605,6 @@ void ptxinfo_opencl_addinfo( std::map<std::string,function_info*> &kernels ) clear_ptxinfo(); } -void dwf_insert_reconv_pt(address_type pc); - struct rec_pts { gpgpu_recon_t *s_kernel_recon_points; int s_num_recon; @@ -1744,11 +1662,3 @@ unsigned int get_converge_point( unsigned int pc, void *thd ) abort(); // returning garbage! } -void dwf_process_reconv_pts(function_info *entry) -{ - rec_pts tmp = find_reconvergence_points(entry); - for (int i = 0; i < tmp.s_num_recon; ++i) { - dwf_insert_reconv_pt(tmp.s_kernel_recon_points[i].target_pc); - } -} - diff --git a/src/cuda-sim/cuda-sim.h b/src/cuda-sim/cuda-sim.h index 4a0185a..322e8a2 100644 --- a/src/cuda-sim/cuda-sim.h +++ b/src/cuda-sim/cuda-sim.h @@ -56,19 +56,10 @@ unsigned ptx_sim_init_thread( kernel_info_t &kernel, class core_t *core, unsigned hw_cta_id, unsigned hw_warp_id ); -const inst_t *ptx_fetch_inst( address_type pc ); +const warp_inst_t *ptx_fetch_inst( address_type pc ); const struct gpgpu_ptx_sim_kernel_info* ptx_sim_kernel_info(class function_info *kernel); -unsigned ptx_thread_donecycle( void *thr ); -void* ptx_thread_get_next_finfo( void *thd ); -int ptx_thread_at_barrier( void *thd ); -int ptx_thread_all_at_barrier( void *thd ); -unsigned long long ptx_thread_get_cta_uid( void *thd ); -void ptx_thread_reset_barrier( void *thd ); -void ptx_thread_release_barrier( void *thd ); void ptx_print_insn( address_type pc, FILE *fp ); unsigned int ptx_set_tex_cache_linesize( unsigned linesize); - -void dwf_process_reconv_pts(function_info *entry); void set_param_gpgpu_num_shaders(int num_shaders); unsigned int get_converge_point(unsigned int pc, void *thd); const char *get_ptxinfo_kname(); diff --git a/src/cuda-sim/instructions.cc b/src/cuda-sim/instructions.cc index 78996bb..23d6cc8 100644 --- a/src/cuda-sim/instructions.cc +++ b/src/cuda-sim/instructions.cc @@ -831,10 +831,9 @@ void andn_impl( const ptx_instruction *pI, ptx_thread_info *thread ) thread->set_operand_value(dst,data, i_type, thread, pI); } -void atom_callback( void* ptx_inst, void* thd ) +void atom_callback( const inst_t* inst, ptx_thread_info* thread ) { - ptx_thread_info *thread = (ptx_thread_info*)thd; - ptx_instruction *pI = (ptx_instruction*)ptx_inst; + const ptx_instruction *pI = dynamic_cast<const ptx_instruction*>(inst); // Check state space assert( pI->get_space()==global_space ); @@ -1112,7 +1111,7 @@ void atom_impl( const ptx_instruction *pI, ptx_thread_info *thread ) thread->m_last_effective_address = src1_data.u32; thread->m_last_memory_space = space; thread->m_last_dram_callback.function = atom_callback; - thread->m_last_dram_callback.instruction = (void*)pI; + thread->m_last_dram_callback.instruction = pI; } void bar_sync_impl( const ptx_instruction *pI, ptx_thread_info *thread ) @@ -3787,8 +3786,6 @@ void vshl_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_ void vshr_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); } void vsub_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { inst_not_implemented(pI); } -extern unsigned g_warp_active_mask; - void vote_impl( const ptx_instruction *pI, ptx_thread_info *thread ) { static bool first_in_warp = true; @@ -3804,7 +3801,7 @@ void vote_impl( const ptx_instruction *pI, ptx_thread_info *thread ) or_all = false; unsigned mask=0x80000000; unsigned offset=31; - while( mask && ((mask & g_warp_active_mask)==0) ) { + while( mask && !pI->active(mask) ) { mask = mask>>1; offset--; } diff --git a/src/cuda-sim/ptx_ir.cc b/src/cuda-sim/ptx_ir.cc index 2d63227..b7ec3ac 100644 --- a/src/cuda-sim/ptx_ir.cc +++ b/src/cuda-sim/ptx_ir.cc @@ -983,7 +983,7 @@ ptx_instruction::ptx_instruction( int opcode, const char *file, unsigned line, const char *source, - unsigned warp_size ) : inst_t() + unsigned warp_size ) : warp_inst_t(warp_size) { m_uid = ++g_num_ptx_inst_uid; m_PC = 0; diff --git a/src/cuda-sim/ptx_ir.h b/src/cuda-sim/ptx_ir.h index afb2476..6010caf 100644 --- a/src/cuda-sim/ptx_ir.h +++ b/src/cuda-sim/ptx_ir.h @@ -786,7 +786,7 @@ struct gpgpu_recon_t { address_type target_pc; }; -class ptx_instruction : public inst_t { +class ptx_instruction : public warp_inst_t { public: ptx_instruction( int opcode, const symbol *pred, diff --git a/src/cuda-sim/ptx_sim.h b/src/cuda-sim/ptx_sim.h index 3a6d9ad..80ccde3 100644 --- a/src/cuda-sim/ptx_sim.h +++ b/src/cuda-sim/ptx_sim.h @@ -277,7 +277,7 @@ public: ptx_thread_info(); void ptx_fetch_inst( inst_t &inst ) const; - void ptx_exec_inst( inst_t &inst ); + void ptx_exec_inst( warp_inst_t &inst, unsigned lane_id ); const ptx_version &get_ptx_version() const; void set_reg( const symbol *reg, const ptx_reg_t &value ); diff --git a/src/debug.cc b/src/debug.cc index f3febfb..7bc72ac 100644 --- a/src/debug.cc +++ b/src/debug.cc @@ -84,14 +84,14 @@ void gpgpu_sim::gpgpu_debug() } } else { for( unsigned sid=0; sid < m_n_shader; sid++ ) { - inst_t *fvi = m_sc[sid]->first_valid_thread(IF_ID); - if( !fvi ) continue; - unsigned hw_thread_id = fvi->hw_thread_id; + unsigned hw_thread_id = m_sc[sid]->first_valid_thread(IF_ID); + if( hw_thread_id == (unsigned)-1 ) + continue; ptx_thread_info *thread = m_sc[sid]->get_functional_thread(hw_thread_id); if( thread_at_brkpt(thread, b) ) { done = false; printf("GPGPU-Sim PTX DBG: reached breakpoint %u at %s (sm=%u, hwtid=%u)\n", - num, b.location().c_str(), sid, fvi->hw_thread_id ); + num, b.location().c_str(), sid, hw_thread_id ); brk_thd = thread; brk_inst = brk_thd->get_inst(); printf( "GPGPU-Sim PTX DBG: reached by thread uid=%u, sid=%u, hwtid=%u\n", diff --git a/src/gpgpu-sim/dwf.cc b/src/gpgpu-sim/dwf.cc deleted file mode 100644 index 7c5305c..0000000 --- a/src/gpgpu-sim/dwf.cc +++ /dev/null @@ -1,2606 +0,0 @@ -/* - * dwf.cc - * - * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, and the - * University of British Columbia - * Vancouver, BC V6T 1Z4 - * All Rights Reserved. - * - * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE - * TERMS AND CONDITIONS. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h - * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda - * (property of NVIDIA). The files benchmarks/BlackScholes/ and - * benchmarks/template/ are derived from the CUDA SDK available from - * http://www.nvidia.com/cuda (also property of NVIDIA). The files from - * src/intersim/ are derived from Booksim (a simulator provided with the - * textbook "Principles and Practices of Interconnection Networks" available - * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by - * the corresponding legal terms and conditions set forth separately (original - * copyright notices are left in files from these sources and where we have - * modified a file our copyright notice appears before the original copyright - * notice). - * - * Using this version of GPGPU-Sim requires a complete installation of CUDA - * which is distributed seperately by NVIDIA under separate terms and - * conditions. To use this version of GPGPU-Sim with OpenCL requires a - * recent version of NVIDIA's drivers which support OpenCL. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the University of British Columbia nor the names of - * its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. - * - * 5. No nonprofit user may place any restrictions on the use of this software, - * including as modified by the user, by any other authorized user. - * - * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, - * Ali Bakhoda, George L. Yuan, at the University of British Columbia, - * Vancouver, BC V6T 1Z4 - */ - - -#include "dwf.h" -#include "histogram.h" -#include <map> -#include <set> -#include <deque> -#include <queue> -#include <string.h> - -using namespace std; - -bool gpgpu_dwf_regbk; -unsigned int gpgpu_dwf_heuristic; -enum { - MAJORITY = 0, - MINORITY = 1, - FIFO = 2, - PDOMPRIO = 3, - PC = 4, - MAJORITY_MAXHEAP = 5, - N_DWFMODE -}; - -typedef struct warp_entry { - address_type pc; - int* tid; // thread id's - int occ; // occupancy vector - int pdom_prio; // pdom_priority - int pdom_occ; // pdom_priority's aux data - int next_warp; // index to next warp in an implicit queue - void* lut_ptr; // pointer to the warp lut entry that last update this warp (a hack), done to decouple warp lut and warp pool - int uid; // unique id of a warp -} warp_entry_t; - -class issue_warp_majority { -public: - - virtual void add_threads( address_type pc, int *tid) = 0; - virtual void push_warp( address_type pc, int idx) = 0; - virtual int pop_warp( ) = 0; - virtual void print( FILE *fout ) = 0; - virtual ~issue_warp_majority( ) {} -}; - -typedef struct maxheap_lut_entry { - address_type pc; // pc of the warps - int maxheap_idx; // index to the max heap -} maxheap_lut_entry_t; - -typedef struct maxheap_entry { - address_type pc; // pc of the warps - int n_thds; // number of threads with this pc (from lut) - int wpool_head; // the first warp with this pc - int wpool_tail; // the last warp with this pc - int lut_idx; // reverse index to the lut (for update in entry movement) -} maxheap_entry_t; - -class mh_lut_class { -private: - - maxheap_lut_entry_t *lut_data; - list<int> *lru_stack; // front = LRU - int n_set; - int insn_size_lgb2; - -public: - - int size; - int assoc; - int n_read; - int n_write; - int n_read_per_cycle; - int n_write_per_cycle; - - int n_aliased; - static maxheap_lut_entry_t clean_entry; - - mh_lut_class (int size, int assoc, int n_read_per_cycle, int n_write_per_cycle ) { - int i; - - this->size = size; - this->assoc = assoc; - lut_data = new maxheap_lut_entry_t[size]; - - for (i=0; i<size; i++) { - lut_data[i] = clean_entry; - } - - n_set = size/assoc; - assert(n_set && !((n_set - 1) & n_set)); // make sure n_set is a power of 2 - - insn_size_lgb2 = 0; - - lru_stack = new list<int>[n_set]; - for (i=0; i<n_set; i++) { - int j; - for (j=0; j<assoc; j++) { - lru_stack[i].push_back(i * assoc + j); - } - } - - this->n_read_per_cycle = n_read_per_cycle; - this->n_write_per_cycle = n_write_per_cycle; - this->n_read = 0; - this->n_write = 0; - this->n_aliased = 0; - } - - ~mh_lut_class ( ) { - delete[] lut_data; - } - - // obtain entry at a known location - maxheap_lut_entry_t get( int lut_idx ) { - assert(lut_idx < size); - n_read++; - return lut_data[lut_idx]; - } - - // modify an entry at a known location - void set( int lut_idx, maxheap_lut_entry_t lut_entry ) { - n_write++; - lut_data[lut_idx] = lut_entry; - } - - // update a lut entry with a new index - void update_mh_idx( int lut_idx, int mh_idx ) { - n_write++; - lut_data[lut_idx].maxheap_idx = mh_idx; - } - - // lookup an entry with a pc - int lookup( address_type pc ) { - int i; - int lut_idx = -1; - int set_start_idx = get_set(pc) * assoc; - - // look for the matched entry within the set - for (i = set_start_idx; i < (set_start_idx + assoc); i++) { - if (lut_data[i].pc == pc) { - lut_idx = i; - } - } - - // update lru stack if hit - if (lut_idx != -1) { - int set_idx = set_start_idx / assoc; - list<int>::iterator it; - it = find(lru_stack[set_idx].begin(), lru_stack[set_idx].end(), lut_idx); - - if (it != lru_stack[set_idx].end()) { - lru_stack[set_idx].erase(it); - lru_stack[set_idx].push_back(lut_idx); - } - } - - return lut_idx; - } - - void free(int lut_idx) { - set(lut_idx, clean_entry); - - int set_idx = lut_idx / assoc; - list<int>::iterator it; - it = find(lru_stack[set_idx].begin(), lru_stack[set_idx].end(), lut_idx); - - if (it != lru_stack[set_idx].end()) { - lru_stack[set_idx].erase(it); - lru_stack[set_idx].push_front(lut_idx); - } - } - - // find the LRU entry to be replaced - int find_lru( maxheap_lut_entry_t lut_entry ) { - int set_idx = get_set(lut_entry.pc); - int lru_idx = lru_stack[set_idx].front(); - - return lru_idx; - } - - // actually replacing the LRU entry - int replace_lru( maxheap_lut_entry_t lut_entry ) { - int set_idx = get_set(lut_entry.pc); - int lru_idx = lru_stack[set_idx].front(); - lru_stack[set_idx].pop_front(); - - // counting the number of overwritten entries - if (lut_data[lru_idx].maxheap_idx != 0) n_aliased++; - - set(lru_idx, lut_entry); - lru_stack[set_idx].push_back(lru_idx); - - return lru_idx; - } - - // reset the number of accesses to zero - void reset_access( ) { - n_read = 0; - n_write = 0; - } - - // clear the number of accesses - done at the end of scheduler cycle - void clear_access( ) { - n_read -= n_read_per_cycle; - n_read = (n_read >= 0)? n_read : 0; - n_write -= n_write_per_cycle; - n_write = (n_write >= 0)? n_write : 0; - } - - // test if the structure is done with all the required accesses - int all_access_done( ) { - return(n_read == 0 && n_write == 0); - } - - void print_lut_e(FILE *fout, maxheap_lut_entry_t lut_e) { - fprintf(fout, "[%08x]mh%02d", - lut_e.pc, lut_e.maxheap_idx); - } - - void print(FILE *fout) { - int i, j; - for (i=0; i<n_set; i++) { - fprintf(fout, "S%02d", i); - for (j=0; j<assoc; j++) { - fprintf(fout, " |%02d:", i * assoc + j); - print_lut_e(fout, lut_data[i * assoc + j]); - } - fprintf(fout, " "); - list<int>::iterator it = lru_stack[i].begin(); - for (; it != lru_stack[i].end(); it++) { - fprintf(fout, "%02d-", *it); - } - fprintf(fout, "\n"); - } - } - -private: - - inline int get_set(address_type pc) { - return((pc >> insn_size_lgb2) & (n_set - 1)); - } -}; - -maxheap_lut_entry_t mh_lut_class::clean_entry = {0xDEADBEEF, 0}; - -// A class tracking the number of accesses done to the maxheap structure -// and the index ranges from 1..n_entries with 1 being the root -class maxheap_class { -private: - - maxheap_entry_t *maxheap_data; - mh_lut_class *lut; - -public: - - int n_read; - int n_write; - int n_entries; - int size; - int n_read_per_cycle; - int n_write_per_cycle; - - int max_n_entries; - static maxheap_entry_t clean_entry; - - maxheap_class( int size, mh_lut_class *lut, int n_read_per_cycle, int n_write_per_cycle ) { - n_read = 0; - n_write = 0; - n_entries = 0; // index to the last element - this->size = size; - maxheap_data = new maxheap_entry_t[size]; - - for (int i=0; i<size; i++) { - maxheap_data[i] = clean_entry; - } - - this->lut = lut; - - this->n_read_per_cycle = n_read_per_cycle; - this->n_write_per_cycle = n_write_per_cycle; - this->n_read = 0; - this->n_write = 0; - this->max_n_entries = 0; - } - - ~maxheap_class( ) { - delete[] maxheap_data; - } - - // insert a new entry into the maxheap - // return: the index to the new entry - int insert( maxheap_entry_t mh_entry ) { - assert(n_entries + 1 < size); - n_write++; - n_entries++; - maxheap_data[n_entries] = mh_entry; - max_n_entries = (max_n_entries >= n_entries)? max_n_entries : n_entries; - return n_entries; - } - - // retrieve the max heap entry at index [mh_idx] - maxheap_entry_t get( int mh_idx ) { - assert(mh_idx > 0); - assert(mh_idx <= n_entries); - n_read++; - return maxheap_data[mh_idx]; - } - - // replace the max heap entry at index [mh_idx] - void set( int mh_idx, maxheap_entry_t mh_entry ) { - assert(mh_idx > 0); - assert(mh_idx <= n_entries); - n_write++; - maxheap_data[mh_idx] = mh_entry; - } - - // a special version of set that only reset the lut_idx - void remove_lut_idx( int mh_idx ) { - assert(mh_idx > 0); - assert(mh_idx <= n_entries); - n_write++; - maxheap_data[mh_idx].lut_idx = -1; - } - - // read both childrens of a given node, count as one read - // return the number of child read - int get_childof(int mh_idx, maxheap_entry_t *child) { - int child_idx = childof(mh_idx); - int child_read = 0; - - if (child_idx <= n_entries) { - n_read++; - child[0] = maxheap_data[child_idx]; - child_read++; - } - if (child_idx + 1 <= n_entries) { - child[1] = maxheap_data[child_idx + 1]; - child_read++; - } - - return child_read; - } - - // pop the root entry of max heap - maxheap_entry_t pop_root( ) { - maxheap_entry_t old_root = get(1); - maxheap_entry_t curr_mhe[3]; - curr_mhe[0] = get(n_entries); - - set(1, curr_mhe[0]); - if (curr_mhe[0].lut_idx >= 0) - lut->update_mh_idx(curr_mhe[0].lut_idx, 1); - - n_entries--; - - int curr_node = 1; - int n_child = 0; - - n_child = get_childof(curr_node, curr_mhe + 1); - while (n_child > 0) { - int max_child = 0; - int i; - for (i = 1; i < n_child + 1; i++) { - if (cmp_mh(curr_mhe[i], curr_mhe[max_child])) { - max_child = i; - } - } - - n_child = 0; - if (max_child > 0) { - int max_child_node = childof(curr_node) + max_child - 1; - set(curr_node, curr_mhe[max_child]); - set(max_child_node, curr_mhe[0]); - - // update the lut for this swap - if (curr_mhe[max_child].lut_idx >= 0) - lut->update_mh_idx(curr_mhe[max_child].lut_idx, curr_node); - if (curr_mhe[0].lut_idx >= 0) - lut->update_mh_idx(curr_mhe[0].lut_idx, max_child_node); - - // get the next child - curr_node = max_child_node; - n_child = get_childof(curr_node, curr_mhe + 1); - } - } - - return old_root; - } - - // probe if the maxheap is empty - int empty( ) { - return(n_entries == 0); - } - - // reset the number of accesses to zero - void reset_access( ) { - n_read = 0; - n_write = 0; - } - - // clear the number of accesses - done at the end of scheduler cycle - void clear_access( ) { - n_read -= n_read_per_cycle; - n_read = (n_read >= 0)? n_read : 0; - n_write -= n_write_per_cycle; - n_write = (n_write >= 0)? n_write : 0; - } - - // test if the structure is done with all the required accesses - int all_access_done( ) { - return(n_read == 0 && n_write == 0); - } - - // sort the max heap again starting from start_idx - // (this entry can only go up in the tree to the root) - void sort_bottomup(int start_idx) { - maxheap_entry_t mh_entry; - maxheap_entry_t mh_parent; - - if (start_idx == 1) return; // no need to resort if the root is incremented - - int curr_idx = start_idx; - int parent_idx = parentof(start_idx); - - int continue_sort = 1; - while (curr_idx > 1 && continue_sort) { - mh_entry = get(curr_idx); - mh_parent = get(parent_idx); - - // swap the entries if it is now larger than it's parent - if (cmp_mh(mh_entry, mh_parent)) { - set(parent_idx, mh_entry); - set(curr_idx, mh_parent); - - // update the lut for this swap - if (mh_entry.lut_idx >= 0) - lut->update_mh_idx(mh_entry.lut_idx, parent_idx); - if (mh_parent.lut_idx >= 0) - lut->update_mh_idx(mh_parent.lut_idx, curr_idx); - - // update index for next iteration - curr_idx = parent_idx; - parent_idx = parentof(curr_idx); - } else { - // swap did not happen, no need to sort anymore - continue_sort = 0; - } - } - } - - void print_mh_e(FILE *fout, maxheap_entry_t mh_e) { - fprintf(fout, "[%08x]%03d(H%03dT%03d)p%02d | ", - mh_e.pc, mh_e.n_thds, mh_e.wpool_head, mh_e.wpool_tail, mh_e.lut_idx); - } - - void print(FILE *fout) { - fprintf(fout, "MaxHeap: "); - fprintf(fout, "N_entries = %d\n", n_entries); - for (int i=0; i<n_entries; i++) { - print_mh_e(fout, maxheap_data[i + 1]); - if (!((i + 2) & (i + 1))) fprintf(fout, "\n"); - } - fprintf(fout, "\n"); - } - -private: - - static inline int parentof(int mh_idx) { - assert(mh_idx > 0); - return(mh_idx / 2); - } - - static inline int childof(int mh_idx) { - return(mh_idx * 2); - } - - static inline int cmp_mh(maxheap_entry_t &a, maxheap_entry_t &b) { - if (a.n_thds > b.n_thds) return 1; - if (a.n_thds == b.n_thds) { - if (a.pc < b.pc) return 1; - } - return 0; - } - -}; - -maxheap_entry_t maxheap_class::clean_entry = {0, 0, -1, -1, -1}; - -typedef struct mh_update_struct { - int n_maxheap_read; - int n_maxheap_write; - int n_mhlut_read; - int n_mhlut_write; -} mh_update; - -// heap implementation of majority policy -class issue_warp_majority_heap : public issue_warp_majority { -public: - - mh_lut_class mh_lut; - maxheap_class maxheap; - - maxheap_lut_entry_t major_lut_e; - maxheap_entry_t major_mh_e; - - vector<warp_entry_t> *warp_pool; - int simd_width; - - int n_stall_on_maxheap; - - queue<mh_update> update_queue; - static pow2_histogram n_pending_updates_histo; - - issue_warp_majority_heap (int simd_width = 0, vector<warp_entry_t> *bp = NULL, - int lut_size = 32, int lut_assoc = 4, int maxheap_size = 128, - int n_read_lut = 4, int n_write_lut = 4, - int n_read_mh = 4, int n_write_mh = 4) - : mh_lut(lut_size, lut_assoc, n_read_lut, n_write_lut), - maxheap(maxheap_size, &mh_lut, n_read_mh, n_write_mh) - { - this->simd_width = simd_width; - this->warp_pool = bp; - - this->major_lut_e = mh_lut_class::clean_entry; - this->major_mh_e = maxheap_class::clean_entry; - - this->n_stall_on_maxheap = 0; - } - - // adding more threads to a specify pc - // these threads may end up in different warpes - void add_threads( address_type pc, int *tid) { - int i; - int n_thds = 0; - for (i=0; i<simd_width; i++) { - if (tid[i] >= 0) n_thds++; - } - - // handle special case with adding threads to current majority pc - if (major_lut_e.pc == pc) { - assert(major_mh_e.pc == pc); - major_mh_e.n_thds += n_thds; - return; - } - - maxheap_lut_entry_t lut_e; - maxheap_entry_t mh_entry; - - // snapshot the current maxheap read/write demand - mh_update new_mh_update; - new_mh_update.n_maxheap_read = maxheap.n_read; - new_mh_update.n_maxheap_write = maxheap.n_write; - new_mh_update.n_mhlut_read = mh_lut.n_read; - new_mh_update.n_mhlut_write = mh_lut.n_write; - - int lut_idx = mh_lut.lookup(pc); - - int sort_from_idx = 0; - - if (lut_idx >= 0) { - // obtain the entry - lut_e = mh_lut.get(lut_idx); - - // get the maxheap entry and update its number of threads - mh_entry = maxheap.get(lut_e.maxheap_idx); - mh_entry.n_thds += n_thds; - maxheap.set(lut_e.maxheap_idx, mh_entry); - - // sort from this specific entry - sort_from_idx = lut_e.maxheap_idx; - } else { - // create a new lut entry - lut_e = mh_lut_class::clean_entry; - lut_e.pc = pc; - - // get index to the LRU lut entry in this set - lut_idx = mh_lut.find_lru(lut_e); - - // get the replaced lut entry and remove its link with the maxheap entry - maxheap_lut_entry_t lut_old = mh_lut.get(lut_idx); - if (lut_old.maxheap_idx > 0) maxheap.remove_lut_idx(lut_old.maxheap_idx); - - // create a new maxheap entry - mh_entry = maxheap_class::clean_entry; - mh_entry.pc = pc; - mh_entry.n_thds = n_thds; - mh_entry.lut_idx = lut_idx; - - // push the new entry into the maxheap and lut respectively - lut_e.maxheap_idx = maxheap.insert(mh_entry); - mh_lut.replace_lru(lut_e); - - // start sorting from the bottom? - sort_from_idx = lut_e.maxheap_idx; - } - - maxheap.sort_bottomup(sort_from_idx); - - // record the newly generated maxheap read/write demand from this update - new_mh_update.n_maxheap_read = maxheap.n_read - new_mh_update.n_maxheap_read; - new_mh_update.n_maxheap_write = maxheap.n_write - new_mh_update.n_maxheap_write; - new_mh_update.n_mhlut_read = mh_lut.n_read - new_mh_update.n_mhlut_read; - new_mh_update.n_mhlut_write = mh_lut.n_write - new_mh_update.n_mhlut_write; - - update_queue.push(new_mh_update); - } - - // call this when a new warp allocated for a specific pc - void push_warp( address_type pc, int idx) { - maxheap_entry_t *p_mh_e = NULL; - maxheap_entry_t mh_e; - maxheap_lut_entry_t lut_e = mh_lut_class::clean_entry; - int lut_idx = -1; - - if (major_mh_e.pc == pc) { - p_mh_e = &major_mh_e; - } else { - lut_idx = mh_lut.lookup(pc); - assert(lut_idx >= 0); // if it is a miss, a new entry should have been created already - lut_e = mh_lut.get(lut_idx); - mh_e = maxheap.get(lut_e.maxheap_idx); - p_mh_e = &mh_e; - - // discounting these 'gets' - // because they should be combined with the 'gets' in add_threads() - mh_lut.n_read--; - maxheap.n_read--; - } - - if (p_mh_e->wpool_head == -1) { - p_mh_e->wpool_head = idx; - p_mh_e->wpool_tail = idx; - } else { - (*warp_pool)[p_mh_e->wpool_tail].next_warp = idx; - p_mh_e->wpool_tail = idx; - } - - if (major_mh_e.pc == pc) { - } else { - maxheap.set(lut_e.maxheap_idx, mh_e); - // discounting this 'set' - // because it should be combined with the 'set' in add_threads() - maxheap.n_write--; - } - } - - // obtain a warp index from this issue logic - int pop_warp( ) { - int bidx = -1; - if (major_mh_e.wpool_head == -1 && !maxheap.empty()) { - if (this->all_access_done( )) { - // pop the majority PC from max heap - major_mh_e = maxheap.pop_root(); - - // pop its corresponding entry from the lut as well (if it exists) - if (major_mh_e.lut_idx >= 0) { - major_lut_e = mh_lut.get(major_mh_e.lut_idx); - mh_lut.free(major_mh_e.lut_idx); - } else { - major_lut_e = mh_lut_class::clean_entry; - } - } else { - n_stall_on_maxheap += 1; - bidx = -1; - return bidx; - } - } - - // just pop and entry to from the virtual queue (and set the head pointer to next warp) - bidx = major_mh_e.wpool_head; - if (bidx >= 0) { - major_mh_e.wpool_head = (*warp_pool)[major_mh_e.wpool_head].next_warp; - } - - return bidx; - } - - void reset_access( ) { - maxheap.reset_access(); - mh_lut.reset_access(); - - while (!update_queue.empty()) { - update_queue.pop(); - } - } - - inline void consume_access( int &req_acc, int &avl_acc) { - if (req_acc > avl_acc) { - req_acc -= avl_acc; - avl_acc = 0; - } else { - avl_acc -= req_acc; - req_acc = 0; - } - } - - void clear_access( ) { - maxheap.clear_access(); - mh_lut.clear_access(); - - int n_maxheap_read_bw = maxheap.n_read_per_cycle; - int n_maxheap_write_bw = maxheap.n_write_per_cycle; - int n_mhlut_read_bw = mh_lut.n_read_per_cycle; - int n_mhlut_write_bw = mh_lut.n_write_per_cycle; - - while ((n_maxheap_read_bw > 0 || n_maxheap_read_bw > 0 || - n_mhlut_read_bw > 0 || n_mhlut_write_bw > 0) && !update_queue.empty()) { - mh_update &c_update = update_queue.front(); - - consume_access (c_update.n_maxheap_read, n_maxheap_read_bw); - consume_access (c_update.n_maxheap_write, n_maxheap_write_bw); - consume_access (c_update.n_mhlut_read, n_mhlut_read_bw); - consume_access (c_update.n_mhlut_write, n_mhlut_write_bw); - - if (c_update.n_maxheap_read == 0 && c_update.n_maxheap_write == 0 && - c_update.n_mhlut_read == 0 && c_update.n_mhlut_write == 0) { - update_queue.pop(); - } else { - break; - } - } - - n_pending_updates_histo.add2bin(update_queue.size()); - } - - void print( FILE *fout ) { - fprintf(fout, "LUT: "); - mh_lut.print_lut_e(fout, major_lut_e); - fprintf(fout, " \tMH: "); - maxheap.print_mh_e(fout, major_mh_e); - fprintf(fout, "\n"); - mh_lut.print(fout); - maxheap.print(fout); - } - - static void print_stat( FILE *fout) { - fprintf(fout, "n_pending_maxheap_updates = "); - n_pending_updates_histo.fprint(fout); - fprintf(fout, "\n"); - } - -private: - - int all_access_done( ) { - return(maxheap.all_access_done() && mh_lut.all_access_done()); - - } -}; -pow2_histogram issue_warp_majority_heap::n_pending_updates_histo; - -class warp_queue { -public: - int m_pc; - int n_thds; - int simd_width; - deque<int> idx_queue; - - warp_queue( address_type pc, int simd_width) { - this->m_pc = pc; - this->n_thds = 0; - this->simd_width = simd_width; - } - - // called right after a lut_entry is looked up - void add_threads( int *tid ) { - for (int i=0; i<simd_width; i++) { - if (tid[i] >= 0) this->n_thds++; - } - } - - // called right after a warp is issued - void sub_threads( int *tid ) { - for (int i=0; i<simd_width; i++) { - if (tid[i] >= 0) this->n_thds--; - } - } - - // if other warp queue should be ahead - bool operator<(const warp_queue& other) const { - if (n_thds == other.n_thds) { - return(m_pc > other.m_pc); // smaller pc first - } else { - return(n_thds < other.n_thds); - } - } - bool operator>(const warp_queue& other) const { - if (n_thds == other.n_thds) { - return(m_pc > other.m_pc); // smaller pc first - } else { - return(n_thds > other.n_thds); - } - } - - void print( FILE *fout ) { - fprintf(fout, "0x%08x(%03d)=[", m_pc, n_thds); - deque<int>::iterator dit = idx_queue.begin(); - for (; dit != idx_queue.end(); dit++) { - fprintf(fout, "%03d ", *dit); - } - fprintf(fout, "]\n"); - } -}; - -bool minor_warp( const warp_queue* a, const warp_queue* b ) { - return(*a<*b); -} - -// queue implementation of majority scheduling policy -class issue_warp_majority_queue : public issue_warp_majority { -public: - map<address_type, warp_queue* > majority_map; - set<warp_queue*> warpq_set; - warp_queue* maj_warp; - - vector<warp_entry_t> *warp_pool; - int simd_width; - - issue_warp_majority_queue(int simd_width = 0, vector<warp_entry_t> *bp = NULL) { - this->maj_warp = NULL; - this->simd_width = simd_width; - this->warp_pool = bp; - } - - // adding more threads to a specify pc - // these threads may end up in different warps - void add_threads( address_type pc, int *tid) { - warp_queue* bq = majority_map[pc]; - if (bq == NULL) { - bq = new warp_queue(pc,simd_width); - warpq_set.insert(bq); - majority_map[pc] = bq; - } - bq->add_threads(tid); - } - - // call this when a new warp allocated for a specific pc - void push_warp( address_type pc, int idx) { - warp_queue* bq = majority_map[pc]; - assert(bq != NULL); - bool check_redundant_idx = false; - if (check_redundant_idx) { - deque<int>::iterator dit = find(bq->idx_queue.begin(), bq->idx_queue.end(), idx); - assert(dit == bq->idx_queue.end()); - } - bq->idx_queue.push_back(idx); - } - - // obtain a warp index from this issue logic - int pop_warp( ) { - int bidx = -1; - - // find the new majority pc if it didn't exist - if (maj_warp == NULL && warpq_set.size()) { - maj_warp = *max_element(warpq_set.begin(), warpq_set.end(), minor_warp); - } - - // if a majority pc indeed exist - if (maj_warp) { - assert(!maj_warp->idx_queue.empty()); - bidx = maj_warp->idx_queue.front(); - maj_warp->idx_queue.pop_front(); - maj_warp->sub_threads((*warp_pool)[bidx].tid); - - // when the majority pc runs out of thread - if (maj_warp->n_thds == 0) { - // remove that warp queue - warpq_set.erase(maj_warp); - majority_map.erase(maj_warp->m_pc); - delete maj_warp; - maj_warp = NULL; - } - } - - return bidx; - } - - void print( FILE *fout ) { - fprintf(fout, "issue_warp_majority:\n"); - set<warp_queue*>::iterator dit = warpq_set.begin(); - for (; dit != warpq_set.end(); dit++) { - fprintf(fout, " %c ", ((*dit)==maj_warp)? 'M':' '); - (*dit)->print(fout); - } - } - - void check_consistency( ) { - set<warp_queue*>::iterator set_it = warpq_set.begin(); - for (; set_it != warpq_set.end(); set_it++) { - warp_queue* bq = (*set_it); - - int real_nthds = 0; - deque<int>::iterator dit = bq->idx_queue.begin(); - for (; dit != bq->idx_queue.end(); dit++) { - int *tid = (*warp_pool)[*dit].tid; - for (int i = 0; i < simd_width; i++) { - real_nthds += (tid[i] >= 0)? 1 : 0; - } - } - - assert(real_nthds == bq->n_thds); - } - } -}; - -// pdom priority -class lesspdom_first { -public: - vector<warp_entry_t> *warp_pool; - lesspdom_first( vector<warp_entry_t> *bp=NULL ) { - this->warp_pool = bp; - } - bool operator() (const int &idx_a, const int &idx_b) const { - if ((*warp_pool)[idx_a].pdom_prio != (*warp_pool)[idx_b].pdom_prio) { - return((*warp_pool)[idx_a].pdom_prio < (*warp_pool)[idx_b].pdom_prio); - } else { - return((*warp_pool)[idx_a].occ > (*warp_pool)[idx_b].occ); - } - } -}; - - -class issue_warp_pdom_prio { -public: - vector<warp_entry_t> *warp_pool; - int* thd_pdom_prio; - int simd_width; - int n_threads; - - int resort_needed; - list<int> pdom_pqueue; //the queue holding all index - - lesspdom_first lesspdom_cmp; - - static set<address_type> reconvgence_pt; //table holding all recvg pt - - issue_warp_pdom_prio (int simd_width = 0, vector<warp_entry_t> *bp = NULL, - int n_threads = 0) - : lesspdom_cmp(bp) - { - this->simd_width = simd_width; - this->warp_pool = bp; - this->n_threads = n_threads; - this->thd_pdom_prio = new int[n_threads]; - memset(this->thd_pdom_prio, 0, sizeof(int)*n_threads); - this->resort_needed = 0; - } - - ~issue_warp_pdom_prio( ) { - delete[] this->thd_pdom_prio; - } - - void reinit( ) { - memset(this->thd_pdom_prio, 0, sizeof(int)*n_threads); - } - - // adding more threads to a warp - void add_threads( int idx, address_type pc) { - assert((*warp_pool)[idx].pc == pc); - - // check to see if this is a newly allocated warp - bool check_pdom = false; - if ((*warp_pool)[idx].pdom_prio == -1) { - check_pdom = true; - } - - // check for newly assigned threads to the warp - int pdom_occ = (*warp_pool)[idx].pdom_occ; - int *tid = (*warp_pool)[idx].tid; - for (int i=0; i<simd_width; i++) { - if (tid[i] >= 0 && !(pdom_occ & (1<<i))) { - if ((*warp_pool)[idx].pdom_prio < thd_pdom_prio[tid[i]]) { - (*warp_pool)[idx].pdom_prio = thd_pdom_prio[tid[i]]; - resort_needed = 1; - } - pdom_occ |= (1<<i); - } - } - if (check_pdom) { - if (reconvgence_pt.find(pc) != reconvgence_pt.end()) { - (*warp_pool)[idx].pdom_prio += 1; - } - } - } - - // call this when a new warp allocated for a specific pc - void push_warp( address_type pc, int idx ) { - assert((*warp_pool)[idx].pc == pc); - // initialize the pdom_prio for this newly allocated warp - (*warp_pool)[idx].pdom_prio = -1; - (*warp_pool)[idx].pdom_occ = 0; - pdom_pqueue.push_back(idx); - } - - // obtain a warp index from this issue logic - int front_warp( ) { - int bidx = -1; - - if (!pdom_pqueue.empty()) { - if (resort_needed) { - pdom_pqueue.sort(lesspdom_cmp); - resort_needed = 0; - } - - bidx = pdom_pqueue.front(); - } - - return bidx; - } - - int size( ) { - return pdom_pqueue.size(); - } - - void enforce_resort( ) { - resort_needed = 1; - } - - int pop_warp( ) { - int bidx = -1; - - if (!pdom_pqueue.empty()) { - if (resort_needed) { - pdom_pqueue.sort(lesspdom_cmp); - resort_needed = 0; - } - - bidx = pdom_pqueue.front(); - pdom_pqueue.pop_front(); - - // update the pdom prio of each thread inside a warp - for (int i=0; i<simd_width; i++) { - if ((*warp_pool)[bidx].tid[i] >= 0) { - thd_pdom_prio[(*warp_pool)[bidx].tid[i]] = (*warp_pool)[bidx].pdom_prio; - } - } - } - - return bidx; - } - -}; - -set<address_type> issue_warp_pdom_prio::reconvgence_pt = set<address_type>(); -//*/ - - -class npc_tracker_class { -public: - map<address_type, unsigned> pc_count; - unsigned* acc_pc_count; - int simd_width; - static map<unsigned, unsigned> histogram; - - npc_tracker_class( ) { - this->acc_pc_count = NULL; - this->simd_width = 0; - } - - npc_tracker_class(unsigned* acc_pc_count, int simd_width) { - this->acc_pc_count = acc_pc_count; - this->simd_width = simd_width; - } - - void add_threads( int *tid, address_type pc ) { - for (int i=0; i<simd_width; i++) { - if (tid[i] != -1) pc_count[pc] += 1; // automatically create a new entry if not exist - } - } - - void sub_threads( int *tid, address_type pc ) { - for (int i=0; i<simd_width; i++) { - if (tid[i] != -1) { - pc_count[pc] -= 1; - assert((int)pc_count[pc] >= 0); - if (pc_count[pc] == 0) pc_count.erase(pc); // manually erasing entries with 0 count - } - } - } - - void update_acc_count( ) { - (*acc_pc_count) += pc_count.size(); - histogram[pc_count.size()] += 1; - } - - unsigned count( ) { return pc_count.size();} - - static void histo_print( FILE* fout ) { - map<unsigned, unsigned>::iterator i; - fprintf(fout, "DYHW nPC Histogram: "); - for (i = histogram.begin(); i != histogram.end(); i++) { - fprintf(fout, "%d:%d ", i->first, i->second); - } - fprintf(fout, "\n"); - } -}; - -map<unsigned, unsigned> npc_tracker_class::histogram; - -class pc_tag { -private: - - address_type m_pc; - -public: - - pc_tag () { - this->reset(); - } - - pc_tag (const pc_tag& p) { this->m_pc = p.m_pc;} - pc_tag (const address_type& other_pc) { this->m_pc = other_pc;} - - pc_tag& operator=(const pc_tag& p) { m_pc = p.m_pc; return *this;} - pc_tag& operator=(const address_type& other_pc) { m_pc = other_pc; return *this;} - - inline bool operator==(const pc_tag& p) const { return(m_pc == p.m_pc);} - inline bool operator==(const address_type& other_pc) const { return(m_pc == other_pc);} - - inline bool operator!=(const pc_tag& p) const { return(m_pc != p.m_pc);} - inline bool operator!=(const address_type& other_pc) const { return(m_pc != other_pc);} - - inline bool operator<(const pc_tag& p) const { return(m_pc < p.m_pc);} - - inline void reset() { - m_pc = -1; - } - - inline address_type get_pc() const { return m_pc;} - - // the hash function to warp LUT - inline unsigned lut_hash( int insn_size_lgb2, int lut_nsets ) const { - return(m_pc >> insn_size_lgb2) & (lut_nsets - 1); - } - - inline void to_print(char *buffer, unsigned length) { - snprintf(buffer, length, "0x%08x", m_pc); - } -}; - -template <class Tag> -class tag2warp_entry_t { -public: - - Tag tag; - int idx; // pointing to warp pool - int occ; // occupancy vector - int accessed; // is the entry accessed this cycle - - tag2warp_entry_t () { - this->reset(); - } - - ~tag2warp_entry_t () {} - - tag2warp_entry_t (const tag2warp_entry_t& p) { - this->tag = p.tag; - this->idx = p.idx; - this->occ = p.occ; - this->accessed = p.accessed; - } - - tag2warp_entry_t& operator=(const tag2warp_entry_t& p) { - if (this != &p) { - tag = p.tag; - idx = p.idx; - occ = p.occ; - accessed = p.accessed; - } - return *this; - } - - inline bool operator==(const tag2warp_entry_t& p) const { - return(tag == p.tag); - } - - inline bool operator==(const Tag& test_tag) const { - return(tag == test_tag); - } - - inline bool operator()(const tag2warp_entry_t& p) const { - return(tag == p.tag); - } - - inline void reset() { - tag.reset(); - idx = 0; - occ = 0; - accessed = 0; - } - - void print( FILE *fout ) { - static char buffer[20]; - tag.to_print(buffer,20); - fprintf(fout, "\t%s->%03d (%02x)\n", buffer, idx, occ); - } - -}; - -template <class Tag> -class tag2warp_set { -public: - vector< tag2warp_entry_t<Tag> > entry; - list< tag2warp_entry_t<Tag>* > lru_stack; - - tag2warp_set(int assoc = 0) : entry(assoc) { - for (unsigned j=0; j<this->entry.size(); j++) { - this->lru_stack.push_back(&(this->entry[j])); - } - } - - tag2warp_set(const tag2warp_set& other) : entry(other.entry.size()) { - for (unsigned j=0; j<this->entry.size(); j++) { - this->lru_stack.push_back(&(this->entry[j])); - } - } - - tag2warp_set& operator=(const tag2warp_set& p) { - printf("tag2warp_set assignment operator called!\n"); - return *this; - } - - ~tag2warp_set() {} -}; - -template <class Tag> -class warp_lut { -public: - virtual ~warp_lut() {} - virtual tag2warp_entry_t<Tag>* lookup_pc2warp( const Tag& tag, bool& lut_missed ) = 0; - virtual void invalidate_entry( tag2warp_entry_t<Tag>* lut_entry, int warp_idx ) = 0; - virtual void clear_accessed( ) = 0; - virtual void print( FILE* fout) = 0; -}; - -template <class Tag> -class warp_lut_sa : public warp_lut<Tag> { -private: - int lut_size; - int lut_assoc; - vector< tag2warp_set<Tag> > tag2warp_lut; - int insn_size_lgb2; - - queue< tag2warp_entry_t<Tag>* > lut_accessed_q; // store accessed lut entry for clear - - struct same_tag { - Tag tag; - bool operator()(tag2warp_entry_t<Tag>* a) { - return(a->tag == tag); - } - }; - - static unsigned int lut_aliased; - -public: - warp_lut_sa(int lut_size, int lut_assoc, int insn_size) { - this->lut_size = lut_size; - this->lut_assoc = lut_assoc; - - // optimize for LUT hash function - insn_size_lgb2 = 0; - while ( (1 << insn_size_lgb2) < insn_size ) insn_size_lgb2++; - - // initialize the pc2warp LUT - // note: lut_size is the absolute size of LUT regardless of assoc. - this->tag2warp_lut.assign(lut_size/lut_assoc, tag2warp_set<Tag>(lut_assoc)); - - // assert on #set in LUT to be power of 2 - int lut_nset_pow2 = 1; - while ( lut_nset_pow2 < (int)tag2warp_lut.size() ) lut_nset_pow2 <<= 1; - assert((int)tag2warp_lut.size() == lut_nset_pow2); - } - - tag2warp_entry_t<Tag>* lookup_pc2warp( const Tag& tag, bool& lut_missed ); - void invalidate_entry( tag2warp_entry_t<Tag>* lut_entry, int warp_idx ) { - if (lut_entry != NULL) { // check for warp lut entry invalidation - if (lut_entry->idx == warp_idx) { - lut_entry->reset(); - } - } - } - - void clear_accessed( ); - - void print( FILE* fout) { - for (unsigned i=0; i< tag2warp_lut.size(); i++) { - for (unsigned j=0; j< tag2warp_lut[i].entry.size(); j++) { - fprintf(fout, "lut%03d-%02d:", i, j); - tag2warp_lut[i].entry[j].print(fout); - } - } - } - - static void print_stats ( FILE* fout ) { - fprintf( fout, "lut_aliased = %d\n", lut_aliased); - } -}; -template <class Tag> unsigned int warp_lut_sa<Tag>::lut_aliased = 0; - - -// lookup function in LUT -// may return an entry that has different PC for replacement -// or return a NULL pointer to indicate that the entry is accessed by another port -template <class Tag> -tag2warp_entry_t<Tag>* warp_lut_sa<Tag>::lookup_pc2warp( const Tag &tag, bool &lut_missed ) -{ - tag2warp_entry_t<Tag>* lut_entry = NULL; - unsigned hashed_pc = tag.lut_hash(insn_size_lgb2, tag2warp_lut.size()); - list< tag2warp_entry_t<Tag>* > &hashed_lru_stack = tag2warp_lut.at(hashed_pc).lru_stack; - struct same_tag same_tag_f; - - same_tag_f.tag = tag; - typename list< tag2warp_entry_t<Tag>* >::iterator lut_it; - lut_it = find_if(hashed_lru_stack.begin(), - hashed_lru_stack.end(), - same_tag_f); - if (lut_it != hashed_lru_stack.end()) { - lut_entry = *lut_it; - lut_entry->accessed = 1; - lut_accessed_q.push(lut_entry); - hashed_lru_stack.splice(hashed_lru_stack.end(), hashed_lru_stack, lut_it); - assert(lut_entry == hashed_lru_stack.back()); - lut_missed = false; - } else { - assert(!hashed_lru_stack.empty()); - lut_entry = hashed_lru_stack.front(); - if (lut_entry->accessed) { - lut_entry = NULL; - } else { - lut_entry->accessed = 1; - lut_accessed_q.push(lut_entry); - hashed_lru_stack.splice(hashed_lru_stack.end(), hashed_lru_stack, hashed_lru_stack.begin()); - assert(lut_entry == hashed_lru_stack.back()); - lut_aliased++; - } - lut_missed = true; - } - assert(hashed_lru_stack.size() == tag2warp_lut[hashed_pc].entry.size()); - - return lut_entry; -} - -template <class Tag> -void warp_lut_sa<Tag>::clear_accessed( ) { - while ( !lut_accessed_q.empty() ) { - lut_accessed_q.front()->accessed = 0; - lut_accessed_q.pop(); - } -} - -// a perfect warp lut that never misses. -template <class Tag> -class warp_lut_perfect : public warp_lut<Tag> { -private: - typedef map< Tag, tag2warp_entry_t<Tag>* > warp_map_t; - warp_map_t m_tag2entry_map; - - static unsigned int lut_max_size; -public: - warp_lut_perfect() {} - ~warp_lut_perfect() { - typename warp_map_t::iterator mit = m_tag2entry_map.begin(); - for (; mit != m_tag2entry_map.end(); mit++) { - delete mit->second; - } - } - - // idealistic implementation of lookup: the entry is never aliased, - // and a new one is created automatically if it does not exist - tag2warp_entry_t<Tag>* lookup_pc2warp( const Tag& tag, bool& lut_missed ) { - typename warp_map_t::iterator mit = m_tag2entry_map.find(tag); - - tag2warp_entry_t<Tag>* lut_entry = NULL; - if (mit != m_tag2entry_map.end()) { - lut_entry = mit->second; - assert(lut_entry->tag == tag); - } else { - lut_entry = new tag2warp_entry_t<Tag>(); - m_tag2entry_map.insert(make_pair(tag, lut_entry)); - } - - lut_missed = false; - lut_max_size = (lut_max_size < m_tag2entry_map.size())? m_tag2entry_map.size() : lut_max_size; - - return lut_entry; - } - - void invalidate_entry( tag2warp_entry_t<Tag>* lut_entry, int warp_idx ) { - if (lut_entry == NULL) return; - if (lut_entry->idx != warp_idx) return; - - typename warp_map_t::iterator mit = m_tag2entry_map.find(lut_entry->tag); - if (mit != m_tag2entry_map.end()) { - assert(mit->second == lut_entry); - mit->second->reset(); - delete mit->second; - m_tag2entry_map.erase(mit); - } - } - - void clear_accessed( ) {} - - void print( FILE* fout) { - typename warp_map_t::iterator mit = m_tag2entry_map.begin(); - for (; mit != m_tag2entry_map.end(); mit++) { - mit->second->print(fout); - } - } - - static void print_stats ( FILE* fout ) { - fprintf( fout, "lut_max_size = %d\n", lut_max_size); - } -}; -template <class Tag> unsigned int warp_lut_perfect<Tag>::lut_max_size = 0; - - -typedef tag2warp_entry_t<pc_tag> warplut_entry_t; -typedef pc_tag warp_tag_t; - -class dwf_hw_sche_class { -public: - int m_id; - warp_lut<pc_tag> *warp_lut_pc; - vector<warp_entry_t> warp_pool; - deque<int> free_warp_q; // the warp allocator - int simd_width; - int regf_width; - int insn_size_lgb2; - bool just_resume; - - vector<char> m_req; // request vector from incoming warp - vector<char> m_occ_new; // occupancy vector of the new warp, double as conflict vector - vector<char> m_occ_upd; // occupancy vector of the updated existing warp - vector<char> m_occ_ext; // occupancy vector of the existing warp - - dwf_hw_sche_class( int lut_size, int lut_assoc, - int simd_width, int regf_width, - int n_threads, int insn_size, - int heuristic, int id, - char *policy_opt = NULL ); - ~dwf_hw_sche_class(); - - warplut_entry_t* lookup_pc2warp( const warp_tag_t& lookup_tag ); - int update_warp( int* tid, address_type pc ); - - // barrier handling - int m_nbarriers; - class dwf_barrier { - public: - bool m_release; // see if a barrier is to be released (ie. all warp in cta hit already) - deque<int> m_queue; // queue storing warps currently hitting a barrier, skipping warplut and scheduler - - dwf_barrier() : m_release(false) {} - dwf_barrier(const dwf_barrier& that) - : m_release(that.m_release), m_queue(that.m_queue) {} - bool ready_to_issue() { - return(m_release && !m_queue.empty()); - } - }; - set< int > m_cta_released_barrier; // set of cta with released barrier - map< int, dwf_barrier > m_barrier; // map <barrier id == cta id, barrier> - int update_warp_at_barrier( int* tid, address_type pc, int cta_id, int barrier_num = 0 ); - void hit_barrier( int cta_id, int barrier_num = 0 ); - void release_barrier( int cta_id, int barrier_num = 0 ); - - int allocate_warp( address_type pc, bool update_scheduler = true ); - void free_warp( int idx, bool update_warplut = true ); - - void issue_warp( int *tid, address_type *pc ); - - void clear_accessed( ) { - warp_lut_pc->clear_accessed(); - } - - void init_cta(int start_thread, int cta_size, address_type start_pc); - - void print_pc2warp_lut( FILE *fout ); - void print_warp_pool( FILE *fout ); - void print_free_warp_q( FILE *fout ); - - int heuristic; - - // FIFO warp issue logic - queue<int> issue_warp_FIFO_q; - - // PC warp issue logic - class pc_first { - public: - vector<warp_entry_t> &warp_pool; - pc_first( vector<warp_entry_t> &bp ) : warp_pool(bp) {} - bool operator() (const int &idx_a, const int &idx_b) const { - if (warp_pool[idx_a].pc != warp_pool[idx_b].pc) { - return(warp_pool[idx_a].pc > warp_pool[idx_b].pc); - } else { - return(warp_pool[idx_a].occ < warp_pool[idx_b].occ); - } - } - }; - pc_first mypc_first; - priority_queue<int, vector<int>, pc_first > issue_warp_PC_q; - - // Majority warp issue logic - issue_warp_majority *issue_warp_MAJ; - void clear_policy_access( ); - void reset_policy_access( ); - - // PDOM Priority issue logic - issue_warp_pdom_prio issue_warp_pdom; - - // statistics - npc_tracker_class npc_tracker; - int max_warppool_occ; - int *warppool_occ_histo; // histogram of warppool occupancy - static unsigned int lut_realmiss; - static unsigned int uid_cnt; - static unsigned int warp_fragmentation; - static unsigned int warp_merge_conflict; - static void print_stats ( FILE* fout ) { - warp_lut_perfect<warp_tag_t>::print_stats( fout ); - warp_lut_sa<warp_tag_t>::print_stats( fout ); - fprintf( fout, "lut_realmiss = %d\n", lut_realmiss); - fprintf( fout, "warp_fragmentation = %d\n", warp_fragmentation); - fprintf( fout, "warp_merge_conflict = %d\n", warp_merge_conflict); - } -}; - -unsigned int dwf_hw_sche_class::lut_realmiss = 0; -unsigned int dwf_hw_sche_class::uid_cnt = 0; -unsigned int dwf_hw_sche_class::warp_fragmentation = 0; -unsigned int dwf_hw_sche_class::warp_merge_conflict = 0; - - -dwf_hw_sche_class::dwf_hw_sche_class( int lut_size, int lut_assoc, - int simd_width, int regf_width, - int n_threads, int insn_size, - int heuristic, int id, - char *policy_opt ) -: m_id(id), -// WarpLUT w/ pc tag -warp_lut_pc( (lut_size == 0)? (warp_lut<pc_tag> *) new warp_lut_perfect<pc_tag>() : - (warp_lut<pc_tag> *) new warp_lut_sa<pc_tag>(lut_size, lut_assoc, insn_size) ), -m_nbarriers(1), // for barrier -mypc_first( warp_pool ), issue_warp_PC_q( mypc_first ), // DPC -issue_warp_pdom(simd_width, &warp_pool, n_threads), // DPdPri -npc_tracker( NULL, simd_width ) -{ - unsigned i; - - this->simd_width = simd_width; - this->regf_width = regf_width; - this->m_req.resize(regf_width); - this->m_occ_new.resize(regf_width); - this->m_occ_upd.resize(regf_width); - this->m_occ_ext.resize(regf_width); - - // initialize the warp pool - // (make sure the thread id's are init to -1) - this->warp_pool.resize(n_threads); - for (i=0; i<warp_pool.size(); i++) { - warp_pool[i].pc = -1; - warp_pool[i].tid = new int[simd_width]; - memset(warp_pool[i].tid, -1, sizeof(int)*simd_width); - warp_pool[i].occ = 0; - warp_pool[i].next_warp = -1; - - // push the index to the warp allocator - free_warp_q.push_back(i); - } - - // setup for various heuristics - this->heuristic = heuristic; - switch (heuristic) { - case MAJORITY: - issue_warp_MAJ = new issue_warp_majority_queue(simd_width, &warp_pool); - break; - case MAJORITY_MAXHEAP: { - int mh_lut_size = 32; - int mh_lut_assoc = 4; - int n_reads_per_cycle_lut = 4; - int n_writes_per_cycle_lut = 4; - int mh_size = 128; - int n_reads_per_cycle_mh = 4; - int n_writes_per_cycle_mh = 4; - if (policy_opt != NULL) { - sscanf(policy_opt, ";LUT=%d:%dr%dw%d;MH=%dr%dw%d", - &mh_lut_size, &mh_lut_assoc, &n_reads_per_cycle_lut, &n_writes_per_cycle_lut, - &mh_size, &n_reads_per_cycle_mh, &n_writes_per_cycle_mh); - } - issue_warp_MAJ = new issue_warp_majority_heap(simd_width, &warp_pool, - mh_lut_size, mh_lut_assoc, mh_size, - n_reads_per_cycle_lut, n_writes_per_cycle_lut, - n_reads_per_cycle_mh, n_writes_per_cycle_mh); - } - break; - } - - this->just_resume = false; - - this->max_warppool_occ = 0; - this->warppool_occ_histo = new int[n_threads]; - memset(this->warppool_occ_histo, 0, n_threads*sizeof(int)); -} - -// should never be called (only at exit?) -dwf_hw_sche_class::~dwf_hw_sche_class( ) -{ - unsigned i; - - for (i=0; i<warp_pool.size(); i++) { - free(warp_pool[i].tid); - } - - delete[] this->warppool_occ_histo; - - delete warp_lut_pc; -} - -// allocate a new warp in warp pool -int dwf_hw_sche_class::allocate_warp( address_type pc, bool update_scheduler ) -{ - int idx; - assert(!free_warp_q.empty()); - idx = free_warp_q.front(); - free_warp_q.pop_front(); - warp_pool[idx].uid = uid_cnt; - uid_cnt++; - warp_pool[idx].pc = pc; - warp_pool[idx].next_warp = -1; - warp_pool[idx].lut_ptr = NULL; - - if (update_scheduler) { - if (heuristic == FIFO) issue_warp_FIFO_q.push(idx); - if (heuristic == PC) issue_warp_PC_q.push(idx); - if (heuristic == MAJORITY || heuristic == MAJORITY_MAXHEAP) - issue_warp_MAJ->push_warp(pc, idx); - if (heuristic == PDOMPRIO) issue_warp_pdom.push_warp(pc, idx); - } - - return idx; -} - -// free a warp in warp pool -// it will reset the content of the warp entry as well -void dwf_hw_sche_class::free_warp( int idx, bool update_warplut ) -{ - bool redundant_idx_check = false; - if (redundant_idx_check) { - deque<int>::iterator dit = find(free_warp_q.begin(), free_warp_q.end(), idx); - assert(dit == free_warp_q.end()); - } - - warp_pool[idx].pc = -1; - memset(warp_pool[idx].tid, -1, sizeof(int)*simd_width); - warp_pool[idx].occ = 0; - warp_pool[idx].next_warp = -1; - if (update_warplut) { - warp_lut_pc->invalidate_entry( (warplut_entry_t*)warp_pool[idx].lut_ptr, idx ); - } - - free_warp_q.push_back(idx); - assert(free_warp_q.size() <= warp_pool.size()); -} - -warplut_entry_t* dwf_hw_sche_class::lookup_pc2warp( const warp_tag_t& lookup_tag ) -{ - bool lut_missed = false; - - warplut_entry_t* lut_entry; - lut_entry = warp_lut_pc->lookup_pc2warp( lookup_tag, lut_missed ); - - if (!lut_missed) { - if (lut_entry->tag != warp_pool[lut_entry->idx].pc) lut_missed = true; - } - - if (lut_missed) { - if (npc_tracker.pc_count.find(lookup_tag.get_pc()) != npc_tracker.pc_count.end()) { - lut_realmiss++; // ie. the incoming warp lost an opportunity to merge - } - } - - return lut_entry; -} - - -void fill_all (vector<char>& container, const char& value) -{ - fill(container.begin(), container.end(), value); -} - -int regfile_hash(signed istream_number, unsigned simd_size, unsigned n_banks); -int dwf_hw_sche_class::update_warp( int *tid, address_type pc ) -{ - int i; - bool newwarp = false; - bool newwarp_alloc = false; - warplut_entry_t* lut_entry; - warp_tag_t warp_tag(pc); - lut_entry = lookup_pc2warp(warp_tag); - - // no LUT entry returned, stall - if (!lut_entry) { - assert(0); - } - - if (heuristic == MAJORITY || heuristic == MAJORITY_MAXHEAP) { - issue_warp_MAJ->add_threads(pc, tid); - } - - npc_tracker.add_threads( tid, pc ); - - // if the pc of the LUT entry does not match, - // allocate a new entry - if (lut_entry->tag != warp_tag) { - lut_entry->idx = allocate_warp(pc); - lut_entry->tag = warp_tag; - lut_entry->occ = 0; - assert(warp_pool[lut_entry->idx].pc == pc); - newwarp = true; - newwarp_alloc = true; - } - - // create the request vector - bool tid_has_valid_entry = false; - fill_all(m_req, 0); - for (i = 0; i<simd_width; i++) { - if (tid[i] != -1) { - int lane = regfile_hash(tid[i],simd_width,regf_width); - // make sure we are not having two threads going to same lane - assert(lane < regf_width); - m_req[lane] += 1; - tid_has_valid_entry = true; - } - } - assert(tid_has_valid_entry); - - // read the old idx pointing to an existing warp - int old_idx = lut_entry->idx; - - // create the conflict vector - fill_all(m_occ_ext, 0); - int regf_mask = regf_width - 1; - for (i = 0; i<simd_width; i++) { - m_occ_ext[i & regf_mask] += ((lut_entry->occ & (1 << i)) == 0)? 0 : 1; - } - fill_all(m_occ_upd, 0); - fill_all(m_occ_new, 0); - int n_regf_slot = simd_width / regf_width; - bool conflict = false; - for (i = 0; i<regf_width; i++) { - if (m_occ_ext[i] + m_req[i] > n_regf_slot) { - m_occ_new[i] = m_occ_ext[i] + m_req[i] - n_regf_slot; - m_occ_upd[i] = n_regf_slot - m_occ_ext[i]; - conflict = true; - } else { - m_occ_upd[i] = m_req[i]; - } - } - - // if the pc of the warp mismatch with lut, - // set conflict vector to all one. - // that force all threads to the newly allocated warp - if (warp_pool[old_idx].pc != pc) { - conflict = true; - for (i = 0; i<regf_width; i++) { - m_occ_new[i] = m_req[i]; - m_occ_upd[i] = 0; - m_occ_ext[i] = n_regf_slot; - } - } - - // if there are conflicted entries, get a new warp - int new_idx = -1; - if (conflict) { - new_idx = allocate_warp(pc); - lut_entry->idx = new_idx; - lut_entry->occ = 0; //update the lut_entry - assert(warp_pool[new_idx].pc == pc); - - int total_occ = 0; - for (i = 0; i < regf_width; i++) - total_occ += m_occ_ext[i] + m_req[i]; - if (total_occ <= simd_width) warp_fragmentation += 1; - warp_merge_conflict += 1; - - newwarp_alloc = true; - } - - // update the warp as indicated by the LUT - // if the lane is conflicted, or the old warp is just not - // write to the new warp - int new_occ = 0; - fill_all(m_occ_new, 0); - for (i = 0; i<simd_width; i++) { - if (tid[i] != -1) { - int rfbank = regfile_hash(tid[i],simd_width,regf_width); - int lane = -1; - if ((m_occ_ext[rfbank] < n_regf_slot) || newwarp) { - lane = rfbank + m_occ_ext[rfbank] * regf_width; - assert(lane < simd_width); - warp_pool[old_idx].tid[lane] = tid[i]; - warp_pool[old_idx].occ++; - lut_entry->occ |= (1<<lane); - m_occ_ext[rfbank]++; - } else { - lane = rfbank + m_occ_new[rfbank] * regf_width; - assert(lane < simd_width); - warp_pool[new_idx].tid[lane] = tid[i]; - warp_pool[new_idx].occ++; - new_occ |= (1<<lane); - m_occ_new[rfbank]++; - assert(m_occ_new[rfbank] <= n_regf_slot); - } - } - } - - // to cover the case where the pc of the warp mismatch with lut - // (because the warp is issued) - if (warp_pool[old_idx].pc == pc) { - issue_warp_pdom.add_threads(old_idx, pc); - } - if (conflict) { - lut_entry->occ = new_occ; - issue_warp_pdom.add_threads(new_idx, pc); - } - - warp_pool[lut_entry->idx].lut_ptr = lut_entry; // link up the lut entry and warp - - bool scheduler_consistency_check = false; - if (scheduler_consistency_check && heuristic == MAJORITY) { - ((issue_warp_majority_queue*)issue_warp_MAJ)->check_consistency(); - } - - return 1; -} - -// called AFTER threads hit a barrier to insert them into the barrier queue -// ASSUME: threads from released barrier are not hitting second barrier right away -int dwf_hw_sche_class::update_warp_at_barrier( int* tid, address_type pc, int cta_id, int barrier_num ) -{ - assert(barrier_num < m_nbarriers); - assert(cta_id >= 0); - - int i; - int warp_index = 0xDEADBEEF; - - npc_tracker.add_threads( tid, pc ); - - // always allocate new warp - warp_index = allocate_warp(pc, false); - assert(warp_pool[warp_index].pc == pc); - - // no need to create the request vector - // no need to create the conflict vector - - // assign threads into the new warp - fill_all(m_occ_ext, 0); - int max_nthreads_per_rfbank = simd_width / regf_width; - for (i = 0; i<simd_width; i++) { - if (tid[i] != -1) { - int rfbank = regfile_hash(tid[i],simd_width,regf_width); - int lane = -1; - - assert(m_occ_ext[rfbank] < max_nthreads_per_rfbank); - lane = rfbank + m_occ_ext[rfbank] * regf_width; - assert(lane < simd_width); - warp_pool[warp_index].tid[lane] = tid[i]; - warp_pool[warp_index].occ++; - m_occ_ext[rfbank]++; - } - } - - warp_pool[warp_index].lut_ptr = NULL; // no link to any lut entry - - // put the warp id into barrier queue - m_barrier[cta_id].m_queue.push_back(warp_index); - - // notify issue module to check this barrier at issue - if ( m_barrier[cta_id].ready_to_issue() ) { - m_cta_released_barrier.insert(cta_id); - } - - return 1; -} - -// called at decode stage when thread hit a barrier -// ASSUME: threads from released barrier are not hitting second barrier right away -void dwf_hw_sche_class::hit_barrier( int cta_id, int barrier_num ) -{ - assert(barrier_num < m_nbarriers); - assert(cta_id >= 0); - - m_barrier[cta_id].m_release = false; -} - -// called at decode stage when all thread in cta hit the barrier -// ASSUME: threads from released barrier are not hitting second barrier right away -void dwf_hw_sche_class::release_barrier( int cta_id, int barrier_num ) -{ - assert(barrier_num < m_nbarriers); - assert(cta_id >= 0); - - map<int, dwf_barrier>::iterator i_barrier = m_barrier.find(cta_id); - assert(i_barrier != m_barrier.end()); // barrier has to exists in the first place! - i_barrier->second.m_release = true; -} - -void dwf_hw_sche_class::issue_warp( int *tid, address_type *pc ) -{ - int i; - bool warp_issued = false; - - // scan the released barriers for ready warp - // TODO: arbitrate between different queues? - set<int>::iterator i_ctabar = m_cta_released_barrier.begin(); - for (; i_ctabar != m_cta_released_barrier.end(); ++i_ctabar) { - int cta_id = *i_ctabar; - map<int, dwf_barrier>::iterator i_barrier = m_barrier.find(cta_id); - - if ( i_barrier->second.ready_to_issue() ) { - int warp_idx = i_barrier->second.m_queue.front(); - - for (i = 0; i < simd_width; i++) { - tid[i] = warp_pool[warp_idx].tid[i]; - } - *pc = warp_pool[warp_idx].pc; - - i_barrier->second.m_queue.pop_front(); - free_warp(warp_idx, false); // don't update warplut as the warp is not linked to it - - // remove cta from checking list if the queue is emptied - // (if the last threads haven't made it back to scheduler in time, - // update_warp_at_barrier will insert the cta id again) - if (i_barrier->second.m_queue.empty()) { - m_cta_released_barrier.erase(i_ctabar); - } - - warp_issued = true; - - break; - } - } - - if (!warp_issued) { - switch (heuristic) { - case FIFO: - // Oldest warp are issued first - if (!issue_warp_FIFO_q.empty()) { - int idx = issue_warp_FIFO_q.front(); - for (i = 0; i < simd_width; i++) { - tid[i] = warp_pool[idx].tid[i]; - } - *pc = warp_pool[idx].pc; - - issue_warp_FIFO_q.pop(); - free_warp(idx); - } else { - memset(tid, -1, sizeof(int)*simd_width); - *pc = -1; - } - break; - case PC: - // lowest PC warp are issued first - if (!issue_warp_PC_q.empty()) { - int idx = issue_warp_PC_q.top(); - for (i = 0; i < simd_width; i++) { - tid[i] = warp_pool[idx].tid[i]; - } - *pc = warp_pool[idx].pc; - - issue_warp_PC_q.pop(); - free_warp(idx); - } else { - memset(tid, -1, sizeof(int)*simd_width); - *pc = -1; - } - break; - case MAJORITY: - case MAJORITY_MAXHEAP: - // issue the most common PC first - { - int idx = issue_warp_MAJ->pop_warp(); - if (idx >= 0) { - for (i = 0; i < simd_width; i++) { - tid[i] = warp_pool[idx].tid[i]; - } - *pc = warp_pool[idx].pc; - free_warp(idx); - } else { - memset(tid, -1, sizeof(int)*simd_width); - *pc = -1; - } - } - break; - case PDOMPRIO: - // issue the warp with lowest PDOM count - { - int idx = issue_warp_pdom.front_warp(); - if (idx >= 0) { - issue_warp_pdom.pop_warp(); - - for (i = 0; i < simd_width; i++) { - tid[i] = warp_pool[idx].tid[i]; - } - *pc = warp_pool[idx].pc; - free_warp(idx); - - just_resume = false; - } else { - memset(tid, -1, sizeof(int)*simd_width); - *pc = -1; - } - } - break; - default: - printf("Unsupported Heuristics!\n"); - abort(); - break; - } - } - - npc_tracker.sub_threads( tid, *pc ); - - int warppool_occ = warp_pool.size() - free_warp_q.size(); - if (max_warppool_occ < warppool_occ) { - max_warppool_occ = warppool_occ; - } - warppool_occ_histo[warppool_occ] += 1; -} - -void dwf_hw_sche_class::init_cta(int start_thread, int cta_size, address_type start_pc) -{ - assert((start_thread % simd_width) == 0); // thread id starting at a warp - - int n_warp_2assign = cta_size / simd_width; - n_warp_2assign += (cta_size % simd_width)? 1 : 0; // round up - - static int *thd_id = NULL; - if (thd_id == NULL) thd_id = new int[simd_width]; - - for (int w = 0; w < n_warp_2assign; w++) { - // generate the warp update register for each warp - fill_n(thd_id, simd_width, -1); - int warp_start_tid = start_thread + w * simd_width; - for (int i = 0; (i < simd_width) && (warp_start_tid + i) < (start_thread + cta_size); i++) { - thd_id[i] = warp_start_tid + i; - } - - // push these warps into DWF scheduler - update_warp( thd_id, start_pc ); - } -} - -void dwf_hw_sche_class::print_free_warp_q( FILE *fout ) -{ - fprintf(fout, "free_node_q (%zd)= ", free_warp_q.size() ); - deque<int>::iterator dit = free_warp_q.begin(); - for (; dit != free_warp_q.end(); dit++) { - fprintf(fout, "%03d ", *dit); - } - fprintf(fout, "\n"); -} - -void print_warp( FILE *fout, warp_entry_t warp_e, int simd_width ) -{ - fprintf(fout, "\t%02d 0x%08x: (", warp_e.pdom_prio, warp_e.pc ); - for (int i=0;i<simd_width;i++) { - fprintf(fout, "%03d ", warp_e.tid[i]); - } - fprintf(fout, ")\n"); -} - -void dwf_hw_sche_class::print_warp_pool( FILE *fout ) -{ - for (unsigned i=0; i< warp_pool.size(); i++) { - if (warp_pool[i].pc != (address_type)-1) { - fprintf(fout, "bp%03d:", i); - print_warp(fout, warp_pool[i], simd_width); - } - } -} - -void dwf_hw_sche_class::clear_policy_access( ) { - if (heuristic == MAJORITY_MAXHEAP) { - ((issue_warp_majority_heap*)issue_warp_MAJ)->clear_access( ); - } -} - -void dwf_hw_sche_class::reset_policy_access( ) { - if (heuristic == MAJORITY_MAXHEAP) { - ((issue_warp_majority_heap*)issue_warp_MAJ)->reset_access( ); - } -} - -/////////////////////////////////////////////////////////////////////////// -// c-wrapper interface -/////////////////////////////////////////////////////////////////////////// - -int dwf_hw_n_sche = 0; -dwf_hw_sche_class **dwf_hw_sche; -unsigned *acc_dyn_pcs = NULL; - -void create_dwf_schedulers( int n_shaders, - int lut_size, int lut_assoc, - int simd_width, int regf_width, - int n_threads, int insn_size, - int heuristic, - char *policy_opt ) -{ - dwf_hw_n_sche = n_shaders; - dwf_hw_sche = new dwf_hw_sche_class*[n_shaders]; - for (int i=0; i<n_shaders; i++) { - dwf_hw_sche[i] = new dwf_hw_sche_class( lut_size, lut_assoc, - simd_width, regf_width, - n_threads, insn_size, - heuristic, i, - policy_opt ); - } - - if (acc_dyn_pcs == NULL) { - acc_dyn_pcs = new unsigned[n_shaders]; - std::fill_n(acc_dyn_pcs, n_shaders, 0); - } - for (int i=0; i<n_shaders; i++) { - dwf_hw_sche[i]->npc_tracker.acc_pc_count = &acc_dyn_pcs[i]; - } -} - -int dwf_update_warp( int shd_id, int* tid, address_type pc ) -{ - return dwf_hw_sche[shd_id]->update_warp( tid, pc ); -} - -int dwf_update_warp_at_barrier( int shd_id, int* tid, address_type pc, int cta_id ) -{ - return dwf_hw_sche[shd_id]->update_warp_at_barrier( tid, pc, cta_id); -} - -void dwf_hit_barrier( int shd_id, int cta_id ) -{ - dwf_hw_sche[shd_id]->hit_barrier( cta_id ); -} - -void dwf_release_barrier( int shd_id, int cta_id ) -{ - dwf_hw_sche[shd_id]->release_barrier( cta_id ); -} - -void dwf_issue_warp( int shd_id, int *tid, address_type *pc ) -{ - dwf_hw_sche[shd_id]->issue_warp( tid, pc ); -} - -void dwf_clear_accessed( int shd_id ) -{ - dwf_hw_sche[shd_id]->clear_accessed( ); -} - -void dwf_clear_policy_access( int shd_id ) -{ - dwf_hw_sche[shd_id]->clear_policy_access( ); -} - -void dwf_reset_policy_access( int shd_id ) -{ - dwf_hw_sche[shd_id]->reset_policy_access( ); -} - -void dwf_init_CTA(int shd_id, int start_thread, int cta_size, address_type start_pc) -{ - dwf_hw_sche[shd_id]->init_cta(start_thread, cta_size, start_pc); - dwf_hw_sche[shd_id]->clear_accessed( ); - dwf_hw_sche[shd_id]->clear_policy_access( ); -} - -void dwf_print_stat( FILE* fout ) -{ - dwf_hw_sche_class::print_stats( fout ); - npc_tracker_class::histo_print( fout ); - fprintf(fout, "max_warppool_occ = "); - for (int i=0; i<dwf_hw_n_sche; i++) { - fprintf(fout, "%d ", dwf_hw_sche[i]->max_warppool_occ); - } - fprintf(fout, "\n"); - for (int i=0; i<dwf_hw_n_sche; i++) { - fprintf(fout, "warppool_occ[%d] = ", i); - for (int j=0; j<dwf_hw_sche[i]->max_warppool_occ; j++) { - fprintf(fout, "%d ", dwf_hw_sche[i]->warppool_occ_histo[j]); - } - fprintf(fout, "\n"); - } - if (dwf_hw_sche[0]->heuristic == MAJORITY_MAXHEAP) { - fprintf(fout, "n_stall_on_maxheap = "); - for (int i=0; i<dwf_hw_n_sche; i++) { - fprintf(fout, "%d ", - ((issue_warp_majority_heap*)dwf_hw_sche[i]->issue_warp_MAJ)->n_stall_on_maxheap); - } - fprintf(fout, "\n"); - fprintf(fout, "maxheap_n_entries = "); - for (int i=0; i<dwf_hw_n_sche; i++) { - fprintf(fout, "%d ", - ((issue_warp_majority_heap*)dwf_hw_sche[i]->issue_warp_MAJ)->maxheap.max_n_entries); - } - fprintf(fout, "\n"); - fprintf(fout, "maxheap_lut_n_aliased = "); - for (int i=0; i<dwf_hw_n_sche; i++) { - fprintf(fout, "%d ", - ((issue_warp_majority_heap*)dwf_hw_sche[i]->issue_warp_MAJ)->mh_lut.n_aliased); - } - fprintf(fout, "\n"); - issue_warp_majority_heap::print_stat(fout); - } -} - -void dwf_reset_reconv_pt() -{ - issue_warp_pdom_prio::reconvgence_pt.clear(); -} - -void dwf_insert_reconv_pt(address_type pc) -{ - issue_warp_pdom_prio::reconvgence_pt.insert(pc); -} - -void dwf_reinit_schedulers( int n_shaders ) -{ - for (int i=0; i<n_shaders; i++) { - dwf_hw_sche[i]->issue_warp_pdom.reinit(); - } -} - -void dwf_update_statistics( int shader_id ) -{ - dwf_hw_sche[shader_id]->npc_tracker.update_acc_count(); -} - -void g_print_dmaj_scheduler(int sid) { - dwf_hw_sche[sid]->issue_warp_MAJ->print(stdout); -} - -void g_print_warp_lut(int sid) { - dwf_hw_sche[sid]->warp_lut_pc->print(stdout); -} - -void g_print_free_warp_q(int sid) { - dwf_hw_sche[sid]->print_free_warp_q(stdout); -} - -void g_print_warp_pool(int sid) { - dwf_hw_sche[sid]->print_warp_pool(stdout); -} - -void g_print_max_heap(int sid) { - dwf_hw_sche[sid]->issue_warp_MAJ->print(stdout); -} - -#ifdef UNIT_TEST - - #undef UNIT_TEST - #include "stat-tool.cc" - -int regfile_hash(signed istream_number, unsigned simd_size, unsigned n_banks) { - if (gpgpu_thread_swizzling) { - signed warp_ID = istream_number / simd_size; - return((istream_number + warp_ID) % n_banks); - } else { - return(istream_number % n_banks); - } -} - -int log2i(int n) { - int lg; - lg = -1; - while (n) { - n>>=1;lg++; - } - return lg; -} - -int test_FIFO() -{ - dwf_hw_sche_class *dwf_sche; - int i; - int tid[6][4] = { - { 0, 1, 2, 3}, - { 4, 5, 6, 7}, - { 8,-1,10,-1}, - {-1, 1,-1, 3}, - { 4, 9,-1,11}, - {-1,13,14,-1} - }; - - int expect_out[12][4] = { - { 0, 1, 2, 3}, - { 0, 1, 2, 3}, - { 0, 1, 2, 3}, - { 4, 5, 6, 7}, - { 8, 1,10, 3}, - { 4, 9,14,11}, - {-1,13,-1,-1}, - { 4, 9,-1,11}, - {-1,13,14,-1}, - { 8,-1,10,-1}, - { 4, 9,14,11}, - { 8,13,10,-1} - }; - - int tid_out[4]; - address_type pc_out; - - dwf_sche = new dwf_hw_sche_class(16, 2, 4, 4, 16, 1, FIFO); - - // same threads - different pc - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[0], 0x409a80); - dwf_sche->update_warp(tid[0], 0x409a88); - - // different threads - different pc - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[0], 0x409a90); - dwf_sche->update_warp(tid[1], 0x409a80); - - // different threads - same pc - // expect two warp to merge into one as there is no lane conflict - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[2], 0x409a90); - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[3], 0x409a90); - - // same as above, but with lane conflict - // expect a new warp allocated, - // but only the conflicting threads goes to new warp - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[4], 0x409a80); - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[5], 0x409a80); - - // different threads - different pc - // purposely try to alias an existing mapping - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[4], 0x410a80); - dwf_sche->update_warp(tid[5], 0x411a80); - - // going back to that mapping - // a new warp should be allocated (despite lack of conflict) - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[2], 0x409a80); - - // testing the occupancy vector - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[4], 0x409aa0); - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[5], 0x409aa0); - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[2], 0x409aa0); - - // fill the warp pool up - for (i=12; i<64; ) { - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[1], 0x409a80 + 8 * i++); - dwf_sche->update_warp(tid[4], 0x409a80 + 8 * i++); - } - // issue all the warp (do some auto checking on the way) - for (i=0; i<64; i++) { - dwf_sche->issue_warp(tid_out, &pc_out); - printf("0x%08x [%d %d %d %d]\n", pc_out, tid_out[0], tid_out[1], tid_out[2], tid_out[3]); - if (i<12) { - if ( memcmp(tid_out, expect_out[i], 4*sizeof(int) ) ) { - printf("%d warp mismatches\n", i); - assert(0); - } - } - } - - // now that all warpes are issue, no entries in the lut is valid - // updating warp with an old address that remains in the lut - // to see if detects the invalid lut entry - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[2], 0x409a80 + 8 * 63); - dwf_sche->update_warp(tid[3], 0x409a80 + 8 * 62); - dwf_sche->issue_warp(tid_out, &pc_out); - assert(!memcmp(tid_out, tid[2], 4*sizeof(int) )); - dwf_sche->issue_warp(tid_out, &pc_out); - assert(!memcmp(tid_out, tid[3], 4*sizeof(int) )); - - dwf_sche->print_warp_pool(stdout); - dwf_sche->warp_lut_pc->print(stdout); - dwf_hw_sche_class::print_stats(stdout); - - delete dwf_sche; - - return 0; -} - -int test_PC () -{ - dwf_hw_sche_class *dwf_sche; - int i; - int tid[4][4] = { - { 0, 1, 2, 3}, - { 4, 5, 6, 7}, - { 8,-1,10,-1}, - {-1,13,14,-1} - }; - - int tid_out[4]; - address_type pc_out; - - dwf_sche = new dwf_hw_sche_class(16, 2, 4, 4, 16, 1, PC); - - // fill the warp pool up in reverse PC order - for (i=0; i<4; i++) { - for (int j=0; j<4; j++) { - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[j], 0x409a80 - 8 * i); - } - } - - // issue the warps, expect them to be in PC order, with higher occ warp issued first - printf("PC Issue Logic:\n"); - for (i=0; i<4; i++) { - for (int j=0; j<4; j++) { - dwf_sche->issue_warp(tid_out, &pc_out); - printf("0x%08x [%d %d %d %d]\n", pc_out, tid_out[0], tid_out[1], tid_out[2], tid_out[3]); - } - } - -} - -int test_MAJ () -{ - dwf_hw_sche_class *dwf_sche; - int i; - int tid[4][4] = { - { 0, 1, 2, 3}, - { 4, 5, 6, 7}, - { 8,-1,10,-1}, - {-1,13,14,-1} - }; - - int tid_out[4]; - address_type pc_out; - - dwf_sche = new dwf_hw_sche_class(16, 2, 4, 4, 16, 1, MAJORITY); - - // fill the warp pool up in reverse PC order - for (i=0; i<4; i++) { - for (int j=0; j<(4-i); j++) { - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[j], 0x409a80 - 8 * i); - } - } - - // issue the warps, expect them to be in PC order, with higher occ warp issued first - printf("Majority Issue Logic:\n"); - for (i=0; i<4; i++) { - for (int j=0; j<4; j++) { - dwf_sche->issue_warp(tid_out, &pc_out); - printf("0x%08x [%d %d %d %d]\n", pc_out, tid_out[0], tid_out[1], tid_out[2], tid_out[3]); - } - } -} - -int test_MAJ_HEAP () -{ - printf("\ntest_MAJ_HEAP:\n"); - dwf_hw_sche_class *dwf_sche; - int i; - int tid[4][4] = { - { 0, 1, 2, 3}, - { 4, 5, 6, 7}, - { 8,-1,10,-1}, - {-1,13,14,-1} - }; - - int tid_out[4]; - address_type pc_out; - - dwf_sche = new dwf_hw_sche_class(16, 2, 4, 4, 16, 1, MAJORITY_MAXHEAP); - - // fill the warp pool up in reverse PC order - for (i=0; i<4; i++) { - for (int j=0; j<(i+1); j++) { - dwf_sche->clear_accessed(); - dwf_sche->update_warp(tid[j], 0x409a80 + 8 * i); - } - } - - dwf_sche->reset_policy_access(); - dwf_sche->issue_warp_MAJ->print(stdout); - - // issue the warps, expect them to be in PC order, with higher occ warp issued first - printf("Majority (Max Heap) Issue Logic:\n"); - for (i=0; i<4; i++) { - for (int j=0; j<4; j++) { - dwf_sche->issue_warp(tid_out, &pc_out); - printf("0x%08x [%d %d %d %d]\n", pc_out, tid_out[0], tid_out[1], tid_out[2], tid_out[3]); - } - dwf_sche->reset_policy_access(); - } -} - -void test_warp_lut_pc () -{ - printf("\ntest_warp_lut_pc:\n"); - warp_lut_sa<pc_tag> warp_lut_pc(16, // size - 4, // assoc - 1); // insn_size - - address_type pc_value[] = {0, 4, 0, 8, 12, 16, 20, 8, 8, 0}; - int n_entry = sizeof(pc_value) / sizeof(address_type); - vector<pc_tag> pc_stream(pc_value, pc_value + n_entry); - - int misses = 0; - for (int n = 0; n < n_entry * 100; n++) { - int i = n % n_entry; - tag2warp_entry_t<pc_tag> *lut_entry = NULL; - bool lut_miss = false; - - lut_entry = warp_lut_pc.lookup_pc2warp(pc_stream[i], lut_miss); - - if (lut_entry->tag != pc_stream[i]) { - lut_entry->tag = pc_stream[i]; - lut_entry->occ = 1; - misses += 1; - } - warp_lut_pc.clear_accessed(); - lut_entry->accessed = 0; - } - - printf("Number of Miss = %d\n", misses); -} - -int main () { - //test_FIFO(); - //test_PC(); - //test_MAJ(); - test_MAJ_HEAP(); - test_warp_lut_pc(); - return 0; -} - -#endif diff --git a/src/gpgpu-sim/dwf.h b/src/gpgpu-sim/dwf.h deleted file mode 100644 index 547abb4..0000000 --- a/src/gpgpu-sim/dwf.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * dwf.h - * - * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, and the - * University of British Columbia - * Vancouver, BC V6T 1Z4 - * All Rights Reserved. - * - * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE - * TERMS AND CONDITIONS. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h - * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda - * (property of NVIDIA). The files benchmarks/BlackScholes/ and - * benchmarks/template/ are derived from the CUDA SDK available from - * http://www.nvidia.com/cuda (also property of NVIDIA). The files from - * src/intersim/ are derived from Booksim (a simulator provided with the - * textbook "Principles and Practices of Interconnection Networks" available - * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by - * the corresponding legal terms and conditions set forth separately (original - * copyright notices are left in files from these sources and where we have - * modified a file our copyright notice appears before the original copyright - * notice). - * - * Using this version of GPGPU-Sim requires a complete installation of CUDA - * which is distributed seperately by NVIDIA under separate terms and - * conditions. To use this version of GPGPU-Sim with OpenCL requires a - * recent version of NVIDIA's drivers which support OpenCL. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the University of British Columbia nor the names of - * its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. - * - * 5. No nonprofit user may place any restrictions on the use of this software, - * including as modified by the user, by any other authorized user. - * - * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, - * Ali Bakhoda, George L. Yuan, at the University of British Columbia, - * Vancouver, BC V6T 1Z4 - */ - -#ifndef dwf_h_INCLUDED -#define dwf_h_INCLUDED - -#ifdef __cplusplus - - #include <cstdio> - #include <cstdlib> - #include <cassert> - #include <vector> - #include <queue> - #include <list> - #include <algorithm> - -#endif - -#include "../abstract_hardware_model.h" - -extern unsigned *acc_dyn_pcs; - -void create_dwf_schedulers( int n_shaders, - int lut_size, int lut_assoc, - int simd_width, int regf_width, - int n_threads, int insn_size, - int heuristic, - char *policy_opt ); - -int dwf_update_warp( int shd_id, int* tid, address_type pc ); - -void dwf_issue_warp( int shd_id, int *tid, address_type *pc ); - -void dwf_clear_accessed( int shd_id ); - -void dwf_clear_policy_access( int shd_id ); -void dwf_reset_policy_access( int shd_id ); - -int dwf_update_warp_at_barrier( int shd_id, int* tid, address_type pc, int cta_id ); -void dwf_hit_barrier( int shd_id, int cta_id ); -void dwf_release_barrier( int shd_id, int cta_id ); - -void dwf_init_CTA(int shd_id, int start_thread, int cta_size, address_type start_pc); - -void dwf_print_stat( FILE* fout ); - -void dwf_reset_reconv_pt(); -void dwf_insert_reconv_pt(address_type pc); - -void dwf_reinit_schedulers( int n_shaders ); - -void dwf_set_accPC( int n_shaders, unsigned *acc_pc_count ); - -void dwf_update_statistics( int shader_id ); - -extern unsigned int gpgpu_dwf_heuristic; -extern bool gpgpu_dwf_regbk; - -#endif diff --git a/src/gpgpu-sim/gpu-sim.cc b/src/gpgpu-sim/gpu-sim.cc index bfa4fda..7fff9fd 100644 --- a/src/gpgpu-sim/gpu-sim.cc +++ b/src/gpgpu-sim/gpu-sim.cc @@ -84,8 +84,6 @@ #include "icnt_wrapper.h" #include "dram.h" #include "addrdec.h" -#include "dwf.h" -#include "warp_tracker.h" #include "stat-tool.h" #include "l2cache.h" @@ -176,7 +174,6 @@ char * gpgpu_clock_domains; unsigned int gpu_n_mem_per_ctrlr; int gpu_n_tpc; char *gpgpu_dwf_hw_opt; -bool gpgpu_thread_swizzling; unsigned int more_thread = 1; #define MEM_LATENCY_STAT_IMPL @@ -266,18 +263,6 @@ void gpgpu_sim::reg_options(option_parser_t opp) "display runtime statistics such as dram utilization {<freq>:<flag>}", "10000:0"); - option_parser_register(opp, "-gpgpu_dwf_heuristic", OPT_UINT32, &gpgpu_dwf_heuristic, - "DWF scheduling heuristic: 0 = majority, 1 = minority, 2 = timestamp, 3 = pdom priority, 4 = pc-based, 5 = max-heap", - "0"); - - option_parser_register(opp, "-gpgpu_dwf_reg_bankconflict", OPT_BOOL, &m_shader_config->gpgpu_dwf_reg_bankconflict, - "bank conflict model used in MICRO'07/TACO'09 work (default=disabled)", - "0"); - - option_parser_register(opp, "-gpgpu_dwf_regbk", OPT_BOOL, &gpgpu_dwf_regbk, - "Have dwf scheduler to avoid bank conflict", - "1"); - option_parser_register(opp, "-gpgpu_memlatency_stat", OPT_INT32, &m_memory_config->gpgpu_memlatency_stat, "track and display latency statistics 0x2 enables MC, 0x4 enables queue logs", "0"); @@ -315,22 +300,6 @@ void gpgpu_sim::reg_options(option_parser_t opp) "Flush cache at the end of each kernel call", "0"); - option_parser_register(opp, "-gpgpu_pre_mem_stages", OPT_UINT32, &m_shader_config->gpgpu_pre_mem_stages, - "default = 0 pre-memory pipeline stages", - "0"); - - option_parser_register(opp, "-gpgpu_no_divg_load", OPT_BOOL, &m_shader_config->gpgpu_no_divg_load, - "Don't allow divergence on load (meaningful for dynamic warp formation only)", - "1"); - - option_parser_register(opp, "-gpgpu_dwf_hw", OPT_CSTR, &gpgpu_dwf_hw_opt, - "dynamic warp formation hw config, i.e., {<#LUT_entries>:<associativity>|none}", - "32:2"); - - option_parser_register(opp, "-gpgpu_thread_swizzling", OPT_BOOL, &gpgpu_thread_swizzling, - "Thread Swizzling (1=on, 0=off)", - "0"); - option_parser_register(opp, "-gpgpu_shmem_size", OPT_UINT32, &m_shader_config->gpgpu_shmem_size, "Size of shared memory per shader core (default 16kB)", "16384"); @@ -538,24 +507,6 @@ void gpgpu_sim::init_gpu() ptx_file_line_stats_create_exposed_latency_tracker(m_n_shader); - // initialize dynamic warp formation scheduler - int dwf_lut_size, dwf_lut_assoc; - sscanf(gpgpu_dwf_hw_opt,"%d:%d", &dwf_lut_size, &dwf_lut_assoc); - char *dwf_hw_policy_opt = strchr(gpgpu_dwf_hw_opt, ';'); - int insn_size = 1; // for cuda-sim - create_dwf_schedulers(m_n_shader, dwf_lut_size, dwf_lut_assoc, - m_shader_config->warp_size, m_shader_config->warp_size, - m_shader_config->n_thread_per_shader, insn_size, - gpgpu_dwf_heuristic, dwf_hw_policy_opt ); - - // always use no diverge on load for stack based SIMT execution (PDOM) - m_shader_config->gpgpu_no_divg_load = (m_shader_config->model != DWF) || - (m_shader_config->gpgpu_no_divg_load && (m_shader_config->model == DWF)); - m_shader_config->m_using_dwf_rrstage = (m_shader_config->model == DWF); - m_shader_config->using_commit_queue = (m_shader_config->model == DWF || m_shader_config->model == POST_DOMINATOR); - - m_shader_config->gpgpu_dwf_rr_stage_n_reg_banks=8; - assert(m_n_shader % gpu_concentration == 0); gpu_n_tpc = m_n_shader / gpu_concentration; @@ -700,11 +651,6 @@ unsigned int gpgpu_sim::run_gpu_sim() return gpu_sim_cycle; } - // refind the diverge/reconvergence pairs - dwf_reset_reconv_pt(); - dwf_process_reconv_pts(entry.entry()); - dwf_reinit_schedulers(m_n_shader); - // initialize the control-flow, memory access, memory latency logger create_thread_CFlogger( m_n_shader, m_shader_config->n_thread_per_shader, program_size, 0, gpgpu_cflog_interval ); shader_CTA_count_create( m_n_shader, gpgpu_cflog_interval); @@ -888,11 +834,6 @@ void gpgpu_sim::gpu_print_stat() const if (m_memory_config->gpgpu_cache_dl2_opt) L2c_print_cache_stat(); - printf("n_regconflict_stall = %d\n", n_regconflict_stall); - - if (m_shader_config->model == DWF) { - dwf_print_stat(stdout); - } if (m_shader_config->model == POST_DOMINATOR) { printf("num_warps_issuable:"); @@ -906,8 +847,6 @@ void gpgpu_sim::gpu_print_stat() const print_shader_cycle_distro( stdout ); - print_thread_pc_histogram( stdout ); - if (gpgpu_cflog_interval != 0) { spill_log_to_file (stdout, 1, gpu_sim_cycle); insn_warp_occ_print(stdout); @@ -983,41 +922,38 @@ unsigned gpgpu_sim::threads_per_core() const return m_shader_config->n_thread_per_shader; } -void gpgpu_sim::mem_instruction_stats(inst_t* warp) +void gpgpu_sim::mem_instruction_stats(warp_inst_t* warp) { - for (unsigned i=0; i< (unsigned) m_shader_config->warp_size; i++) { - if (warp[i].hw_thread_id == -1) continue; //bubble - //this breaks some encapsulation: the is_[space] functions, if you change those, change this. - bool store = is_store(warp[i]); - switch (warp[i].space.get_type()) { - case undefined_space: - case reg_space: - break; - case shared_space: - m_shader_stats->gpgpu_n_shmem_insn++; - break; - case const_space: - m_shader_stats->gpgpu_n_const_insn++; - break; - case param_space_kernel: - case param_space_local: - m_shader_stats->gpgpu_n_param_insn++; - break; - case tex_space: - m_shader_stats->gpgpu_n_tex_insn++; - break; - case global_space: - case local_space: - if (store){ + if( warp->empty() ) + return; //bubble + //this breaks some encapsulation: the is_[space] functions, if you change those, change this. + switch (warp->space.get_type()) { + case undefined_space: + case reg_space: + break; + case shared_space: + m_shader_stats->gpgpu_n_shmem_insn++; + break; + case const_space: + m_shader_stats->gpgpu_n_const_insn++; + break; + case param_space_kernel: + case param_space_local: + m_shader_stats->gpgpu_n_param_insn++; + break; + case tex_space: + m_shader_stats->gpgpu_n_tex_insn++; + break; + case global_space: + case local_space: + if( is_store(*warp) ) m_shader_stats->gpgpu_n_store_insn++; - } else { + else m_shader_stats->gpgpu_n_load_insn++; - } - break; - default: - abort(); - } - } + break; + default: + abort(); + } } //////////////////////////////////////////////////////////////////////////////////// @@ -1159,7 +1095,7 @@ void shader_core_ctx::issue_block2core( kernel_info_t &kernel ) allocate_barrier( free_cta_hw_id, warps ); // initialize the SIMT stacks and fetch hardware - init_warps(start_thread, end_thread); + init_warps( free_cta_hw_id, start_thread, end_thread); m_n_active_cta++; g_total_cta_left-=1; // used for exiting early from simulation @@ -1362,10 +1298,9 @@ void gpgpu_sim::cycle() // L1 cache + shader core pipeline stages for (unsigned i=0;i<m_n_shader;i++) { if (m_sc[i]->get_not_completed() || more_thread) { - if (!strcmp("GPGPUSIM_ORIG",m_shader_config->pipeline_model) ) - m_sc[i]->cycle(); - else if (!strcmp("GT200",m_shader_config->pipeline_model) ) + if (!strcmp("GT200",m_shader_config->pipeline_model) ) m_sc[i]->cycle_gt200(); + else abort(); } } if( g_single_step && ((gpu_sim_cycle+gpu_tot_sim_cycle) >= g_single_step) ) { @@ -1431,14 +1366,6 @@ void gpgpu_sim::cycle() printf("maxmrqlatency = %d \n", m_memory_stats->max_mrq_latency); printf("maxmflatency = %d \n", m_memory_stats->max_mf_latency); } - if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP) { - printf("DWF_MS: "); - for (unsigned i=0;i<m_n_shader;i++) { - printf("%u ",acc_dyn_pcs[i]); - } - printf("\n"); - print_thread_pc( stdout, m_n_shader ); - } if (gpu_runtime_stat_flag & GPU_RSTAT_SHD_INFO) { shader_print_runtime_stat( stdout ); } diff --git a/src/gpgpu-sim/gpu-sim.h b/src/gpgpu-sim/gpu-sim.h index 081cacf..fab1ab8 100644 --- a/src/gpgpu-sim/gpu-sim.h +++ b/src/gpgpu-sim/gpu-sim.h @@ -98,8 +98,6 @@ enum divergence_support_t { POST_DOMINATOR = 1, - MIMD = 2, - DWF = 3, NUM_SIMD_MODEL }; @@ -123,8 +121,6 @@ struct shader_core_config bool gpgpu_operand_collector; int gpgpu_operand_collector_num_units; int gpgpu_operand_collector_num_units_sfu; - unsigned gpgpu_pre_mem_stages; - bool gpgpu_no_divg_load; bool gpgpu_stall_on_use; bool gpgpu_cache_wt_through; //Shader core resources @@ -145,9 +141,6 @@ struct shader_core_config int gpgpu_coalesce_arch; bool gpgpu_local_mem_map; int gpu_padded_cta_size; - unsigned gpgpu_dwf_rr_stage_n_reg_banks; - int m_using_dwf_rrstage; // model register read bank conflicts in DWF (i.e., not "lane aware") - int using_commit_queue; //is the scheduler using commit_queue? }; enum dram_ctrl_t { @@ -173,8 +166,6 @@ struct memory_config { extern int gpgpu_mem_address_mask; extern unsigned int gpu_n_mem_per_ctrlr; -extern bool gpgpu_thread_swizzling; - extern int gpu_runtime_stat_flag; extern int gpgpu_cflog_interval; @@ -214,7 +205,7 @@ public: unsigned num_shader() const { return m_n_shader; } unsigned threads_per_core() const; - void mem_instruction_stats( class inst_t* warp); + void mem_instruction_stats( class warp_inst_t* warp); int issue_mf_from_fq(class mem_fetch *mf); void gpu_print_stat() const; diff --git a/src/gpgpu-sim/mem_fetch.cc b/src/gpgpu-sim/mem_fetch.cc index 296a834..e2bc3e3 100644 --- a/src/gpgpu-sim/mem_fetch.cc +++ b/src/gpgpu-sim/mem_fetch.cc @@ -115,10 +115,7 @@ void mem_fetch::set_status( enum mshr_status status, enum mem_req_stat stat, uns { if ( mshr ) { mshr->set_status(status); - if( mshr->has_inst() ) - time_vector_update(mshr->get_insts_uid(),stat,cycle,type); - else - time_vector_update(request_uid,stat,cycle,type); + time_vector_update(request_uid,stat,cycle,type); } } @@ -130,8 +127,7 @@ bool mem_fetch::isatomic() const void mem_fetch::do_atomic() { - dram_callback_t &cb = mshr->get_atomic_callback(); - cb.function(cb.instruction, cb.thread); + mshr->do_atomic(); } bool mem_fetch::isinst() const diff --git a/src/gpgpu-sim/mem_latency_stat.cc b/src/gpgpu-sim/mem_latency_stat.cc index 28e9036..fda42e5 100644 --- a/src/gpgpu-sim/mem_latency_stat.cc +++ b/src/gpgpu-sim/mem_latency_stat.cc @@ -170,9 +170,9 @@ unsigned memory_stats_t::memlatstat_done(mem_fetch *mf, unsigned n_warp_per_shad mf_num_lat_pw_perwarp[wid]++; mf_tot_lat_pw_perwarp[wid] += mf_latency; mf_tot_lat_pw += mf_latency; - if( mf->get_mshr() && mf->get_mshr()->has_inst() ) - check_time_vector_update(mf->get_mshr()->get_insts_uid(),MR_2SH_FQ_POP,mf_latency,mf->get_type()); - mf_lat_table[LOGB2(mf_latency)]++; + unsigned idx = LOGB2(mf_latency); + assert(idx<32); + mf_lat_table[idx]++; shader_mem_lat_log(mf->get_sid(), mf_latency); mf_total_lat_table[mf->get_tlx_addr().chip][mf->get_tlx_addr().bk] += mf_latency; if (mf_latency > max_mf_latency) diff --git a/src/gpgpu-sim/scoreboard.cc b/src/gpgpu-sim/scoreboard.cc index 711a6ab..3484714 100644 --- a/src/gpgpu-sim/scoreboard.cc +++ b/src/gpgpu-sim/scoreboard.cc @@ -67,8 +67,9 @@ void Scoreboard::reserveRegisters(unsigned wid, const class inst_t* inst) } // Release registers for an instruction -void Scoreboard::releaseRegisters(unsigned wid, const class inst_t *inst) +void Scoreboard::releaseRegisters(const class warp_inst_t *inst) { + unsigned wid = inst->warp_id(); if(inst->out[0] > 0) releaseRegister(wid, inst->out[0]); if(inst->out[1] > 0) releaseRegister(wid, inst->out[1]); if(inst->out[2] > 0) releaseRegister(wid, inst->out[2]); diff --git a/src/gpgpu-sim/scoreboard.h b/src/gpgpu-sim/scoreboard.h index 6cec22c..4e1c154 100644 --- a/src/gpgpu-sim/scoreboard.h +++ b/src/gpgpu-sim/scoreboard.h @@ -23,7 +23,7 @@ public: void printContents(); void reserveRegisters(unsigned wid, const inst_t *inst); - void releaseRegisters(unsigned wid, const inst_t *inst); + void releaseRegisters(const warp_inst_t *inst); bool checkCollision(unsigned wid, const inst_t *inst); bool pendingWrites(unsigned wid) const; diff --git a/src/gpgpu-sim/shader.cc b/src/gpgpu-sim/shader.cc index 495c4c0..976671a 100644 --- a/src/gpgpu-sim/shader.cc +++ b/src/gpgpu-sim/shader.cc @@ -69,8 +69,6 @@ #include "gpu-sim.h" #include "addrdec.h" #include "dram.h" -#include "dwf.h" -#include "warp_tracker.h" #include "stat-tool.h" #include "gpu-misc.h" #include "../cuda-sim/ptx_sim.h" @@ -308,40 +306,11 @@ unsigned char shader_core_ctx::fq_push(unsigned long long int addr, return(m_gpu->issue_mf_from_fq(mf)); } -inst_t *shader_core_ctx::first_valid_thread( inst_t *warp ) +unsigned shader_core_ctx::first_valid_thread( unsigned stage ) { - for(unsigned t=0; t < m_config->warp_size; t++ ) - if( warp[t].hw_thread_id != -1 ) - return warp+t; - return NULL; + abort(); } -inst_t *shader_core_ctx::first_valid_thread( unsigned stage ) -{ - return first_valid_thread(m_pipeline_reg[stage]); -} - -void shader_core_ctx::move_warp( inst_t *&dst, inst_t *&src ) -{ - - assert( pipeline_regster_empty(dst) ); - inst_t* temp = dst; - dst = src; - src = temp; - for( unsigned t=0; t < m_config->warp_size; t++) - src[t] = inst_t(); -} - -void shader_core_ctx::clear_stage( inst_t *warp ) -{ - for( unsigned t=0; t < m_config->warp_size; t++) - warp[t] = inst_t(); -} - -bool shader_core_ctx::pipeline_regster_empty( inst_t *reg ) -{ - return first_valid_thread(reg) == NULL; -} void shader_core_ctx::L1cache_print( FILE *fp, unsigned &total_accesses, unsigned &total_misses) const { @@ -390,28 +359,14 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_config = config; m_stats = stats; unsigned warp_size=config->warp_size; - assert( !((config->model == DWF) && m_config->gpgpu_operand_collector) ); m_name = name; m_sid = shader_id; m_tpc = tpc_id; - m_dwf_RR_k = 0; - m_pipeline_reg = (inst_t**) calloc(N_PIPELINE_STAGES, sizeof(inst_t*)); - for (int j = 0; j<N_PIPELINE_STAGES; j++) { - m_pipeline_reg[j] = (inst_t*) calloc(warp_size, sizeof(inst_t)); - for (unsigned i=0; i<warp_size; i++) - m_pipeline_reg[j][i] = inst_t(); - } + m_pipeline_reg = new warp_inst_t*[N_PIPELINE_STAGES]; + for (int j = 0; j<N_PIPELINE_STAGES; j++) + m_pipeline_reg[j] = new warp_inst_t(warp_size); - if (m_config->gpgpu_pre_mem_stages) { - pre_mem_pipeline = (inst_t**) calloc(m_config->gpgpu_pre_mem_stages+1, sizeof(inst_t*)); - for (unsigned j = 0; j<=m_config->gpgpu_pre_mem_stages; j++) { - pre_mem_pipeline[j] = (inst_t*) calloc(warp_size, sizeof(inst_t)); - for (unsigned i=0; i<warp_size; i++) { - pre_mem_pipeline[j][i] = inst_t(); - } - } - } m_thread = (thread_ctx_t*) calloc(sizeof(thread_ctx_t), config->n_thread_per_shader); m_not_completed = 0; @@ -420,11 +375,8 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_n_active_cta = 0; for (unsigned i = 0; i<MAX_CTA_PER_SHADER; i++ ) m_cta_status[i]=0; - m_next_warp = 0; for (unsigned i = 0; i<config->n_thread_per_shader; i++) { m_thread[i].m_functional_model_thread_state = NULL; - m_thread[i].m_avail4fetch = false; - m_thread[i].m_waiting_at_barrier = false; m_thread[i].m_cta_id = -1; } @@ -449,8 +401,6 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, m_pdom_warp = new pdom_warp_ctx_t*[config->max_warps_per_shader]; for (unsigned i = 0; i < config->max_warps_per_shader; ++i) m_pdom_warp[i] = new pdom_warp_ctx_t(i,this); - if (m_config->using_commit_queue) - m_thd_commit_queue = new fifo_pipeline<std::vector<int> >("thd_commit_queue", 0, 0,gpu_sim_cycle); m_shader_memory_new_instruction_processed = false; // Initialize scoreboard @@ -477,27 +427,12 @@ shader_core_ctx::shader_core_ctx( class gpgpu_sim *gpu, // fetch m_last_warp_fetched = 0; m_last_warp_issued = 0; - m_ready_warps = (int*)calloc(m_config->max_warps_per_shader,sizeof(int)); - m_tmp_ready_warps = (int*)calloc(m_config->max_warps_per_shader,sizeof(int)); - m_last_warp=0; - m_last_issued_thread=0; // MIMD - - m_warp_tracker = NULL; - m_thread_pc_tracker = NULL; - if (m_config->gpgpu_no_divg_load) { - m_warp_tracker = new warp_tracker_pool(this); - m_thread_pc_tracker = new thread_pc_tracker(warp_size, config->n_thread_per_shader); - } - m_fetch_tid_out = (int*) malloc(sizeof(int) * warp_size); - m_dwf_rrstage_bank_access_counter = (int*) malloc(sizeof(int) * m_config->gpgpu_dwf_rr_stage_n_reg_banks); } void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed ) { if( reset_not_completed ) m_not_completed = 0; - m_next_warp = 0; - m_last_issued_thread=0; for (unsigned i = start_thread; i<end_thread; i++) { m_thread[i].n_insn = 0; m_thread[i].m_cta_id = -1; @@ -508,9 +443,8 @@ void shader_core_ctx::reinit(unsigned start_thread, unsigned end_thread, bool re } } -void shader_core_ctx::init_warps( unsigned start_thread, unsigned end_thread ) +void shader_core_ctx::init_warps( unsigned cta_id, unsigned start_thread, unsigned end_thread ) { - unsigned num_threads = end_thread - start_thread; address_type start_pc = next_pc(start_thread); if (m_config->model == POST_DOMINATOR) { unsigned start_warp = start_thread / m_config->warp_size; @@ -525,45 +459,16 @@ void shader_core_ctx::init_warps( unsigned start_thread, unsigned end_thread ) } } m_pdom_warp[i]->launch(start_pc,initial_active_mask); - m_warp[i].init(start_pc,i,n_active); + m_warp[i].init(start_pc,cta_id,i,n_active); m_not_completed += n_active; } - } else if (m_config->model == DWF) { - dwf_init_CTA(m_sid, start_thread, num_threads, start_pc); - for (unsigned i = start_thread; i<end_thread; i++) - m_thread[i].m_in_scheduler = true; - } - for (unsigned tid=start_thread;tid<end_thread;tid++) { - m_thread[tid].m_avail4fetch = true; - } -} - -// register id for unused register slot in instruction -#define DNA (0) - -unsigned g_next_shader_inst_uid=1; - -bool shader_core_ctx::fetch_stalled() -{ - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[TS_IF][i].hw_thread_id != -1 ) { - return true; // stalled - } } - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[IF_ID][i].hw_thread_id != -1 ) { - return true; // stalled - } - } - - m_new_warp_TS = true; - return false; // not stalled } // initalize the pipeline stage register to nops void shader_core_ctx::clear_stage_reg(int stage) { - clear_stage( m_pipeline_reg[stage] ); + m_pipeline_reg[stage]->clear(); } // return the next pc of a thread @@ -577,186 +482,6 @@ address_type shader_core_ctx::next_pc( int tid ) const return the_thread->get_pc(); // PC should already be updatd to next PC at this point (was set in shader_decode() last time thread ran) } -// issue thread to the warp -// tid - thread id, warp_id - used by PDOM, wlane - position in warp -void shader_core_ctx::shader_issue_thread(int tid, int wlane, unsigned active_mask ) -{ - m_thread[tid].m_functional_model_thread_state->ptx_fetch_inst( m_pipeline_reg[TS_IF][wlane] ); - m_pipeline_reg[TS_IF][wlane].hw_thread_id = tid; - m_pipeline_reg[TS_IF][wlane].wlane = wlane; - m_pipeline_reg[TS_IF][wlane].memreqaddr = 0; - m_pipeline_reg[TS_IF][wlane].uid = g_next_shader_inst_uid++; - m_pipeline_reg[TS_IF][wlane].warp_active_mask = active_mask; - m_pipeline_reg[TS_IF][wlane].issue_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - - assert( m_thread[tid].m_avail4fetch ); - m_thread[tid].m_avail4fetch = false; - assert( m_warp[wid_from_hw_tid(tid,m_config->warp_size)].get_avail4fetch() > 0 ); - m_warp[wid_from_hw_tid(tid,m_config->warp_size)].dec_avail4fetch(); -} - -int shader_core_ctx::pdom_sched_find_next_warp (int ready_warp_count) -{ - bool found = false; - int selected_warp = m_ready_warps[0]; - switch (m_config->pdom_sched_type) { - case 0: selected_warp = m_ready_warps[0]; found=true; break; // first ok warp found - case 1: selected_warp = m_ready_warps[rand()%ready_warp_count]; found=true; break; //random - case 8: - // "loose" round robin: - // execute the next available warp which is after the warp execued last time - selected_warp = (m_last_warp + 1) % m_config->max_warps_per_shader; - while (!found) { - for (int i=0;i<ready_warp_count;i++) { - if (selected_warp==m_ready_warps[i]) - found=true; - } - if( !found ) - selected_warp = (selected_warp + 1) % m_config->max_warps_per_shader; - } - break; - default: assert(0); - } - if (found) { - if (ready_warp_count==1) - m_stats->n_pdom_sc_single_stat++; - else - m_stats->n_pdom_sc_orig_stat++; - return selected_warp; - } else { - return -1; - } -} - -void shader_core_ctx::fetch_simd_postdominator() -{ - int warp_ok = 0; - bool complete = false; - int tmp_warp; - int warp_id; - - address_type check_pc = -1; - - // First, check to see if entire program is completed, - // if it is, then break out of loop - for (unsigned i=0; i<m_config->n_thread_per_shader; i++) { - if (!ptx_thread_done(i)) { - complete = false; - break; - } else { - complete = true; - } - } - if (complete) - return; - - if (fetch_stalled()) - return; - clear_stage_reg(TS_IF); - - unsigned ready_warp_count = 0; - for (unsigned i=0; i<m_config->max_warps_per_shader; i++) { - m_ready_warps[i]=-1; - m_tmp_ready_warps[i]=-1; - } - - // Finds a warp where all threads in it are available for fetching - // simultaneously(all threads are not yet in pipeline, or, the ones - // that are not available, are completed already - for (unsigned i=0; i<m_config->max_warps_per_shader; i++) { - if( m_warp[m_next_warp].waiting() ) { - // waiting for kernel launch, barrier, membar, atomic - } else if( (m_warp[m_next_warp].get_n_completed()+m_warp[m_next_warp].get_avail4fetch()) < m_config->warp_size) { - // waiting for instruction still in pipeline barrel processing - } else if ( !warp_scoreboard_hazard(m_next_warp) ) { - // this warp is ready and can be issued if selected - m_tmp_ready_warps[ready_warp_count] = m_next_warp; - ready_warp_count++; - } - m_next_warp = (m_next_warp + 1) % m_config->max_warps_per_shader; - } - for (unsigned i=0;i<ready_warp_count;i++) - m_ready_warps[i]=m_tmp_ready_warps[i]; - m_stats->num_warps_issuable[ready_warp_count]++; - m_stats->num_warps_issuable_pershader[m_sid]+= ready_warp_count; - if (ready_warp_count) { - tmp_warp = pdom_sched_find_next_warp (ready_warp_count); - if (tmp_warp != -1) { - m_next_warp = tmp_warp; - warp_ok=1; - } - } - - if (!warp_ok) { - // None of the instructions from inside the warp can be scheduled -> should - // probably just stall, ie nops into pipeline - clear_stage_reg(TS_IF); - m_next_warp = (m_next_warp+1) % m_config->max_warps_per_shader; - return; - } - - /************************************************************/ - // at this point we have a warp to execute which is pointed to by next_warp - - warp_id = m_next_warp; - m_last_warp = warp_id; - int wtid = m_config->warp_size*warp_id; - pdom_warp_ctx_t *scheduled_warp = m_pdom_warp[warp_id]; - - // schedule threads according to active mask on the top of pdom stack - unsigned active_mask = scheduled_warp->get_active_mask(); - - for (unsigned i = 0; i < m_config->warp_size; i++) { - unsigned int mask = (1 << i); - if ((active_mask & mask) == mask) { - assert (!ptx_thread_done(wtid+i)); - shader_issue_thread(wtid+i,i,active_mask); - } - } - m_next_warp = (m_next_warp+1)%m_config->max_warps_per_shader; - - // check if all issued threads have the same pc - for (unsigned i = 0; i < m_config->warp_size; i++) { - if ( m_pipeline_reg[TS_IF][i].hw_thread_id != -1 ) { - if ( check_pc == (unsigned)-1 ) { - check_pc = m_pipeline_reg[TS_IF][i].pc; - } else { - assert( check_pc == m_pipeline_reg[TS_IF][i].pc ); - } - } - } -} - -/** - * check if warp has data hazard - * - * @param warp_id - * - * @return bool : false if hazard exists - */ -bool shader_core_ctx::warp_scoreboard_hazard(int warp_id) -{ - inst_t active_inst; - - // Get an active thread in the warp - int wtid = m_config->warp_size*warp_id; - pdom_warp_ctx_t *scheduled_warp = m_pdom_warp[warp_id]; - thread_ctx_t *active_thread = NULL; - unsigned active_mask = scheduled_warp->get_active_mask(); - for (unsigned i = 0; i < m_config->warp_size; i++) { - unsigned int mask = (1 << i); - if ((active_mask & mask) == mask) { - active_thread = &(m_thread[wtid+i]); - } - } - if(active_thread == NULL) - return false; - - // Decode instruction - active_thread->m_functional_model_thread_state->ptx_fetch_inst( active_inst ); - return m_scoreboard->checkCollision(warp_id, &active_inst); -} - void pdom_warp_ctx_t::pdom_update_warp_mask() { int wtid = m_warp_size*m_warp_id; @@ -892,213 +617,6 @@ void shader_core_ctx::new_cache_window() m_L1C->shd_cache_new_window(); } -void shader_core_ctx::fetch_mimd() -{ - if (fetch_stalled()) - return; - clear_stage_reg(TS_IF); - - for (unsigned i=0, j=0;i<m_config->n_thread_per_shader && j< m_config->warp_size;i++) { - int thd_id = (i + m_last_issued_thread + 1) % m_config->n_thread_per_shader; - if (m_thread[thd_id].m_avail4fetch && !m_thread[thd_id].m_waiting_at_barrier ) { - shader_issue_thread(thd_id, j,(unsigned)-1); - m_last_issued_thread = thd_id; - j++; - } - } -} - -// seperate the incoming warp into multiple warps with seperate pcs -int shader_core_ctx::split_warp_by_pc(int *tid_in, int **tid_split, address_type *pc) -{ - unsigned n_pc = 0; - static int *pc_cnt = NULL; // count the number of threads with the same pc - - assert(tid_in); - assert(tid_split); - assert(pc); - memset(pc,0,sizeof(address_type)*m_config->warp_size); - - if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*m_config->warp_size); - memset(pc_cnt,0,sizeof(int)*m_config->warp_size); - - // go through each thread in the given warp - for (unsigned i=0; i< m_config->warp_size; i++) { - if (tid_in[i] < 0) continue; - int matched = 0; - address_type thd_pc; - thd_pc = next_pc(tid_in[i]); - - // check to see if the pc has occured before - for (unsigned j=0; j<n_pc; j++) { - if (thd_pc == pc[j]) { - tid_split[j][pc_cnt[j]] = tid_in[i]; - pc_cnt[j]++; - matched = 1; - break; - } - } - // if not, put the tid in a seperate warp - if (!matched) { - assert(n_pc < m_config->warp_size); - tid_split[n_pc][0] = tid_in[i]; - pc[n_pc] = thd_pc; - pc_cnt[n_pc] = 1; - n_pc++; - } - } - return n_pc; -} - -// see if this warp just executed the barrier instruction -int shader_core_ctx::warp_reached_barrier(int *tid_in) -{ - int reached_barrier = 0; - for (unsigned i=0; i<m_config->warp_size; i++) { - if (tid_in[i] < 0) continue; - if (m_thread[tid_in[i]].m_reached_barrier) { - reached_barrier = 1; - break; - } - } - return reached_barrier; -} - -// seperate the incoming warp into multiple warps with seperate pcs and cta -int shader_core_ctx::split_warp_by_cta(int *tid_in, int **tid_split, address_type *pc, int *cta) -{ - unsigned n_pc = 0; - static int *pc_cnt = NULL; // count the number of threads with the same pc - - assert(tid_in); - assert(tid_split); - assert(pc); - memset(pc,0,sizeof(address_type)*m_config->warp_size); - - if (!pc_cnt) pc_cnt = (int*) malloc(sizeof(int)*m_config->warp_size); - memset(pc_cnt,0,sizeof(int)*m_config->warp_size); - - // go through each thread in the given warp - for (unsigned i=0; i<m_config->warp_size; i++) { - if (tid_in[i] < 0) continue; - int matched = 0; - address_type thd_pc; - thd_pc = next_pc(tid_in[i]); - - int thd_cta = ptx_thread_get_cta_uid( m_thread[tid_in[i]].m_functional_model_thread_state ); - - // check to see if the pc has occured before - for (unsigned j=0; j<n_pc; j++) { - if (thd_pc == pc[j] && thd_cta == cta[j]) { - tid_split[j][pc_cnt[j]] = tid_in[i]; - pc_cnt[j]++; - matched = 1; - break; - } - } - // if not, put the tid in a seperate warp - if (!matched) { - assert(n_pc < m_config->warp_size); - tid_split[n_pc][0] = tid_in[i]; - pc[n_pc] = thd_pc; - cta[n_pc] = thd_cta; - pc_cnt[n_pc] = 1; - n_pc++; - } - } - return n_pc; -} - -void shader_core_ctx::fetch_simd_dwf() -{ - static int *tid_in = NULL; - static int *tid_out = NULL; - - if (!tid_in) { - tid_in = (int*) malloc(sizeof(int)*m_config->warp_size); - memset(tid_in, -1, sizeof(int)*m_config->warp_size); - } - if (!tid_out) { - tid_out = (int*) malloc(sizeof(int)*m_config->warp_size); - memset(tid_out, -1, sizeof(int)*m_config->warp_size); - } - - - static int **tid_split = NULL; - if (!tid_split) { - tid_split = (int**)malloc(sizeof(int*)*m_config->warp_size); - tid_split[0] = (int*)malloc(sizeof(int)*m_config->warp_size*m_config->warp_size); - for (unsigned i=1; i<m_config->warp_size; i++) { - tid_split[i] = tid_split[0] + m_config->warp_size * i; - } - } - - static address_type *thd_pc = NULL; - if (!thd_pc) thd_pc = (address_type*)malloc(sizeof(address_type)*m_config->warp_size); - static int *thd_cta = NULL; - if (!thd_cta) thd_cta = (int*)malloc(sizeof(int)*m_config->warp_size); - - int warpupdate_bw = 1; - while (!m_thd_commit_queue->empty() && warpupdate_bw > 0) { - // grab a committed warp, split it into multiple BRUs (tid_split) by PC - std::vector<int> *tid_commit = m_thd_commit_queue->pop(gpu_sim_cycle); - memset(tid_split[0], -1, sizeof(int)*m_config->warp_size*m_config->warp_size); - memset(thd_pc, 0, sizeof(address_type)*m_config->warp_size); - memset(thd_cta, -1, sizeof(int)*m_config->warp_size); - - int reached_barrier = warp_reached_barrier(tid_commit->data()); - - unsigned n_warp_update; - if (reached_barrier) { - n_warp_update = split_warp_by_cta(tid_commit->data(), tid_split, thd_pc, thd_cta); - } else { - n_warp_update = split_warp_by_pc(tid_commit->data(), tid_split, thd_pc); - } - - if (n_warp_update > 2) m_stats->gpgpu_commit_pc_beyond_two++; - warpupdate_bw -= n_warp_update; - // put the splitted warp updates into the DWF scheduler - for (unsigned i=0;i<n_warp_update;i++) { - for (unsigned j=0;j<m_config->warp_size;j++) { - if (tid_split[i][j] < 0) continue; - assert(m_thread[tid_split[i][j]].m_avail4fetch); - assert(!m_thread[tid_split[i][j]].m_in_scheduler); - m_thread[tid_split[i][j]].m_in_scheduler = true; - } - dwf_clear_accessed(m_sid); - if (reached_barrier) { - dwf_update_warp_at_barrier(m_sid, tid_split[i], thd_pc[i], thd_cta[i]); - } else { - dwf_update_warp(m_sid, tid_split[i], thd_pc[i]); - } - } - - delete tid_commit; - } - - // Track the #PC right after the warps are input to the scheduler - dwf_update_statistics(m_sid); - dwf_clear_policy_access(m_sid); - - if (fetch_stalled()) { - return; - } - clear_stage_reg(TS_IF); - - address_type scheduled_pc; - dwf_issue_warp(m_sid, tid_out, &scheduled_pc); - - for (unsigned i=0; i<m_config->warp_size; i++) { - int issue_tid = tid_out[i]; - if (issue_tid >= 0) { - shader_issue_thread(issue_tid, i, (unsigned)-1); - m_thread[issue_tid].m_in_scheduler = false; - m_thread[issue_tid].m_reached_barrier = false; - assert(m_pipeline_reg[TS_IF][i].pc == scheduled_pc); - } - } -} - void gpgpu_sim::print_shader_cycle_distro( FILE *fout ) const { fprintf(fout, "Warp Occupancy Distribution:\n"); @@ -1120,11 +638,11 @@ void shader_core_ctx::fetch_new() if( m_inst_fetch_buffer.m_valid ) { // decode 1 or 2 instructions and place them into ibuffer address_type pc = m_inst_fetch_buffer.m_pc; - const inst_t* pI1 = ptx_fetch_inst(pc); + const warp_inst_t* pI1 = ptx_fetch_inst(pc); assert(pI1); m_warp[m_inst_fetch_buffer.m_warp_id].ibuffer_fill(0,pI1); m_warp[m_inst_fetch_buffer.m_warp_id].inc_inst_in_pipeline(); - const inst_t* pI2 = ptx_fetch_inst(pc+pI1->isize); + const warp_inst_t* pI2 = ptx_fetch_inst(pc+pI1->isize); if( pI2 ) { m_warp[m_inst_fetch_buffer.m_warp_id].ibuffer_fill(1,pI2); m_warp[m_inst_fetch_buffer.m_warp_id].inc_inst_in_pipeline(); @@ -1207,60 +725,38 @@ int is_local ( memory_space_t space ) } -void shader_core_ctx::ptx_exec_inst( inst_t &inst ) +void shader_core_ctx::func_exec_inst( warp_inst_t &inst ) { - m_thread[inst.hw_thread_id].m_functional_model_thread_state->ptx_exec_inst(inst); - if( inst.callback.function != NULL ) - m_warp[inst.hw_thread_id/m_config->warp_size].inc_n_atomic(); - if (is_local(inst.space.get_type()) && (is_load(inst) || is_store(inst))) - inst.memreqaddr = translate_local_memaddr(inst.memreqaddr, inst.hw_thread_id, m_gpu->num_shader()); -} - -void shader_core_ctx::issue_warp( const inst_t *pI, unsigned active_mask, inst_t *&warp, unsigned warp_id ) -{ - m_warp[warp_id].ibuffer_free(); - assert(pI->valid()); - unsigned cta_id = (unsigned)-1; for ( unsigned t=0; t < m_config->warp_size; t++ ) { - unsigned tid=m_config->warp_size*warp_id+t; - warp[t] = *pI; - warp[t].warp_active_mask = active_mask; - if( active_mask & (1<<t) ) { - cta_id = m_thread[tid].m_cta_id; - warp[t].hw_thread_id = tid; - warp[t].wlane = t; - warp[t].uid = g_next_shader_inst_uid++; - warp[t].issue_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - ptx_exec_inst( warp[t] ); + if( inst.active(t) ) { + unsigned tid=m_config->warp_size*inst.warp_id()+t; + m_thread[tid].m_functional_model_thread_state->ptx_exec_inst(inst,t); + if( inst.has_callback(t) ) + m_warp[inst.warp_id()].inc_n_atomic(); + if (is_local(inst.space.get_type()) && (is_load(inst) || is_store(inst))) + inst.set_addr(t, translate_local_memaddr(inst.get_addr(t), tid, m_gpu->num_shader()) ); if ( ptx_thread_done(tid) ) { - m_warp[warp_id].inc_n_completed(); - m_warp[warp_id].ibuffer_flush(); + m_warp[inst.warp_id()].inc_n_completed(); + m_warp[inst.warp_id()].ibuffer_flush(); } } } - assert( cta_id != (unsigned)-1 ); - if( pI->op == BARRIER_OP ) - set_at_barrier(cta_id,warp_id); - else if( pI->op == MEMORY_BARRIER_OP ) +} + +void shader_core_ctx::issue_warp( warp_inst_t *&pipe_reg, const warp_inst_t *next_inst, unsigned active_mask, unsigned warp_id ) +{ + m_warp[warp_id].ibuffer_free(); + assert(next_inst->valid()); + *pipe_reg = *next_inst; // static instruction information + pipe_reg->issue( active_mask, warp_id, gpu_tot_sim_cycle + gpu_sim_cycle ); // dynamic instruction information + func_exec_inst( *pipe_reg ); + if( next_inst->op == BARRIER_OP ) + set_at_barrier(m_warp[warp_id].get_cta_id(),warp_id); + else if( next_inst->op == MEMORY_BARRIER_OP ) set_at_memory_barrier(warp_id); m_pdom_warp[warp_id]->pdom_update_warp_mask(); - m_scoreboard->reserveRegisters(warp_id, pI); - m_warp[warp_id].set_next_pc(pI->pc + pI->isize); - - ///// - memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size); - int n_thd_in_warp = 0; - for (unsigned i=0; i<m_config->warp_size; i++) { - m_fetch_tid_out[i] = warp[i].hw_thread_id; - if (m_fetch_tid_out[i] >= 0) - n_thd_in_warp += 1; - } - - m_new_warp_TS = false; - - // warp tracker keeps track of warps in the pipeline, let it know we are going to issue this warp - assert( n_thd_in_warp > 0 ); - m_warp_tracker->wpt_register_warp(m_fetch_tid_out, pI->pc, n_thd_in_warp,m_config->warp_size); + m_scoreboard->reserveRegisters(warp_id, next_inst); + m_warp[warp_id].set_next_pc(next_inst->pc + next_inst->isize); } void shader_core_ctx::decode_new() @@ -1271,7 +767,7 @@ void shader_core_ctx::decode_new() unsigned issued=0; while( !m_warp[warp_id].waiting() && !m_warp[warp_id].ibuffer_empty() && (checked < 2) && (issued < 2) ) { unsigned active_mask = m_pdom_warp[warp_id]->get_active_mask(); - const inst_t *pI = m_warp[warp_id].ibuffer_next(); + const warp_inst_t *pI = m_warp[warp_id].ibuffer_next(); unsigned pc,rpc; m_pdom_warp[warp_id]->get_pdom_stack_top_info(&pc,&rpc); if( pI ) { @@ -1281,11 +777,11 @@ void shader_core_ctx::decode_new() m_warp[warp_id].ibuffer_flush(); } else if ( !m_scoreboard->checkCollision(warp_id, pI) ) { assert( m_warp[warp_id].inst_in_pipeline() ); - if ( (pI->op != SFU_OP) && pipeline_regster_empty(m_pipeline_reg[ID_OC]) ) { - issue_warp(pI, active_mask, m_pipeline_reg[ID_OC], warp_id); + if ( (pI->op != SFU_OP) && m_pipeline_reg[ID_OC]->empty() ) { + issue_warp(m_pipeline_reg[ID_OC],pI,active_mask,warp_id); issued++; - } else if ( (pI->op == SFU_OP || pI->op == ALU_SFU_OP) && pipeline_regster_empty(m_pipeline_reg[ID_OC_SFU]) ) { - issue_warp(pI, active_mask, m_pipeline_reg[ID_OC_SFU], warp_id); + } else if ( (pI->op == SFU_OP || pI->op == ALU_SFU_OP) && m_pipeline_reg[ID_OC_SFU]->empty() ) { + issue_warp(m_pipeline_reg[ID_OC_SFU],pI,active_mask,warp_id); issued++; } } @@ -1300,92 +796,6 @@ void shader_core_ctx::decode_new() } } -void shader_core_ctx::fetch() -{ - // check if decode stage is stalled - bool decode_stalled = !pipeline_regster_empty( m_pipeline_reg[IF_ID] ); - - // find a ready warp and put it in the TS_IF pipeline register - switch (m_config->model) { - case POST_DOMINATOR: fetch_simd_postdominator(); break; - case DWF: fetch_simd_dwf(); break; - case MIMD: fetch_mimd(); break; - default: fprintf(stderr, "Unknown scheduler: %d\n", m_config->model); assert(0); break; - } - - memset(m_fetch_tid_out, -1, sizeof(int)*m_config->warp_size); - - if (m_config->gpgpu_no_divg_load && m_new_warp_TS && !decode_stalled) { - - // count number of active threads in this warp, determine PC value - // record active threads in tid_out - int n_thd_in_warp = 0; - address_type pc_out = 0xDEADBEEF; - for (unsigned i=0; i<m_config->warp_size; i++) { - m_fetch_tid_out[i] = m_pipeline_reg[TS_IF][i].hw_thread_id; - if (m_fetch_tid_out[i] >= 0) { - n_thd_in_warp += 1; - pc_out = m_pipeline_reg[TS_IF][i].pc; - } - } - - m_new_warp_TS = false; - - // warp tracker keeps track of warps in the pipeline, let it know we are going to issue this warp - if( n_thd_in_warp > 0 ) - m_warp_tracker->wpt_register_warp(m_fetch_tid_out, pc_out, n_thd_in_warp,m_config->warp_size); - - // some statistics collection - if (gpu_runtime_stat_flag & GPU_RSTAT_DWF_MAP) - m_thread_pc_tracker->set_threads_pc( m_fetch_tid_out, pc_out ); - if (gpgpu_cflog_interval != 0) { - insn_warp_occ_log( m_sid, pc_out, n_thd_in_warp); - shader_warp_occ_log( m_sid, n_thd_in_warp); - } - if ( m_config->gpgpu_warpdistro_shader < 0 || m_sid == (unsigned)m_config->gpgpu_warpdistro_shader ) { - m_stats->shader_cycle_distro[n_thd_in_warp + 2] += 1; - if (n_thd_in_warp == 0) - if (m_pending_mem_access == 0) - m_stats->shader_cycle_distro[1]++; - } - } else { - if ( m_config->gpgpu_warpdistro_shader < 0 || m_sid == (unsigned)m_config->gpgpu_warpdistro_shader ) { - m_stats->shader_cycle_distro[0] += 1; - } - } - - if (!decode_stalled) { - for (unsigned i = 0; i < m_config->warp_size; i++) { - int tid_tsif = m_pipeline_reg[TS_IF][i].hw_thread_id; - address_type pc_out = m_pipeline_reg[TS_IF][i].pc; - cflog_update_thread_pc(m_sid, tid_tsif, pc_out); - } - } - - if (enable_ptx_file_line_stats && !decode_stalled) { - int TS_stage_empty = 1; - for (unsigned i = 0; i < m_config->warp_size; i++) { - if (m_pipeline_reg[TS_IF][i].hw_thread_id >= 0) { - TS_stage_empty = 0; - break; - } - } - if (TS_stage_empty) { - if (enable_ptx_file_line_stats) - ptx_file_line_stats_commit_exposed_latency(m_sid, 1); - } - } - - // if not, send the warp part to decode stage - if (!decode_stalled) { - check_stage_pcs(TS_IF); - inst_t *fvi = first_valid_thread(m_pipeline_reg[TS_IF]); - if( fvi ) - m_warp[fvi->hw_thread_id/m_config->warp_size].set_last_fetch(gpu_sim_cycle); - move_warp(m_pipeline_reg[IF_ID],m_pipeline_reg[TS_IF]); - } -} - address_type coalesced_segment(address_type addr, unsigned segment_size_lg2bytes) { return (addr >> segment_size_lg2bytes); @@ -1419,232 +829,16 @@ address_type shader_core_ctx::translate_local_memaddr(address_type localaddr, in ///////////////////////////////////////////////////////////////////////////////////////// -void shader_core_ctx::decode() -{ - op_type op = NO_OP; - unsigned warp_id = -1; - unsigned cta_id = -1; - - address_type regs_regs_PC = 0xDEADBEEF; - address_type warp_current_pc = 0x600DBEEF; - address_type warp_next_pc = 0x600DBEEF; - int warp_diverging = 0; - const int nextstage = (m_config->gpgpu_operand_collector) ? ID_OC : \ - (m_config->m_using_dwf_rrstage ? ID_RR : ID_EX); - - if( !pipeline_regster_empty(m_pipeline_reg[nextstage]) ) - return; - - check_stage_pcs(IF_ID); - - // decode the instruction - int first_valid_thread = -1; - for (unsigned i=0; i<m_config->warp_size;i++) { - if (m_pipeline_reg[IF_ID][i].hw_thread_id == -1 ) - continue; /* bubble or masked off */ - if (first_valid_thread == -1) { - first_valid_thread = i; - op = m_pipeline_reg[IF_ID][i].op; - int tid = m_pipeline_reg[IF_ID][i].hw_thread_id; - warp_id = tid/m_config->warp_size; - assert( !warp_waiting_at_barrier(warp_id) ); - cta_id = m_thread[tid].m_cta_id; - } - } - - // execute the instruction functionally - short last_hw_thread_id = -1; - bool first_thread_in_warp = true; - for (unsigned i=0; i<m_config->warp_size;i++) { - if (m_pipeline_reg[IF_ID][i].hw_thread_id == -1 ) - continue; /* bubble or masked off */ - - if(last_hw_thread_id > -1) - first_thread_in_warp = false; - last_hw_thread_id = m_pipeline_reg[IF_ID][i].hw_thread_id; - - /* get the next instruction to execute from fetch stage */ - int tid = m_pipeline_reg[IF_ID][i].hw_thread_id; - - // Functionally execute instruction - m_thread[tid].m_functional_model_thread_state->ptx_exec_inst( m_pipeline_reg[IF_ID][i] ); - if( m_pipeline_reg[IF_ID][i].callback.function != NULL ) - m_warp[warp_id].inc_n_atomic(); - if (is_local(m_pipeline_reg[IF_ID][i].space) && (is_load(m_pipeline_reg[IF_ID][i]) || is_store(m_pipeline_reg[IF_ID][i]))) - m_pipeline_reg[IF_ID][i].memreqaddr = translate_local_memaddr(m_pipeline_reg[IF_ID][i].memreqaddr, tid, m_gpu->num_shader()); - - // Mark destination registers as write-pending in scoreboard - // Only do this for the first thread in warp - if(first_thread_in_warp) - m_scoreboard->reserveRegisters(warp_id, &(m_pipeline_reg[IF_ID][i])); - warp_current_pc = m_pipeline_reg[IF_ID][i].pc; - regs_regs_PC = next_pc( tid ); - - if ( ptx_thread_at_barrier( m_thread[tid].m_functional_model_thread_state ) ) { - if (m_config->model == DWF) { - m_thread[tid].m_waiting_at_barrier=true; - m_thread[tid].m_reached_barrier=true; // not reset at barrier release, but at the issue after that - m_warp[wid_from_hw_tid(tid,m_config->warp_size)].inc_waiting_at_barrier(); - int cta_uid = ptx_thread_get_cta_uid( m_thread[tid].m_functional_model_thread_state ); - dwf_hit_barrier( m_sid, cta_uid ); - - int release = ptx_thread_all_at_barrier( m_thread[tid].m_functional_model_thread_state ); //test if all threads arrived at the barrier - if ( release ) { //All threads arrived at barrier...releasing - int cta_uid = ptx_thread_get_cta_uid( m_thread[tid].m_functional_model_thread_state ); - for ( unsigned t=0; t < m_config->n_thread_per_shader; ++t ) { - if ( !ptx_thread_at_barrier( m_thread[t].m_functional_model_thread_state ) ) - continue; - int other_cta_uid = ptx_thread_get_cta_uid( m_thread[t].m_functional_model_thread_state ); - if ( other_cta_uid == cta_uid ) { //reseting @barrier tracking info - m_warp[wid_from_hw_tid(t,m_config->warp_size)].clear_waiting_at_barrier(); - m_thread[t].m_waiting_at_barrier=false; - ptx_thread_reset_barrier( m_thread[t].m_functional_model_thread_state ); - } - } - if (m_config->model == DWF) { - dwf_release_barrier( m_sid, cta_uid ); - } - ptx_thread_release_barrier( m_thread[tid].m_functional_model_thread_state ); - } - } - } else { - assert( !m_thread[tid].m_waiting_at_barrier ); - } - - // branch divergence detection - if (warp_next_pc != regs_regs_PC) { - if (warp_next_pc == 0x600DBEEF) { - warp_next_pc = regs_regs_PC; - } else { - warp_diverging = 1; - } - } - } - - move_warp(m_pipeline_reg[nextstage],m_pipeline_reg[IF_ID]); - - if( op == BARRIER_OP ) - set_at_barrier(cta_id,warp_id); - else if( op == MEMORY_BARRIER_OP ) - set_at_memory_barrier(warp_id); - - m_n_diverge += warp_diverging; - if (warp_diverging == 1) { - assert(warp_current_pc != 0x600DBEEF); // guard against empty warp causing warp divergence - ptx_file_line_stats_add_warp_divergence(warp_current_pc, 1); - } -} - -unsigned int n_regconflict_stall = 0; - - -int regfile_hash(signed thread_number, unsigned simd_size, unsigned n_banks) { - if (gpgpu_thread_swizzling) { - signed warp_ID = thread_number / simd_size; - return((thread_number + warp_ID) % n_banks); - } else { - return(thread_number % n_banks); - } -} - -void shader_core_ctx::preexecute() -{ - if( m_config->gpgpu_dwf_reg_bankconflict) { - // Model register bank conflicts as in - // Fung et al. MICRO'07 / ACM TACO'09 papers. - // - // This models conflicts due to moving threads to different SIMD lanes - // (which occur if not using "lane aware" dynamic warp formation). - - inst_t *fvi = first_valid_thread(m_pipeline_reg[RR_EX]); - if( fvi ) { - if (m_dwf_RR_k) { - //stalled due to register access conflict, but can still service a register read - m_dwf_RR_k--; - return; - } - - int n_access_per_cycle = m_config->warp_size / m_config->gpgpu_dwf_rr_stage_n_reg_banks; - int max_reg_bank_acc = 0; - for (unsigned i=0; i<m_config->gpgpu_dwf_rr_stage_n_reg_banks; i++) - m_dwf_rrstage_bank_access_counter[i] = 0; - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[ID_RR][i].hw_thread_id != -1 ) - m_dwf_rrstage_bank_access_counter[regfile_hash(m_pipeline_reg[ID_RR][i].hw_thread_id, - m_config->warp_size, - m_config->gpgpu_dwf_rr_stage_n_reg_banks)]++; - } - for (unsigned i=0; i<m_config->gpgpu_dwf_rr_stage_n_reg_banks; i++) { - if (m_dwf_rrstage_bank_access_counter[i] > max_reg_bank_acc ) - max_reg_bank_acc = m_dwf_rrstage_bank_access_counter[i]; - } - // calculate the number of cycles needed for each register bank to fulfill all accesses - m_dwf_RR_k = (max_reg_bank_acc / n_access_per_cycle) + ((max_reg_bank_acc % n_access_per_cycle)? 1 : 0); - - // if there is more than one access cycle needed at a bank, stall - if (m_dwf_RR_k > 1) { - n_regconflict_stall++; - m_dwf_RR_k--; - return; - } - } - - check_stage_pcs(ID_RR); - m_dwf_RR_k = 0; - } - - if( pipeline_regster_empty(m_pipeline_reg[ID_EX]) ) - move_warp(m_pipeline_reg[ID_EX],m_pipeline_reg[ID_RR]); -} - - void shader_core_ctx::execute_pipe( unsigned pipeline, unsigned next_stage ) { - if (m_config->gpgpu_pre_mem_stages) { - if( !pipeline_regster_empty(pre_mem_pipeline[0]) ) - return; // stalled - } else { - if( !pipeline_regster_empty(m_pipeline_reg[next_stage]) ) - return; // stalled - } - - check_stage_pcs(ID_EX); - - // Check that all threads have the same delay cycles - unsigned cycles = -1; - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[pipeline][i].hw_thread_id == -1 ) - continue; // bubble - if(cycles == (unsigned)-1) - cycles = m_pipeline_reg[pipeline][i].cycles; - else { - if( cycles != m_pipeline_reg[pipeline][i].cycles ) { - printf("Shader %d: threads do not have the same delay cycles.\n", m_sid); - assert(0); - } - } - } - - bool stall_inst_not_done = false; - for (unsigned i=0; i<m_config->warp_size; i++) { - if (m_pipeline_reg[pipeline][i].hw_thread_id == -1 ) - continue; - m_pipeline_reg[pipeline][i].cycles--; - if( m_pipeline_reg[pipeline][i].cycles > 0 ) { - // Stall here to model instruction throughput for different types of instructions - stall_inst_not_done=true; - continue; - } - } - if( stall_inst_not_done ) - return; - if (m_config->gpgpu_pre_mem_stages) { - move_warp(pre_mem_pipeline[0], m_pipeline_reg[pipeline]); - } else { - move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]); - // inform memory stage that a new instruction has arrived - m_shader_memory_new_instruction_processed = false; - } + if( !m_pipeline_reg[next_stage]->empty() ) + return; + if( m_pipeline_reg[pipeline]->cycles ) { + m_pipeline_reg[pipeline]->cycles--; + return; + } + move_warp(m_pipeline_reg[next_stage],m_pipeline_reg[pipeline]); + m_shader_memory_new_instruction_processed = false; } void shader_core_ctx::execute() @@ -1653,32 +847,15 @@ void shader_core_ctx::execute() execute_pipe(ID_EX, EX_MM); } -void shader_core_ctx::pre_memory() -{ - // This stage can be used to approximately model a deeper pipeline. - // The main effect this models is the register read-after-write delay. - // We walk through pre-memory stages in reverse order - // (highest number = stage closest to writeback, 0 = stage closest to fetch - if( pipeline_regster_empty(m_pipeline_reg[EX_MM]) ) { - move_warp( m_pipeline_reg[EX_MM], pre_mem_pipeline[m_config->gpgpu_pre_mem_stages] ); - // inform memory stage that a new instruction has arrived - m_shader_memory_new_instruction_processed = false; - } - for (unsigned j = m_config->gpgpu_pre_mem_stages; j > 0; j--) { - if( pipeline_regster_empty(pre_mem_pipeline[j]) ) - move_warp( pre_mem_pipeline[j], pre_mem_pipeline[j-1]); - } -} - -mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, inst_t* warp) +mshr_entry* mshr_shader_unit::add_mshr(mem_access_t &access, warp_inst_t* warp) { - //creates an mshr based on the access struct information + // creates an mshr based on the access struct information mshr_entry* mshr = alloc_free_mshr(access.space == tex_space); - mshr->init(access.addr,access.iswrite,access.space,warp->hw_thread_id/m_shader_config->warp_size); + mshr->init(access.addr,access.iswrite,access.space,warp->warp_id()); assert(access.warp_indices.size()); //code assumes at least one instruction attached to mshr. for (unsigned i = 0; i < access.warp_indices.size(); i++) mshr->add_inst(warp[access.warp_indices[i]]); - if (m_shader_config->gpgpu_interwarp_mshr_merge) { + if( m_shader_config->gpgpu_interwarp_mshr_merge ) { mshr_entry* mergehit = m_mshr_lookup.shader_get_mergeable_mshr(mshr); if (mergehit) { mergehit->merge(mshr); @@ -1732,7 +909,7 @@ void shader_core_ctx::get_memory_access_list( bool limit_broadcast, std::vector<mem_access_t> &accessq ) { - const inst_t* insns = m_pipeline_reg[EX_MM]; + const warp_inst_t* insns = m_pipeline_reg[EX_MM]; // Calculates memory accesses generated by this warp // Returns acesses which are "coalesced" // Does not coalesce nor overlap bank accesses across warp "parts". @@ -1768,28 +945,23 @@ void shader_core_ctx::get_memory_access_list( unsigned mem_pipe_size = m_config->warp_size / warp_parts; for (unsigned part = 0; part < m_config->warp_size; part += mem_pipe_size) { for (unsigned i = part; i < part + mem_pipe_size; i++) { - if ( insns[i].hw_thread_id == -1 ) + if ( !insns->active(i) ) continue; - - if( insns[i].space == undefined_space ) { - // Instruction must have been predicated off - continue; - } - - address_type lane_segment_address = tag_func(insns[i].memreqaddr, line_size); + if( insns->space == undefined_space ) + continue; // this happens when thread predicated off + new_addr_type addr = insns->get_addr(i); + address_type lane_segment_address = tag_func(addr, line_size); unsigned quarter = 0; if( line_size>=4 ) - quarter = (insns[i].memreqaddr / (line_size/4)) & 3; - bool isatomic = (insns[i].callback.function != NULL); + quarter = (addr / (line_size/4)) & 3; bool match = false; - if (not isatomic) { //atomics must have own request + if( !insns->isatomic() ) { //atomics must have own request for (unsigned j = qpartbegin; j < accessq.size(); j++) { if (lane_segment_address == accessq[j].addr) { assert( not accessq[j].isatomic ); accessq[j].quarter_count[quarter]++; accessq[j].warp_indices.push_back(i); - if (limit_broadcast) - // two threads access this address, so its a broadcast. + if (limit_broadcast) // two threads access this address, so its a broadcast. accessq[j].order = ++broadcast_order; //do broadcast in its own cycle. match = true; break; @@ -1797,15 +969,15 @@ void shader_core_ctx::get_memory_access_list( } } if (!match) { // does not match an previous request by another thread, so need a new request - assert( insns[i].space != undefined_space ); + assert( insns->space != undefined_space ); accessq.push_back( mem_access_t( lane_segment_address, - insns[i].space, + insns->space, mem_pipe, - isatomic, - is_store(insns[i]), + insns->isatomic(), + is_store(*insns), line_size, quarter, i) ); // Determine Bank Conflicts: - unsigned bank = (this->*bank_func)(insns[i].memreqaddr, line_size); + unsigned bank = (this->*bank_func)(insns->get_addr(i), line_size); // ensure no concurrent bank access accross warp parts. // ie. order will be less than part for all previous loads in previous parts, so: if (bank_accs[bank] < part) @@ -1820,7 +992,6 @@ void shader_core_ctx::get_memory_access_list( std::stable_sort(accessq.begin()+qbegin,accessq.end()); } - void shader_core_ctx::memory_shared_process_warp() { // initial processing of shared memory warps @@ -1835,31 +1006,31 @@ void shader_core_ctx::memory_shared_process_warp() void shader_core_ctx::memory_const_process_warp() { - // initial processing of const memory warps - std::vector<mem_access_t> &accessq = m_memory_queue.constant; - unsigned qbegin = accessq.size(); - get_memory_access_list( - &shader_core_ctx::null_bank_func, - line_size_based_tag_func, - CONSTANT_MEM_PATH, - 1, //warp parts - m_L1C->get_line_sz(), false, //no broadcast limit. - accessq); - //do cache checks here for each request (non-physical), could be done later for more accurate timing of cache accesses, but probably uneccesary; - for (unsigned i = qbegin; i < accessq.size(); i++) { - if ( accessq[i].space == param_space_kernel ) { - accessq[i].cache_hit = true; - } else { - cache_request_status status = m_L1C->access( accessq[i].addr, - 0, //should always be a read - gpu_sim_cycle+gpu_tot_sim_cycle, - NULL/*should never writeback*/); - accessq[i].cache_hit = (status == HIT); - if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true; - if (accessq[i].cache_hit) m_stats->L1_const_miss++; - } - accessq[i].cache_checked = true; - } + // initial processing of const memory warps + std::vector<mem_access_t> &accessq = m_memory_queue.constant; + unsigned qbegin = accessq.size(); + get_memory_access_list( &shader_core_ctx::null_bank_func, + line_size_based_tag_func, + CONSTANT_MEM_PATH, + 1, //warp parts + m_L1C->get_line_sz(), false, //no broadcast limit. + accessq); + // do cache checks here for each request (non-physical), could be + // done later for more accurate timing of cache accesses, but probably uneccesary; + for (unsigned i = qbegin; i < accessq.size(); i++) { + if ( accessq[i].space == param_space_kernel ) { + accessq[i].cache_hit = true; + } else { + cache_request_status status = m_L1C->access( accessq[i].addr, + 0, //should always be a read + gpu_sim_cycle+gpu_tot_sim_cycle, + NULL/*should never writeback*/); + accessq[i].cache_hit = (status == HIT); + if (m_config->gpgpu_perfect_mem) accessq[i].cache_hit = true; + if (accessq[i].cache_hit) m_stats->L1_const_miss++; + } + accessq[i].cache_checked = true; + } } void shader_core_ctx::memory_texture_process_warp() @@ -1874,7 +1045,8 @@ void shader_core_ctx::memory_texture_process_warp() m_L1T->get_line_sz(), false, //no broadcast limit. accessq); - //do cache checks here for each request (non-hardware), could be done later for more accurate timing of cache accesses, but probably uneccesary; + // do cache checks here for each request (non-hardware), could be done later + // for more accurate timing of cache accesses, but probably uneccesary; for (unsigned i = qbegin; i < accessq.size(); i++) { cache_request_status status = m_L1T->access( accessq[i].addr, 0, //should always be a read @@ -1896,7 +1068,7 @@ void shader_core_ctx::memory_global_process_warp() if (m_config->gpgpu_coalesce_arch == 13) { warp_parts = 2; if(m_config->gpgpu_no_dl1) { - unsigned data_size = first_valid_thread( m_pipeline_reg[EX_MM] )->data_size; + unsigned data_size = m_pipeline_reg[EX_MM]->data_size; // line size is dependant on instruction; switch (data_size) { case 1: line_size = 32; break; @@ -1940,15 +1112,11 @@ void shader_core_ctx::memory_global_process_warp() } } } - - mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) { - //Atempt to send an request/write to memory based on information in access. - - inst_t* warp = m_pipeline_reg[EX_MM]; - inst_t* req_head = warp + access.warp_indices[0]; + // Attempt to send an request/write to memory based on information in access. + warp_inst_t* warp = m_pipeline_reg[EX_MM]; // If the cache told us it needed to write back a dirty line, do this now // It is possible to do this writeback in the same cycle as the access request, this may not be realistic. @@ -1976,7 +1144,7 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) default: assert(0); break; } //reserve mshr - bool requires_mshr = (m_config->model != MIMD) and (not access.iswrite); + bool requires_mshr = (not access.iswrite); if (requires_mshr and not access.reserved_mshr) { if (not m_mshr_unit->has_mshr(1)) return MSHR_RC_FAIL; @@ -2001,46 +1169,34 @@ mem_stage_stall_type shader_core_ctx::send_mem_request(mem_access_t &access) } //send over interconnect partial_write_mask_t write_mask = NO_PARTIAL_WRITE; - unsigned warp_id = req_head->hw_thread_id/m_config->warp_size; + unsigned warp_id = warp->warp_id(); if (access.iswrite) { if (!strcmp("GT200",m_config->pipeline_model) ) m_warp[warp_id].inc_store_req(); for (unsigned i=0;i < access.warp_indices.size();i++) { unsigned w = access.warp_indices[i]; - int data_offset = warp[w].memreqaddr & ((unsigned long long int)access.req_size - 1); - for (unsigned b = data_offset; b < data_offset + warp[w].data_size; b++) write_mask.set(b); + int data_offset = warp->get_addr(w) & ((unsigned long long int)access.req_size - 1); + for (unsigned b = data_offset; b < data_offset + warp->data_size; b++) write_mask.set(b); } if (write_mask.count() != access.req_size) m_stats->gpgpu_n_partial_writes++; } fq_push( access.addr, request_size, access.iswrite, write_mask, warp_id , access.reserved_mshr, - access_type, req_head->pc); - } - - // book keeping for mshr : this request is done (sent/accounted for) - if (requires_mshr) { - for (unsigned i = 0; i < access.warp_indices.size(); i++) { - unsigned o = access.warp_indices[i]; - m_pending_mem_access++; - if (enable_ptx_file_line_stats) - ptx_file_line_stats_add_inflight_memory_insn(m_sid, warp[o].pc); - } - - // Scoreboard addition: do not make cache miss instructions wait for memory, - // let the scoreboard handle stalling of instructions. - // Mark thread as a cache miss - if (not access.iswrite) { - // set the pipeline instructions in this request to noops, they all wait for memory; - for (unsigned i = 0; i < access.warp_indices.size(); i++) { - unsigned o = access.warp_indices[i]; - m_pipeline_reg[EX_MM][o].cache_miss = true; - } - } + access_type, warp->pc ); } return NO_RC_FAIL; } +void shader_core_ctx::writeback() +{ + mshr_entry *m = m_mshr_unit->return_head(); + if( m ) + m_mshr_unit->pop_return_head(); + if( !m_pipeline_reg[MM_WB]->empty() ) + m_scoreboard->releaseRegisters( m_pipeline_reg[MM_WB] ); + move_warp(m_pipeline_reg[WB_RT],m_pipeline_reg[MM_WB]); +} bool shader_core_ctx::memory_shared_cycle( mem_stage_stall_type &rc_fail, mem_stage_access_type &fail_type) { @@ -2184,8 +1340,7 @@ mem_stage_stall_type shader_core_ctx::dcache_check(mem_access_t& access) if (access.isatomic) { if (m_config->gpgpu_perfect_mem) { // complete functional execution of atomic here - dram_callback_t &atom_exec = m_pipeline_reg[EX_MM][access.warp_indices[0]].callback; - atom_exec.function(atom_exec.instruction, atom_exec.thread); + m_pipeline_reg[EX_MM]->do_atomic(); } else { // atomics always go to memory access.cache_hit = false; @@ -2224,11 +1379,10 @@ void shader_core_ctx::memory_queue() // Called once per warp when warp enters memory stage. // Generates a list of memory accesses, but does not perform the memory access. - if( pipeline_regster_empty(m_pipeline_reg[EX_MM]) ) + if( m_pipeline_reg[EX_MM]->empty() ) return; m_gpu->mem_instruction_stats(m_pipeline_reg[EX_MM]); - inst_t *inst = first_valid_thread(m_pipeline_reg[EX_MM]); - switch (inst->space.get_type()) { + switch( m_pipeline_reg[EX_MM]->space.get_type() ) { case shared_space: memory_shared_process_warp(); break; case tex_space: memory_texture_process_warp(); break; case const_space: case param_space_kernel: memory_const_process_warp(); break; @@ -2258,9 +1412,8 @@ void shader_core_ctx::memory() m_stats->gpu_stall_shd_mem_breakdown[type][rc_fail]++; return; } - if( not pipeline_regster_empty( m_pipeline_reg[MM_WB] ) ) + if( not m_pipeline_reg[MM_WB]->empty() ) return; // writeback stalled - check_stage_pcs(EX_MM); move_warp(m_pipeline_reg[MM_WB],m_pipeline_reg[EX_MM]); } @@ -2281,292 +1434,6 @@ void shader_core_ctx::register_cta_thread_exit(int tid ) } } -void obtain_insn_latency_info(insn_latency_info *latinfo, const inst_t *insn) -{ - latinfo->pc = insn->pc; - latinfo->latency = gpu_tot_sim_cycle + gpu_sim_cycle - insn->issue_cycle; -} - -int debug_tid = 0; - -void shader_core_ctx::writeback() -{ - std::vector<inst_t> done_insts; - std::vector<insn_latency_info> unlock_lat_infos; - bool w2rf = false; - memset(m_pl_tid,-1, sizeof(int)*m_config->warp_size); - check_stage_pcs(MM_WB); - - // detect if a valid instruction is in MM_WB - for (unsigned i=0; i<m_config->warp_size; i++) { - w2rf |= (m_pipeline_reg[MM_WB][i].hw_thread_id >= 0); - m_pl_tid[i] = m_pipeline_reg[MM_WB][i].hw_thread_id; - } - - //check mshrs for commit; - unsigned mshr_threads_unlocked = 0; - bool stalled_by_MSHR = false; - - mshr_entry *mshr_head = m_mshr_unit->return_head(); - if (mshr_head && (mshr_threads_unlocked + mshr_head->num_inst() <= m_config->warp_size) ) { - assert (mshr_head->num_inst()); - for (unsigned j = 0; j < mshr_head->num_inst(); j++) { - const inst_t &insn = mshr_head->get_inst(j); - time_vector_update(insn.uid,MR_WRITEBACK,gpu_sim_cycle+gpu_tot_sim_cycle,RD_REQ); - obtain_insn_latency_info(&m_mshr_lat_info[mshr_threads_unlocked], &insn); - if (enable_ptx_file_line_stats) - ptx_file_line_stats_sub_inflight_memory_insn(m_sid, insn.pc); - assert (insn.hw_thread_id >= 0); - m_pending_mem_access--; - mshr_threads_unlocked++; - if (m_config->gpgpu_operand_collector) { - if ( j== 0 ) - m_operand_collector.writeback(insn); - } else - stalled_by_MSHR = true; - } - mshr_head->get_insts(done_insts); - - m_mshr_unit->pop_return_head(); - unlock_lat_infos.resize(mshr_threads_unlocked); - std::copy(m_mshr_lat_info, m_mshr_lat_info + mshr_threads_unlocked, unlock_lat_infos.begin()); - assert(mshr_threads_unlocked); - } - - if ( m_config->gpgpu_operand_collector ) - stalled_by_MSHR = !m_operand_collector.writeback( m_pipeline_reg[MM_WB] ); - - if (!stalled_by_MSHR) { - inst_t inst; - for (unsigned i=0; i<m_config->warp_size; i++) { - op_type op; - if (m_pipeline_reg[MM_WB][i].hw_thread_id > -1) - op = m_pipeline_reg[MM_WB][i].op; - obtain_insn_latency_info(&m_pl_lat_info[i], &m_pipeline_reg[MM_WB][i]); - if (!m_pipeline_reg[MM_WB][i].cache_miss) { // Do not include cache misses for a writeback - if (m_pipeline_reg[MM_WB][i].hw_thread_id > -1) { - done_insts.push_back(m_pipeline_reg[MM_WB][i]); - unlock_lat_infos.push_back(m_pl_lat_info[i]); - } - } - if (m_pl_tid[i] > -1 ) - inst = m_pipeline_reg[MM_WB][i]; - } - - // Unlock the warp for re-fetching (put it in the fixed delay queue) - if (w2rf) // Only need to unlock if this is a valid instruction - queue_warp_unlocking(m_pl_tid, inst); - } else - m_stats->gpu_stall_by_MSHRwb++; - - for (unsigned i=0; i<done_insts.size(); i++) { - inst_t done_inst = done_insts[i]; - call_thread_done(done_inst); - - gpu_sim_insn++; // a (scalar) instruction is done - if ( !is_const(done_inst.space) ) - m_stats->gpu_sim_insn_no_ld_const++; - m_gpu->gpu_sim_insn_last_update = gpu_sim_cycle; - m_gpu->gpu_sim_insn_last_update_sid = m_sid; - m_num_sim_insn++; - m_thread[done_inst.hw_thread_id].n_insn++; - m_thread[done_inst.hw_thread_id].n_insn_ac++; - - if (enable_ptx_file_line_stats) { - unsigned pc = unlock_lat_infos[i].pc; - unsigned long latency = unlock_lat_infos[i].latency; - ptx_file_line_stats_add_latency(pc, latency); - } - } - - if (!stalled_by_MSHR) { - if (!strcmp("GT200",m_config->pipeline_model) ) { - inst_t *fvt=first_valid_thread(m_pipeline_reg[MM_WB]); - if( fvt ) { - unsigned warp_id = fvt->hw_thread_id/m_config->warp_size; - m_warp[warp_id].dec_inst_in_pipeline(); - } - } - move_warp(m_pipeline_reg[WB_RT], m_pipeline_reg[MM_WB]); - } - - process_delay_queue(); -} - -/* - * Queues a warp into fixed delay queue for unlocking - * - * The amount of delay to add is determined by the instruction type. - * - * @param *tid Array of tid in the warp to unlock - * @param space Address space for the current instruction in the warp - * - */ -void shader_core_ctx::queue_warp_unlocking(int *tids, const inst_t &inst ) -{ - // Create a delay queue object and add it to the queue - fixeddelay_queue_warp_t fixeddelay_queue_warp; - - // Set ready_cycle based on instruction space - fixeddelay_queue_warp.inst = inst; - switch(inst.space.get_type()) { - case shared_space: - fixeddelay_queue_warp.ready_cycle = gpu_tot_sim_cycle + gpu_sim_cycle + 5; // Adds 5*4=20 cycles - break; - default: - fixeddelay_queue_warp.ready_cycle = gpu_tot_sim_cycle + gpu_sim_cycle; - break; - } - - // Store threads in delay queue warp object - fixeddelay_queue_warp.tids.resize(m_config->warp_size); - std::copy(tids, tids+m_config->warp_size, fixeddelay_queue_warp.tids.begin()); - m_fixeddelay_queue.insert(fixeddelay_queue_warp); -} - -/* - * Process a delay queue by unlocking warps ready this cycle - * - * @param *shader Pointer to shader core - * - */ -void shader_core_ctx::process_delay_queue() { - shader_core_ctx *shader=this; - // Unlock warps in fixeddelay_queue_warp - std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp>::iterator it; - std::multiset<fixeddelay_queue_warp_t, fixeddelay_queue_warp_comp>::iterator it_last; - for ( it=shader->m_fixeddelay_queue.begin() ; - it != shader->m_fixeddelay_queue.end(); - ) { - if(it->ready_cycle <= gpu_tot_sim_cycle + gpu_sim_cycle) { - if(!m_config->gpgpu_stall_on_use) { - // This disables stall-on-use - // If thread is still in warp_tracker, do not unlock yet - bool skip_unlock = false; - for(unsigned i=0; i<m_config->warp_size; i++) { - int tid = it->tids[i]; - if(tid < 0) continue; - if(m_warp_tracker->wpt_thread_in_wpt(tid)) { - skip_unlock = true; - break; - } - } - if(skip_unlock) { - it_last = it++; - continue; - } - } - - if (!strcmp("GT200",m_config->pipeline_model) ) { - if( it->inst.space == shared_space ) { - for(unsigned i=0; i < m_config->warp_size; i++ ) { - if( it->tids[i]>= 0 ) { - unsigned warp_id = it->tids[i]/m_config->warp_size; - m_scoreboard->releaseRegisters(warp_id,&it->inst); - break; - } - } - } - } - - // Unlock warp - unlock_warp(it->tids); - - // Remove warp information from delay queue - it_last = it++; - shader->m_fixeddelay_queue.erase(it_last); - } else { - break; - } - } -} - -/* - * Unlock a warp - * - * @param tids Vector of tid in the warp to unlock - * - */ -void shader_core_ctx::unlock_warp( std::vector<int> tids ) -{ - assert( tids.size() == m_config->warp_size ); // required by thd_commit_queue usage in fetch_simd_dwf() - int thd_unlocked = 0; - int thd_exited = 0; - int tid; - int valid_tid = -1; - - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { - // Unlock - for (unsigned i=0; i<m_config->warp_size; i++) { - tid = tids[i]; - if (tid >= 0) { - valid_tid = tid; - // thread completed if it is going to fetching beyond code boundary - if ( ptx_thread_done(tid) ) { - m_not_completed -= 1; - m_stats->gpu_completed_thread += 1; - int warp_id = wid_from_hw_tid(tid,m_config->warp_size); - if (!(m_warp[warp_id].get_n_completed() < m_config->warp_size)) - printf("GPGPU-Sim uArch: shader[%d]->warp[%d].n_completed = %d; warp_size = %d\n", - m_sid,warp_id, m_warp[warp_id].get_n_completed(), m_config->warp_size); - assert( m_warp[warp_id].get_n_completed() < m_config->warp_size ); - m_warp[warp_id].inc_n_completed(); - register_cta_thread_exit( tid ); - thd_exited = 1; - } else { - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { - assert(!m_thread[tid].m_avail4fetch); - m_thread[tid].m_avail4fetch=true; - assert( m_warp[tid/m_config->warp_size].get_avail4fetch() < m_config->warp_size ); - m_warp[tid/m_config->warp_size].inc_avail4fetch(); - } - thd_unlocked = 1; - } - } - } - } - - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) { - if(thd_unlocked || thd_exited) { - // Update the warp active mask - m_pdom_warp[wid_from_hw_tid(valid_tid,m_config->warp_size)]->pdom_update_warp_mask(); - } - } - - if (m_config->model == POST_DOMINATOR) { - // Do nothing - } else { - // For this case, submit to commit_queue - if (m_config->using_commit_queue && thd_unlocked) - m_thd_commit_queue->push( new std::vector<int>(tids), gpu_sim_cycle ); - } -} - - -/* - * Signals to the warp_tracker that a thread in a warp (for a given pc/instruction) is done - * - * @param *shd Pointer to shader core - * @param done_inst Completed instruction - * - */ -void shader_core_ctx::call_thread_done( inst_t &done_inst ) -{ - if (m_config->gpgpu_no_divg_load) { - // Signal to unlock the thread. If all threads are done, deregister warp - if( m_warp_tracker->wpt_signal_avail(done_inst.hw_thread_id, done_inst.pc) == 1 ) { - // Entire warp has returned - // Deregister warp - m_warp_tracker->wpt_deregister_warp(done_inst.hw_thread_id, done_inst.pc); - - if (! (!strcmp("GT200",m_config->pipeline_model) && (done_inst.space == shared_space)) ) - // Signal scoreboard to release register - m_scoreboard->releaseRegisters( wid_from_hw_tid(done_inst.hw_thread_id, m_config->warp_size), &done_inst ); - } - } -} - - void gpgpu_sim::shader_print_runtime_stat( FILE *fout ) { fprintf(fout, "SHD_INSN: "); @@ -2641,118 +1508,35 @@ void gpgpu_sim::shader_print_l1_miss_stat( FILE *fout ) fprintf(fout, "\n"); } -void shader_core_ctx::print_warp( inst_t *warp, FILE *fout, int print_mem, int mask ) const +void shader_core_ctx::print_warp( warp_inst_t *warp, FILE *fout, int print_mem, int mask ) const { - unsigned i, j, warp_id = (unsigned)-1; - for (i=0; i<m_config->warp_size; i++) { - if (warp[i].hw_thread_id > -1) { - warp_id = warp[i].hw_thread_id / m_config->warp_size; - break; - } - } - i = (i>=m_config->warp_size)? 0 : i; - - if( warp[i].pc != (address_type)-1 ) - fprintf(fout,"0x%04x ", warp[i].pc ); - else - fprintf(fout,"bubble " ); - - if( mask & 2 ) { - fprintf(fout, "(" ); - for (j=0; j<m_config->warp_size; j++) - fprintf(fout, "%03d ", warp[j].hw_thread_id); - fprintf(fout, "): "); - } else { - fprintf(fout, "w%02d[", warp_id); - for (j=0; j<m_config->warp_size; j++) - fprintf(fout, "%c", ((warp[j].hw_thread_id != -1)?'1':'0') ); - fprintf(fout, "]: "); - } - - if( warp_id != (unsigned)-1 && m_config->model == POST_DOMINATOR ) { - unsigned rp = m_pdom_warp[warp_id]->get_rp(); - if( rp == (unsigned)-1 ) { - fprintf(fout," rp:--- "); - } else { - fprintf(fout," rp:0x%03x ", rp ); - } - } - - ptx_print_insn( warp[i].pc, fout ); - - if( mask & 0x10 ) { - if ( (warp[i].op == STORE_OP || - warp[i].op == LOAD_OP) && print_mem ) - fprintf(fout, " mem: 0x%016llx", warp[i].memreqaddr); - } - fprintf(fout, "\n"); + if ( warp->empty() ) { + fprintf(fout,"bubble\n" ); + return; + } else + fprintf(fout,"0x%04x ", warp->pc ); + unsigned warp_id = warp->warp_id(); + fprintf(fout, "w%02d[", warp_id); + for (unsigned j=0; j<m_config->warp_size; j++) + fprintf(fout, "%c", (warp->active(j)?'1':'0') ); + fprintf(fout, "]: "); + if ( m_config->model == POST_DOMINATOR ) { + unsigned rp = m_pdom_warp[warp_id]->get_rp(); + if ( rp == (unsigned)-1 ) { + fprintf(fout," rp:--- "); + } else { + fprintf(fout," rp:0x%03x ", rp ); + } + } + ptx_print_insn( warp->pc, fout ); + fprintf(fout, "\n"); } void shader_core_ctx::print_stage(unsigned int stage, FILE *fout, int print_mem, int mask ) { - inst_t *warp = m_pipeline_reg[stage]; - print_warp(warp,fout,print_mem,mask); + print_warp(m_pipeline_reg[stage],fout,print_mem,mask); } -void shader_core_ctx::print_pre_mem_stages( FILE *fout, int print_mem, int mask ) -{ - unsigned i, j; - int warp_id; - - if (!m_config->gpgpu_pre_mem_stages) return; - - for (unsigned pms = 0; pms <= m_config->gpgpu_pre_mem_stages; pms++) { - fprintf(fout, "PM[%01d] = ", pms); - - warp_id = -1; - - for (i=0; i<m_config->warp_size; i++) { - if (pre_mem_pipeline[pms][i].hw_thread_id > -1) { - warp_id = pre_mem_pipeline[pms][i].hw_thread_id / m_config->warp_size; - break; - } - } - i = (i>=m_config->warp_size)? 0 : i; - - if( pre_mem_pipeline[pms][i].pc != (address_type)-1 ) - fprintf(fout,"0x%04x ", pre_mem_pipeline[pms][i].pc ); - else - fprintf(fout,"bubble " ); - - if( mask & 2 ) { - fprintf(fout, "(" ); - for (j=0; j<m_config->warp_size; j++) - fprintf(fout, "%03d ", pre_mem_pipeline[pms][j].hw_thread_id); - fprintf(fout, "): "); - } else { - fprintf(fout, "w%02d[", warp_id); - for (j=0; j<m_config->warp_size; j++) - fprintf(fout, "%c", ((pre_mem_pipeline[pms][j].hw_thread_id != -1)?'1':'0') ); - fprintf(fout, "]: "); - } - - if( warp_id != -1 && m_config->model == POST_DOMINATOR ) { - unsigned rp = m_pdom_warp[warp_id]->get_rp(); - if( rp == (unsigned)-1 ) { - fprintf(fout," rp:--- "); - } else { - fprintf(fout," rp:0x%03x ", rp ); - } - } - - ptx_print_insn( pre_mem_pipeline[pms][i].pc, fout ); - - if( mask & 0x10 ) { - if ( ( pre_mem_pipeline[pms][i].op == LOAD_OP || - pre_mem_pipeline[pms][i].op == STORE_OP ) && print_mem ) - fprintf(fout, " mem: 0x%016llx", pre_mem_pipeline[pms][i].memreqaddr); - } - fprintf(fout, "\n"); - } -} - -const char * ptx_get_fname( unsigned PC ); - void shader_core_ctx::display_pdom_state(FILE *fout, int mask ) { if ( (mask & 4) && m_config->model == POST_DOMINATOR ) { @@ -2765,7 +1549,7 @@ void shader_core_ctx::display_pdom_state(FILE *fout, int mask ) int done = ptx_thread_done(tid); nactive += (ptx_thread_done(tid)?0:1); if ( done && (mask & 8) ) { - unsigned done_cycle = ptx_thread_donecycle( m_thread[tid].m_functional_model_thread_state ); + unsigned done_cycle = m_thread[tid].m_functional_model_thread_state->donecycle(); if ( done_cycle ) { printf("\n w%02u:t%03u: done @ cycle %u", i, tid, done_cycle ); } @@ -2787,9 +1571,6 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) gpu_tot_sim_cycle, gpu_sim_cycle, m_not_completed); fprintf(fout, "=================================================\n"); - if (!strcmp("GPGPUSIM_ORIG",m_config->pipeline_model) ) - display_pdom_state(fout,mask); - if (!strcmp("GT200",m_config->pipeline_model) ) { dump_istream_state(fout); fprintf(fout,"\n"); @@ -2829,24 +1610,14 @@ void shader_core_ctx::display_pipeline(FILE *fout, int print_mem, int mask ) print_stage(ID_OC_SFU, fout, print_mem, mask); m_operand_collector.dump(fout); } - if (m_config->m_using_dwf_rrstage) { - fprintf(fout, "ID/RR = "); - print_stage(ID_RR, fout, print_mem, mask); - } if (!strcmp("GT200",m_config->pipeline_model) ) fprintf(fout, "ID/EX (SP) = "); - else - fprintf(fout, "ID/EX = "); print_stage(ID_EX, fout, print_mem, mask); if (!strcmp("GT200",m_config->pipeline_model) ) { fprintf(fout, "ID/EX (SFU) = "); print_stage(OC_EX_SFU, fout, print_mem, mask); } - print_pre_mem_stages(fout, print_mem, mask); - if (!m_config->gpgpu_pre_mem_stages) - fprintf(fout, "EX/MEM = "); - else - fprintf(fout, "PM/MEM = "); + fprintf(fout, "EX/MEM = "); print_stage(EX_MM, fout, print_mem, mask); fprintf(fout, "MEM/WB = "); print_stage(MM_WB, fout, print_mem, mask); @@ -2905,7 +1676,7 @@ unsigned int shader_core_ctx::max_cta( class function_info *kernel ) void shader_core_ctx::cycle_gt200() { - clear_stage(m_pipeline_reg[WB_RT]); + m_pipeline_reg[WB_RT]->clear(); writeback(); memory(); execute(); @@ -2914,23 +1685,6 @@ void shader_core_ctx::cycle_gt200() fetch_new(); } -void shader_core_ctx::cycle() -{ - clear_stage(m_pipeline_reg[WB_RT]); - writeback(); - memory(); - if (m_config->gpgpu_pre_mem_stages) // for modeling deeper pipelines - pre_memory(); - execute(); - if (m_config->m_using_dwf_rrstage) { - preexecute(); - } - if (m_config->gpgpu_operand_collector) - m_operand_collector.step(m_pipeline_reg[ID_OC]); - decode(); - fetch(); -} - // Flushes all content of the cache to memory void shader_core_ctx::cache_flush() @@ -3052,7 +1806,6 @@ std::list<opndcoll_rfu_t::op_t> opndcoll_rfu_t::arbiter_t::allocate_reads() return result; } - barrier_set_t::barrier_set_t( unsigned max_warps_per_core, unsigned max_cta_per_core ) { m_max_warps_per_core = max_warps_per_core; @@ -3244,15 +1997,13 @@ bool shd_warp_t::waiting() void shd_warp_t::print( FILE *fout ) const { if ( n_completed < m_warp_size ) { - fprintf( fout, "w%02u npc: 0x%04x, done:%2u a4f:%2u, i:%u s:%u a:%u b:%2u, (done: ", + fprintf( fout, "w%02u npc: 0x%04x, done:%2u i:%u s:%u a:%u (done: ", m_warp_id, m_next_pc, n_completed, - n_avail4fetch, m_inst_in_pipeline, m_stores_outstanding, - m_n_atomic, - n_waiting_at_barrier ); + m_n_atomic ); for (unsigned i = m_warp_id*m_warp_size; i < (m_warp_id+1)*m_warp_size; i++ ) { if ( m_shader->ptx_thread_done(i) ) fprintf(fout,"1"); else fprintf(fout,"0"); @@ -3360,12 +2111,6 @@ void mshr_entry::print(FILE *fp, unsigned mask) const if ( m_mf ) ptx_print_insn( m_mf->get_pc(), fp ); fprintf(fp,"\n"); - if ( mask & 0x200 ) { - for (unsigned i = 0; i < m_insts.size(); i++) { - fprintf(fp,"\tthread: UID:%d HW:%d ReqAddr:0x%llx\n", - m_insts[i].uid, m_insts[i].hw_thread_id, m_insts[i].memreqaddr); - } - } } } @@ -3373,8 +2118,8 @@ void opndcoll_rfu_t::init( unsigned num_collectors_alu, unsigned num_collectors_sfu, unsigned num_banks, shader_core_ctx *shader, - inst_t **alu_port, - inst_t **sfu_port ) + warp_inst_t **alu_port, + warp_inst_t **sfu_port ) { m_num_collectors = num_collectors_alu+num_collectors_sfu; @@ -3409,36 +2154,26 @@ void opndcoll_rfu_t::init( unsigned num_collectors_alu, } } -bool opndcoll_rfu_t::writeback( inst_t *warp ) -{ - // prefer not to stall writeback - inst_t *fvt=m_shader->first_valid_thread(warp); - if (!fvt) - return true; // nothing to do - return writeback(*fvt); -} - -int register_bank(int regnum, int tid, unsigned num_banks, unsigned bank_warp_shift) +int register_bank(int regnum, int wid, unsigned num_banks, unsigned bank_warp_shift) { int bank = regnum; if (bank_warp_shift) - bank += tid >> bank_warp_shift; + bank += wid; return bank % num_banks; } -bool opndcoll_rfu_t::writeback( const inst_t &fvt ) +bool opndcoll_rfu_t::writeback( const warp_inst_t &warp ) { - int tid = fvt.hw_thread_id; - assert( tid >= 0 ); // must be a valid instruction - std::list<unsigned> regs = m_shader->get_regs_written(fvt); + assert( !warp.empty() ); + std::list<unsigned> regs = m_shader->get_regs_written(warp); std::list<unsigned>::iterator r; unsigned last_reg = -1; unsigned n=0; for( r=regs.begin(); r!=regs.end();r++,n++ ) { unsigned reg = *r; - unsigned bank = register_bank(reg,tid,m_num_banks,m_bank_warp_shift); + unsigned bank = register_bank(reg,warp.warp_id(),m_num_banks,m_bank_warp_shift); if( m_arbiter.bank_idle(bank) ) { - m_arbiter.allocate_bank_for_write(bank,op_t(&fvt,reg,m_num_banks,m_bank_warp_shift)); + m_arbiter.allocate_bank_for_write(bank,op_t(&warp,reg,m_num_banks,m_bank_warp_shift)); } else { return false; } @@ -3451,8 +2186,8 @@ void opndcoll_rfu_t::dispatch_ready_cu() { port_to_du_t::iterator p; for( p=m_dispatch_units.begin(); p!=m_dispatch_units.end(); ++p ) { - inst_t **port = p->first; - if( !m_shader->pipeline_regster_empty(*port) ) + warp_inst_t **port = p->first; + if( !(*port)->empty() ) continue; dispatch_unit_t &du = p->second; collector_unit_t *cu = du.find_ready(); @@ -3463,12 +2198,11 @@ void opndcoll_rfu_t::dispatch_ready_cu() } } -void opndcoll_rfu_t::allocate_cu( inst_t *&id_oc_reg ) +void opndcoll_rfu_t::allocate_cu( warp_inst_t *&id_oc_reg ) { - inst_t *fvi = m_shader->first_valid_thread(id_oc_reg); - if( fvi ) { - inst_t **port = NULL; - if( fvi->op == SFU_OP ) + if( !id_oc_reg->empty() ) { + warp_inst_t **port = NULL; + if( id_oc_reg->op == SFU_OP ) port = m_sfu_port; else port = m_alu_port; @@ -3489,8 +2223,8 @@ void opndcoll_rfu_t::allocate_reads() for( std::list<op_t>::iterator r=allocated.begin(); r!=allocated.end(); r++ ) { const op_t &rr = *r; unsigned reg = rr.get_reg(); - unsigned tid = rr.get_tid(); - unsigned bank = register_bank(reg,tid,m_num_banks,m_bank_warp_shift); + unsigned wid = rr.get_wid(); + unsigned bank = register_bank(reg,wid,m_num_banks,m_bank_warp_shift); m_arbiter.allocate_for_read(bank,rr); read_ops[bank] = rr; } @@ -3513,7 +2247,7 @@ void gpgpu_sim::decrement_atomic_count( unsigned sid, unsigned wid ) bool opndcoll_rfu_t::collector_unit_t::ready() const { - return (!m_free) && m_not_ready.none() && m_rfu->shader_core()->pipeline_regster_empty(*m_port); + return (!m_free) && m_not_ready.none() && (*m_port)->empty(); } void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *shader ) const @@ -3532,7 +2266,7 @@ void opndcoll_rfu_t::collector_unit_t::dump(FILE *fp, const shader_core_ctx *sha } void opndcoll_rfu_t::collector_unit_t::init( unsigned n, - inst_t **port, + warp_inst_t **port, unsigned num_banks, unsigned log2_warp_size, unsigned warp_size, @@ -3543,36 +2277,33 @@ void opndcoll_rfu_t::collector_unit_t::init( unsigned n, m_port=port; m_num_banks=num_banks; assert(m_warp==NULL); - m_warp = (inst_t*)calloc(sizeof(inst_t),warp_size); - m_rfu->shader_core()->clear_stage(m_warp); + m_warp = new warp_inst_t(warp_size); m_bank_warp_shift=log2_warp_size; } -void opndcoll_rfu_t::collector_unit_t::allocate( inst_t *&pipeline_reg ) +void opndcoll_rfu_t::collector_unit_t::allocate( warp_inst_t *&pipeline_reg ) { assert(m_free); assert(m_not_ready.none()); m_free = false; - inst_t *fvi = m_rfu->shader_core()->first_valid_thread(pipeline_reg); - if( fvi ) { - m_tid = fvi->hw_thread_id; - m_warp_id = m_tid/m_rfu->shader_core()->get_config()->warp_size; + if( !pipeline_reg->empty() ) { + m_warp_id = pipeline_reg->warp_id(); for( unsigned op=0; op < 4; op++ ) { - int reg_num = fvi->arch_reg[4+op]; // this math needs to match that used in function_info::ptx_decode_inst + int reg_num = pipeline_reg->arch_reg[4+op]; // this math needs to match that used in function_info::ptx_decode_inst if( reg_num >= 0 ) { // valid register m_src_op[op] = op_t( this, op, reg_num, m_num_banks, m_bank_warp_shift ); m_not_ready.set(op); } else m_src_op[op] = op_t(); } - m_rfu->shader_core()->move_warp(m_warp,pipeline_reg); + move_warp(m_warp,pipeline_reg); } } void opndcoll_rfu_t::collector_unit_t::dispatch() { assert( m_not_ready.none() ); - m_rfu->shader_core()->move_warp(*m_port,m_warp); + move_warp(*m_port,m_warp); m_free=true; for( unsigned i=0; i<MAX_REG_OPERANDS;i++) m_src_op[i].reset(); diff --git a/src/gpgpu-sim/shader.h b/src/gpgpu-sim/shader.h index e621aad..7423025 100644 --- a/src/gpgpu-sim/shader.h +++ b/src/gpgpu-sim/shader.h @@ -117,12 +117,6 @@ public: class ptx_thread_info *m_functional_model_thread_state; unsigned m_cta_id; // hardware CTA this thread belongs - // used for controlling fetch - bool m_avail4fetch; // false if instruction from thread is in pipeline - bool m_in_scheduler; // DWF error checking - bool m_waiting_at_barrier; // DWF and MIMD models - bool m_reached_barrier; // DWF only - // per thread stats (ac stands for accumulative). unsigned n_insn; unsigned n_insn_ac; @@ -147,7 +141,6 @@ public: m_imiss_pending=false; m_warp_id=(unsigned)-1; n_completed = m_warp_size; - n_avail4fetch = n_waiting_at_barrier = 0; m_n_atomic=0; m_membar=false; m_done_exit=false; @@ -156,15 +149,14 @@ public: for(unsigned i=0;i<IBUFFER_SIZE;i++) m_ibuffer[i]=NULL; } - void init( address_type start_pc, unsigned wid, unsigned active ) + void init( address_type start_pc, unsigned cta_id, unsigned wid, unsigned active ) { + m_cta_id=cta_id; m_warp_id=wid; m_next_pc=start_pc; assert( n_completed >= active ); assert( n_completed <= m_warp_size); - assert( n_avail4fetch < m_warp_size ); n_completed -= active; // active threads are not yet completed - n_avail4fetch += active; // number of threads in warp available to be fetched } bool done(); @@ -176,10 +168,6 @@ public: void print( FILE *fout ) const; void print_ibuffer( FILE *fout ) const; - unsigned get_avail4fetch() const { return n_avail4fetch; } - void inc_avail4fetch() { n_avail4fetch++; } - void dec_avail4fetch() { n_avail4fetch--; } - unsigned get_n_completed() const { return n_completed; } void inc_n_completed() { n_completed++; } @@ -189,16 +177,13 @@ public: void inc_n_atomic() { m_n_atomic++; } void dec_n_atomic() { m_n_atomic--; } - void inc_waiting_at_barrier() { n_waiting_at_barrier++; } - void clear_waiting_at_barrier() { n_waiting_at_barrier=0; } - void set_membar() { m_membar=true; } void clear_membar() { m_membar=false; } bool get_membar() const { return m_membar; } address_type get_pc() const { return m_next_pc; } void set_next_pc( address_type pc ) { m_next_pc = pc; } - void ibuffer_fill( unsigned slot, const inst_t *pI ) + void ibuffer_fill( unsigned slot, const warp_inst_t *pI ) { assert(slot < IBUFFER_SIZE ); m_ibuffer[slot]=pI; @@ -219,10 +204,9 @@ public: m_ibuffer[i]=NULL; } } - const inst_t *ibuffer_next() + const warp_inst_t *ibuffer_next() { - const inst_t *result = m_ibuffer[m_next]; - return result; + return m_ibuffer[m_next]; } void ibuffer_free() { @@ -255,23 +239,23 @@ public: assert( m_inst_in_pipeline > 0 ); m_inst_in_pipeline--; } + unsigned get_cta_id() const { return m_cta_id; } private: static const unsigned IBUFFER_SIZE=2; class shader_core_ctx *m_shader; + unsigned m_cta_id; unsigned m_warp_id; unsigned m_warp_size; address_type m_next_pc; unsigned n_completed; // number of threads in warp completed - unsigned n_avail4fetch; // number of threads in warp available to fetch class mshr_entry *m_imiss_pending; - const inst_t *m_ibuffer[IBUFFER_SIZE]; + const warp_inst_t *m_ibuffer[IBUFFER_SIZE]; unsigned m_next; - int n_waiting_at_barrier; // number of threads in warp that have reached the barrier unsigned m_n_atomic; // number of outstanding atomic operations bool m_membar; // if true, warp is waiting at memory barrier @@ -331,7 +315,7 @@ public: void init( new_addr_type address, bool wr, memory_space_t space, unsigned warp_id ); void clear() { m_insts.clear(); } void set_mf( class mem_fetch *mf ) { m_mf=mf; } - void add_inst( inst_t inst ) { m_insts.push_back(inst); } + void add_inst( warp_inst_t inst ) { m_insts.push_back(inst); } void set_status( enum mshr_status status ); void merge( mshr_entry *mshr ) { @@ -339,11 +323,12 @@ public: m_merged_requests = mshr; mshr->m_merged_on_other_reqest = true; } - - dram_callback_t &get_atomic_callback() + void do_atomic() { - assert(isatomic()); - return m_insts[0].callback; + for( std::vector<warp_inst_t>::iterator e=m_insts.begin(); e != m_insts.end(); ++e ) { + warp_inst_t &inst = *e; + inst.do_atomic(); + } } mshr_entry *get_last_merged() { @@ -382,18 +367,13 @@ public: assert(m_status!=INVALID&&m_insts.size()>0); return m_insts[n]; } - unsigned get_insts_uid() const - { - assert(m_status!=INVALID&&m_insts.size()>0); - return m_insts[0].uid; - } bool isatomic() const { assert(m_status!=INVALID); if( isinst() ) return false; assert(m_insts.size()>0); - return (m_insts[0].callback.function != NULL); + return m_insts[0].isatomic(); } new_addr_type get_addr() const { return m_addr; } void print(FILE *fp, unsigned mask) const; @@ -403,7 +383,7 @@ private: unsigned m_request_uid; unsigned m_warp_id; new_addr_type m_addr; // address being fetched - std::vector<inst_t> m_insts; + std::vector<warp_inst_t> m_insts; bool m_iswrite; bool m_merged_on_other_reqest; //true if waiting for another mshr - this mshr doesn't send a memory request struct mshr_entry *m_merged_requests; //mshrs waiting on this mshr @@ -419,7 +399,7 @@ private: const unsigned WARP_PER_CTA_MAX = 32; typedef std::bitset<WARP_PER_CTA_MAX> warp_set_t; -int register_bank(int regnum, int tid, unsigned num_banks, unsigned bank_warp_shift); +int register_bank(int regnum, int wid, unsigned num_banks, unsigned bank_warp_shift); class shader_core_ctx; @@ -439,22 +419,13 @@ public: unsigned num_collectors_sfu, unsigned num_banks, shader_core_ctx *shader, - inst_t **alu_port, - inst_t **sfu_port ); + warp_inst_t **alu_port, + warp_inst_t **sfu_port ); // modifiers - bool writeback( const inst_t &fvt ); - bool writeback( inst_t *warp ); // might cause stall - - void step( inst_t *&id_oc_reg ) - { - dispatch_ready_cu(); - allocate_reads(); - allocate_cu(id_oc_reg); - process_banks(); - } + bool writeback( const warp_inst_t &warp ); // might cause stall - void step( inst_t *&alu_issue_port, inst_t *&sfu_issue_port ) + void step( warp_inst_t *&alu_issue_port, warp_inst_t *&sfu_issue_port ) { dispatch_ready_cu(); allocate_reads(); @@ -484,7 +455,7 @@ private: } void dispatch_ready_cu(); - void allocate_cu( inst_t *&id_oc_reg ); + void allocate_cu( warp_inst_t *&id_oc_reg ); void allocate_reads(); // types @@ -498,22 +469,20 @@ private: op_t( collector_unit_t *cu, unsigned op, unsigned reg, unsigned num_banks, unsigned bank_warp_shift ) { m_valid = true; - m_fvi=NULL; + m_warp=NULL; m_cu = cu; m_operand = op; m_register = reg; - m_tid = cu->get_tid(); - m_bank = register_bank(reg,m_tid,num_banks,bank_warp_shift); + m_bank = register_bank(reg,cu->get_warp_id(),num_banks,bank_warp_shift); } - op_t( const inst_t *fvi, unsigned reg, unsigned num_banks, unsigned bank_warp_shift ) + op_t( const warp_inst_t *warp, unsigned reg, unsigned num_banks, unsigned bank_warp_shift ) { m_valid=true; - m_fvi=fvi; + m_warp=warp; m_register=reg; m_cu=NULL; m_operand = -1; - m_tid = fvi->hw_thread_id; - m_bank = register_bank(reg,m_tid,num_banks,bank_warp_shift); + m_bank = register_bank(reg,warp->warp_id(),num_banks,bank_warp_shift); } // accessors @@ -523,16 +492,22 @@ private: assert( m_valid ); return m_register; } + unsigned get_wid() const + { + if( m_warp ) return m_warp->warp_id(); + else if( m_cu ) return m_cu->get_warp_id(); + else abort(); + return 0; + } unsigned get_oc_id() const { return m_cu->get_id(); } - unsigned get_tid() const { return m_tid; } unsigned get_bank() const { return m_bank; } unsigned get_operand() const { return m_operand; } void dump(FILE *fp) const { if(m_cu) fprintf(fp," <R%u, CU:%u, w:%02u> ", m_register,m_cu->get_id(),m_cu->get_warp_id()); - else if( m_fvi ) - fprintf(fp," <R%u, fvi tid:%02u> ", m_register,m_fvi->hw_thread_id ); + else if( !m_warp->empty() ) + fprintf(fp," <R%u, wid:%02u> ", m_register,m_warp->warp_id() ); } std::string get_reg_string() const { @@ -546,11 +521,10 @@ private: private: bool m_valid; collector_unit_t *m_cu; - const inst_t *m_fvi; + const warp_inst_t *m_warp; unsigned m_operand; // operand offset in instruction. e.g., add r1,r2,r3; r2 is oprd 0, r3 is 1 (r1 is dst) unsigned m_register; unsigned m_bank; - unsigned m_tid; }; enum alloc_t { @@ -676,7 +650,6 @@ private: m_warp = NULL; m_src_op = new op_t[MAX_REG_OPERANDS]; m_not_ready.reset(); - m_tid = -1; m_warp_id = -1; m_num_banks = 0; m_bank_warp_shift = 0; @@ -686,18 +659,17 @@ private: const op_t *get_operands() const { return m_src_op; } void dump(FILE *fp, const shader_core_ctx *shader ) const; - unsigned get_tid() const { return m_tid; } // returns hw id of first valid instruction unsigned get_warp_id() const { return m_warp_id; } unsigned get_id() const { return m_cuid; } // returns CU hw id // modifiers void init(unsigned n, - inst_t **port, + warp_inst_t **port, unsigned num_banks, unsigned log2_warp_size, unsigned warp_size, opndcoll_rfu_t *rfu ); - void allocate( inst_t *&pipeline_reg ); + void allocate( warp_inst_t *&pipeline_reg ); void collect_operand( unsigned op ) { @@ -708,11 +680,10 @@ private: private: bool m_free; - unsigned m_tid; unsigned m_cuid; // collector unit hw id - inst_t **m_port; // pipeline register to issue to when ready + warp_inst_t **m_port; // pipeline register to issue to when ready unsigned m_warp_id; - inst_t *m_warp; + warp_inst_t *m_warp; op_t *m_src_op; std::bitset<MAX_REG_OPERANDS> m_not_ready; unsigned m_num_banks; @@ -772,12 +743,12 @@ private: collector_unit_t *m_cu; arbiter_t m_arbiter; - inst_t **m_alu_port; - inst_t **m_sfu_port; + warp_inst_t **m_alu_port; + warp_inst_t **m_sfu_port; - typedef std::map<inst_t**/*port*/,dispatch_unit_t> port_to_du_t; + typedef std::map<warp_inst_t**/*port*/,dispatch_unit_t> port_to_du_t; port_to_du_t m_dispatch_units; - std::map<inst_t**,std::list<collector_unit_t*> > m_free_cu; + std::map<warp_inst_t**,std::list<collector_unit_t*> > m_free_cu; shader_core_ctx *m_shader; }; @@ -929,7 +900,7 @@ public: //return queue pop; (includes texture pipeline return) void pop_return_head(); - mshr_entry* add_mshr(mem_access_t &access, inst_t* warp); + mshr_entry* add_mshr(mem_access_t &access, warp_inst_t* warp); void mshr_return_from_mem(mshr_entry *mshr); unsigned get_max_mshr_used() const {return m_max_mshr_used;} void print(FILE* fp, class shader_core_ctx* shader,unsigned mask); @@ -1028,11 +999,10 @@ public: void deallocate_barrier( unsigned cta_id ); void decrement_atomic_count( unsigned wid ); - void cycle(); void cycle_gt200(); void reinit(unsigned start_thread, unsigned end_thread, bool reset_not_completed ); - void init_warps(unsigned start_thread, unsigned end_thread); + void init_warps(unsigned cta_id, unsigned start_thread, unsigned end_thread); unsigned max_cta( class function_info *kernel ); void cache_flush(); @@ -1043,14 +1013,10 @@ public: void store_ack( class mem_fetch *mf ); void dump_istream_state( FILE *fout ); void mshr_print(FILE* fp, unsigned mask); - inst_t *first_valid_thread( inst_t *warp ); - inst_t *first_valid_thread( unsigned stage ); + unsigned first_valid_thread( unsigned stage ); class ptx_thread_info* get_functional_thread( unsigned tid ) { return m_thread[tid].m_functional_model_thread_state; } - void move_warp( inst_t *&dst, inst_t *&src ); - void print_warp( inst_t *warp, FILE *fout, int print_mem, int mask ) const; - void clear_stage(inst_t *warp); + void print_warp( warp_inst_t *warp, FILE *fout, int print_mem, int mask ) const; std::list<unsigned> get_regs_written( const inst_t &fvt ) const; - bool pipeline_regster_empty( inst_t *reg ); const shader_core_config *get_config() const { return m_config; } unsigned get_num_sim_insn() const { return m_num_sim_insn; } int get_not_completed() const { return m_not_completed; } @@ -1075,30 +1041,14 @@ private: address_type next_pc( int tid ) const; - void ptx_exec_inst( inst_t &inst ); + void func_exec_inst( warp_inst_t &inst ); void fetch_new(); - void issue_warp(const inst_t *pI, unsigned active_mask, inst_t *&warp, unsigned warp_id ); + void issue_warp( warp_inst_t *&warp, const warp_inst_t *pI, unsigned active_mask, unsigned warp_id ); void decode_new(); - void fetch(); - - void fetch_mimd(); - void fetch_simd_dwf(); - void fetch_simd_postdominator(); - int pdom_sched_find_next_warp (int ready_warp_count); - bool fetch_stalled(); - void shader_issue_thread(int tid, int wlane, unsigned active_mask ); - int warp_reached_barrier(int *tid_in); - - void decode(); - - void preexecute(); - void execute(); void execute_pipe( unsigned pipeline, unsigned next_stage ); - void pre_memory(); - void memory(); // advance memory pipeline stage void memory_queue(); void memory_shared_process_warp(); @@ -1137,12 +1087,7 @@ private: std::vector<mem_access_t> &accessq ); mem_stage_stall_type send_mem_request(mem_access_t &access); - void check_stage_pcs( unsigned stage ); - void check_pm_stage_pcs( unsigned stage ); - void writeback(); - int split_warp_by_pc(int *tid_in, int **tid_split, address_type *pc); - int split_warp_by_cta(int *tid_in, int **tid_split, address_type *pc, int *cta); unsigned char fq_push( unsigned long long int addr, int bsize, @@ -1152,19 +1097,9 @@ private: enum mem_access_type mem_acc, address_type pc ); - bool warp_scoreboard_hazard(int warp_id); - mshr_entry* check_mshr4tag(unsigned long long int addr,int mem_type); - void update_mshr(unsigned long long int fetched_addr, unsigned int mshr_idx, int mem_type ); - void visualizer_dump(FILE *fp); - void clean(unsigned int n_threads); void call_thread_done(inst_t &done_inst ); - void queue_warp_unlocking(int *tids, const inst_t &inst ); - void process_delay_queue(); - void unlock_warp(std::vector<int> tids ); - void print_pre_mem_stages( FILE *fout, int print_mem, int mask ); void print_stage(unsigned int stage, FILE *fout, int print_mem, int mask ); - void print_shader_cycle_distro( FILE *fout ); // general information unsigned m_sid; // shader id @@ -1191,8 +1126,7 @@ private: pdom_warp_ctx_t **m_pdom_warp; // pdom reconvergence context for each warp class warp_tracker_pool *m_warp_tracker; - inst_t** m_pipeline_reg; - inst_t** pre_mem_pipeline; + warp_inst_t** m_pipeline_reg; Scoreboard *m_scoreboard; opndcoll_rfu_t m_operand_collector; mshr_shader_unit *m_mshr_unit; @@ -1204,19 +1138,6 @@ private: int m_last_warp_fetched; int m_last_warp_issued; - bool m_new_warp_TS; // new warp at TS pipeline register - int m_last_warp; // SIMT: last warp issued - int m_next_warp; // SIMT: Keeps track of which warp of instructions to fetch/execute - unsigned m_last_issued_thread; // MIMD - - int *m_ready_warps; - int *m_tmp_ready_warps; - int *m_fetch_tid_out; - - // pre-execute stage - int m_dwf_RR_k; // counter for register read pipeline - int *m_dwf_rrstage_bank_access_counter; - cache_t *m_L1I; // instruction cache cache_t *m_L1D; // data cache (global/local memory accesses) cache_t *m_L1T; // texture cache @@ -1229,8 +1150,6 @@ private: int *m_pl_tid; insn_latency_info *m_mshr_lat_info; insn_latency_info *m_pl_lat_info; - - class thread_pc_tracker *m_thread_pc_tracker; }; void init_mshr_pool(); @@ -1255,7 +1174,6 @@ void shader_print_l1_miss_stat( FILE *fout ); #define N_PIPELINE_STAGES 10 extern unsigned int *shader_cycle_distro; -extern unsigned int n_regconflict_stall; int is_store ( const inst_t &op ); diff --git a/src/gpgpu-sim/warp_tracker.cc b/src/gpgpu-sim/warp_tracker.cc deleted file mode 100644 index 44cbbc6..0000000 --- a/src/gpgpu-sim/warp_tracker.cc +++ /dev/null @@ -1,271 +0,0 @@ -/* - * warp_tracker.cc - * - * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda and the - * University of British Columbia - * Vancouver, BC V6T 1Z4 - * All Rights Reserved. - * - * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE - * TERMS AND CONDITIONS. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h - * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda - * (property of NVIDIA). The files benchmarks/BlackScholes/ and - * benchmarks/template/ are derived from the CUDA SDK available from - * http://www.nvidia.com/cuda (also property of NVIDIA). The files from - * src/intersim/ are derived from Booksim (a simulator provided with the - * textbook "Principles and Practices of Interconnection Networks" available - * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by - * the corresponding legal terms and conditions set forth separately (original - * copyright notices are left in files from these sources and where we have - * modified a file our copyright notice appears before the original copyright - * notice). - * - * Using this version of GPGPU-Sim requires a complete installation of CUDA - * which is distributed seperately by NVIDIA under separate terms and - * conditions. To use this version of GPGPU-Sim with OpenCL requires a - * recent version of NVIDIA's drivers which support OpenCL. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the University of British Columbia nor the names of - * its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. - * - * 5. No nonprofit user may place any restrictions on the use of this software, - * including as modified by the user, by any other authorized user. - * - * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, - * Ali Bakhoda, George L. Yuan, at the University of British Columbia, - * Vancouver, BC V6T 1Z4 - */ - -#include "warp_tracker.h" -#include "gpu-sim.h" -#include "shader.h" -#include <set> - -using namespace std; - -/* - * Constructor for warp_tracker_pool. - * - * Resizes the warp_tracker map and pool and allocates empty warp_trackers. - * - * @param tid_in Array of thread id's corresponding to a warp - * @param *my_shader Pointer to the shader core - * - */ -warp_tracker_pool::warp_tracker_pool(class shader_core_ctx *my_shader) -{ - m_shader=my_shader; - const shader_core_config *config = my_shader->get_config(); - gpu_n_thread_per_shader = config->n_thread_per_shader; - warp_size = config->warp_size; - warp_tracker_map.resize(gpu_n_thread_per_shader); -} - -/* - * Register a new warp_tracker with a warp - * - * A warp_tracker is fetched from the pool of warp_trackers and assigned to - * track the input warp. A (sid,tid,pc) to warp_tracker mapping is also stored. - * - * @param tid_in Array of thread id's corresponding to a single warp (array of size warp_size) - * @param *shd Pointer to the shader core - * - */ -void warp_tracker_pool::wpt_register_warp( int *tid_in, address_type pc, unsigned n_thd, unsigned warp_size ) -{ - assert(n_thd); - warp_tracker *wpt = new warp_tracker(tid_in,pc,warp_size); - // assign the new warp_tracker to warp_tracker_map - for (unsigned i=0; i<warp_size; i++) { - if (tid_in[i] >= 0) { - assert( map_get_warp_tracker(tid_in[i],pc) == NULL ); - map_set_warp_tracker(tid_in[i], pc, wpt); - } - } -} - -/* - * Signal that the current thread has completed and ready to be unlocked. - * - * @param tid Thread that is exiting - * @param *shd Pointer to the shader core - * - * @return Returns true is all threads in the warp have completed. - */ -int warp_tracker_pool::wpt_signal_avail( int tid, address_type pc ) -{ - warp_tracker *wpt = map_get_warp_tracker(tid,pc); - assert(wpt != NULL); - - - // signal the warp tracker - if (wpt->avail_thd()) { - return 1; - } else { - return 0; - } -} - -/* - * Unlock a warp - * - * Unlocks a warp for re-fetching. Sets avail4fetch = 1 for all threads and increments n_avail4fetch - * by number of active threads. - * - * @param tid Thread that is exiting - * - */ -void warp_tracker_pool::wpt_deregister_warp( int tid, address_type pc ) { - warp_tracker *wpt = map_get_warp_tracker(tid,pc); - assert(wpt != NULL); - map_clear_warp_tracker(wpt); - delete wpt; -} - - -/* - * Signal that the a thread is done and is exiting (exit instruction) - * - * Marks a thread as completed. If all threads in the warp have completed, call register_cta_thread_exit on all - * threads and removed the warp from warp tracker. - * - * @param tid Thread that is exiting - * - * @return The warp's mask of active threads. - */ -int warp_tracker_pool::wpt_signal_complete( int tid, address_type pc ) -{ - warp_tracker *wpt = map_get_warp_tracker(tid,pc); - assert(wpt != NULL); - - // signal the warp tracker - if (wpt->complete_thd(tid)) { - // if the warp has completed execution, remove this warp_tracker - map_clear_warp_tracker(wpt); - int warp_mask = 0; - for (unsigned i=0; i<warp_size; i++) { - if (wpt->tid(i) >= 0) { - m_shader->register_cta_thread_exit( wpt->tid(i) ); - warp_mask |= (1 << i); - } - } - delete wpt; - return warp_mask; - } else { - return 0; - } -} - -/* - * Check if this thread is being tracked by the warp tracker currently - * - * Checks if any pc of the given tid maps to a warp_tracker - * - * @param tid Thread to check - * - * @return True is thread is being tracked - */ -bool warp_tracker_pool::wpt_thread_in_wpt(int tid) { - std::map<address_type, warp_tracker*>::iterator it; - for(it=warp_tracker_map[tid].begin(); it!=warp_tracker_map[tid].end(); it++) - if((*it).second != NULL) - return true; - - return false; -} - -//------------------------------------------------------------------------------------ - -map<unsigned, unsigned> thread_pc_tracker::histogram; - -thread_pc_tracker *thread_pc_tracker = NULL; - -void print_thread_pc_histogram( FILE *fout ) -{ - thread_pc_tracker::histo_print(fout); -} - -void print_thread_pc( FILE *fout, unsigned n_shader ) -{ - fprintf(fout, "SHD_PC_C: "); - for (unsigned i=0; i<n_shader; i++) { - fprintf(fout, "%d ", thread_pc_tracker[i].get_acc_pc_count() ); - } - fprintf(fout, "\n"); -} - -// uncomment to enable checking for warp consistency -// #define CHECK_WARP_CONSISTENCY - -void shader_core_ctx::check_stage_pcs( unsigned stage ) -{ -#ifdef CHECK_WARP_CONSISTENCY - address_type inst_pc = (address_type)-1; - unsigned tid; - if( m_config->model == MIMD ) - return; - - std::set<unsigned> tids; - - for ( int i = 0; i < m_config->warp_size; i++) { - if (m_pipeline_reg[i][stage].hw_thread_id == -1 ) - continue; - if ( inst_pc == (address_type)-1 ) - inst_pc = m_pipeline_reg[i][stage].pc; - tid = m_pipeline_reg[i][stage].hw_thread_id; - assert( tids.find(tid) == tids.end() ); - tids.insert(tid); - assert( inst_pc == m_pipeline_reg[i][stage].pc ); - } -#endif -} - -void shader_core_ctx::check_pm_stage_pcs( unsigned stage ) -{ -#ifdef CHECK_WARP_CONSISTENCY - address_type inst_pc = (address_type)-1; - unsigned tid; - if( m_config->model == MIMD ) - return; - - std::set<unsigned> tids; - - for (int i = 0; i < m_config->warp_size; i++) { - if (pre_mem_pipeline[i][stage].hw_thread_id == -1 ) - continue; - if ( inst_pc == (address_type)-1 ) - inst_pc = pre_mem_pipeline[i][stage].pc; - tid = pre_mem_pipeline[i][stage].hw_thread_id; - assert( tids.find(tid) == tids.end() ); - tids.insert(tid); - assert( inst_pc == pre_mem_pipeline[i][stage].pc ); - } -#endif -} diff --git a/src/gpgpu-sim/warp_tracker.h b/src/gpgpu-sim/warp_tracker.h deleted file mode 100644 index 8397a81..0000000 --- a/src/gpgpu-sim/warp_tracker.h +++ /dev/null @@ -1,261 +0,0 @@ -/* - * waro_tracker.h - * - * Copyright (c) 2009 by Tor M. Aamodt, Wilson W. L. Fung, Ali Bakhoda and the - * University of British Columbia - * Vancouver, BC V6T 1Z4 - * All Rights Reserved. - * - * THIS IS A LEGAL DOCUMENT BY DOWNLOADING GPGPU-SIM, YOU ARE AGREEING TO THESE - * TERMS AND CONDITIONS. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * NOTE: The files libcuda/cuda_runtime_api.c and src/cuda-sim/cuda-math.h - * are derived from the CUDA Toolset available from http://www.nvidia.com/cuda - * (property of NVIDIA). The files benchmarks/BlackScholes/ and - * benchmarks/template/ are derived from the CUDA SDK available from - * http://www.nvidia.com/cuda (also property of NVIDIA). The files from - * src/intersim/ are derived from Booksim (a simulator provided with the - * textbook "Principles and Practices of Interconnection Networks" available - * from http://cva.stanford.edu/books/ppin/). As such, those files are bound by - * the corresponding legal terms and conditions set forth separately (original - * copyright notices are left in files from these sources and where we have - * modified a file our copyright notice appears before the original copyright - * notice). - * - * Using this version of GPGPU-Sim requires a complete installation of CUDA - * which is distributed seperately by NVIDIA under separate terms and - * conditions. To use this version of GPGPU-Sim with OpenCL requires a - * recent version of NVIDIA's drivers which support OpenCL. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the University of British Columbia nor the names of - * its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 4. This version of GPGPU-SIM is distributed freely for non-commercial use only. - * - * 5. No nonprofit user may place any restrictions on the use of this software, - * including as modified by the user, by any other authorized user. - * - * 6. GPGPU-SIM was developed primarily by Tor M. Aamodt, Wilson W. L. Fung, - * Ali Bakhoda, George L. Yuan, at the University of British Columbia, - * Vancouver, BC V6T 1Z4 - */ - -#ifndef warp_tracker_h_INCLUDED -#define warp_tracker_h_INCLUDED - -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include <cassert> -#include <map> -#include <list> -#include <deque> -#include <queue> -#include <vector> -#include <map> -#include <list> - -#include "../abstract_hardware_model.h" -#include "shader.h" - -void print_thread_pc_histogram( FILE *fout ); -void print_thread_pc( FILE *fout, unsigned n_shader ); - -class warp_tracker { -public: - warp_tracker( int *tid, address_type pc, unsigned warp_size ) - { - // makes a copy of pc and thread ids in warp - m_pc = pc; - m_n_thd = 0; - m_warp_size=warp_size; - m_tid.reserve(warp_size); - std::copy(tid, tid+warp_size, m_tid.begin()); - for (unsigned i=0; i<warp_size; i++) - if (tid[i] >= 0) m_n_thd++; - m_n_notavail = m_n_thd; - } - - void print_info( unsigned sid ) const - { - printf("sid=%d tid=[", sid); - for(unsigned i=0; i<m_tid.size(); i++) - if(m_tid[i] > -1) printf("%d ", m_tid[i]); - printf("]\n"); - } - unsigned warp_size() const { return m_warp_size; } - address_type pc() const { return m_pc; } - int tid(unsigned i) const { return m_tid[i]; } - - bool avail_thd() - { - // signal that this thread is available for fetch - // if all threads in the warp are available, change all their status - // and return true - assert( m_n_notavail > 0 ); - m_n_notavail--; - return (m_n_notavail==0); - } - - bool complete_thd( int tid_in ) - { - // a bookkeeping method to allow a warp to be deallocated - // when its threads have finished executing. - assert( m_n_notavail > 0 ); - m_n_notavail--; - if (m_n_notavail) { - return false; - } else { - return true; - } - } - -private: - address_type m_pc; - std::vector<int> m_tid; - int m_n_thd; // total number of threads in this warp with active mask set to enabled - int m_n_notavail; // number of threads waiting (preventing this warp from being issued again) - unsigned m_warp_size; -}; - - -class warp_tracker_pool { -public: - warp_tracker_pool( class shader_core_ctx *my_shader ); - - void wpt_register_warp( int *tid_in, address_type pc, unsigned n_thread_in_warp, unsigned warp_size ); - int wpt_signal_avail( int tid, address_type pc ); - void wpt_deregister_warp( int tid, address_type pc ); - int wpt_signal_complete( int tid, address_type pc ); - bool wpt_thread_in_wpt( int tid ); - -private: - warp_tracker* map_get_warp_tracker(int tid, address_type pc) { - // Returns NULL pointer if no warp_tracker assigned - if(warp_tracker_map[tid].find(pc) == warp_tracker_map[tid].end()) - return NULL; - return warp_tracker_map[tid][pc]; - } - - void map_set_warp_tracker(int tid, address_type pc, warp_tracker* wpt) { - // Make sure that warp tracker is not already assigned here - if(warp_tracker_map[tid].find(pc) != warp_tracker_map[tid].end()) - assert(warp_tracker_map[tid][pc] == NULL); - warp_tracker_map[tid][pc] = wpt; - } - - void map_clear_warp_tracker( warp_tracker *wpt ) { - // Make sure that warp tracker was previously assigned - address_type pc = wpt->pc(); - for (unsigned i=0; i<wpt->warp_size(); i++) { - int tid = wpt->tid(i); - if (tid >= 0) { - assert(warp_tracker_map[tid].find(pc) != warp_tracker_map[tid].end()); - assert(warp_tracker_map[tid][pc] != NULL); - warp_tracker_map[tid][pc] = NULL; - } - } - } - -// data - - class shader_core_ctx *m_shader; - unsigned gpu_n_thread_per_shader; - unsigned warp_size; - - // Warp tracker map: vector (index thread id) of maps (index pc) - std::vector< std::map<address_type, warp_tracker*> > warp_tracker_map; -}; - -class thread_pc_tracker { -public: - address_type *thd_pc; // tracks the pc of each thread - std::map<address_type, unsigned> pc_count; - unsigned acc_pc_count; - int simd_width; - static std::map<unsigned, unsigned> histogram; // static so automatically aggregated across cores - - thread_pc_tracker( ) { - this->acc_pc_count = 0; - this->simd_width = 0; - this->thd_pc = NULL; - } - - thread_pc_tracker(int simd_width, int thread_count) { - this->acc_pc_count = 0; - this->simd_width = simd_width; - this->thd_pc = new address_type[thread_count]; - memset( this->thd_pc, 0, sizeof(address_type)*thread_count); - } - - void add_threads( int *tid, address_type pc ) { - for (int i=0; i<simd_width; i++) { - if (tid[i] != -1) { - pc_count[pc] += 1; // automatically create a new entry if not exist - thd_pc[tid[i]] = pc; - } - } - } - - void sub_threads( int *tid ) { - for (int i=0; i<simd_width; i++) { - if (tid[i] != -1) { - address_type pc = thd_pc[tid[i]]; - if (pc == 0) break; - pc_count[pc] -= 1; - assert((int)pc_count[pc] >= 0); - if (pc_count[pc] == 0) pc_count.erase(pc); // manually erasing entries with 0 count - } - } - } - - void update_acc_count( ) { - acc_pc_count += pc_count.size(); - histogram[pc_count.size()] += 1; - } - - void set_threads_pc ( int *tid, address_type pc ) { - sub_threads(tid); - add_threads(tid, pc); - update_acc_count( ); - } - - unsigned get_acc_pc_count( ) { return acc_pc_count;} - - unsigned count( ) { return pc_count.size();} - - static void histo_print( FILE* fout ) { - if (histogram.empty()) return; // do not output anything if the histogram is empty - std::map<unsigned, unsigned>::iterator i; - fprintf(fout, "Thread PC Histogram: "); - for (i = histogram.begin(); i != histogram.end(); i++) { - fprintf(fout, "%d:%d ", i->first, i->second); - } - fprintf(fout, "\n"); - } -}; - -#endif diff --git a/src/intersim/interconnect_interface.cpp b/src/intersim/interconnect_interface.cpp index 56b2d18..0ed7150 100644 --- a/src/intersim/interconnect_interface.cpp +++ b/src/intersim/interconnect_interface.cpp @@ -556,7 +556,7 @@ void time_vector_update_icnt_injected(void* data, int input) { mem_fetch* mf = (mem_fetch*) data; if( mf->get_mshr() && !mf->get_mshr()->isinst() ) { - unsigned uid=mf->get_is_write()? mf->get_request_uid() : mf->get_mshr()->get_insts_uid(); + unsigned uid=mf->get_request_uid(); long int cycle = gpu_sim_cycle + gpu_tot_sim_cycle; int req_type = mf->get_is_write()? WT_REQ : RD_REQ; if (is_mem(input)) { |
