summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Aamodt <[email protected]>2010-10-05 13:34:47 -0800
committerTor Aamodt <[email protected]>2010-10-05 13:34:47 -0800
commite0f1b4359832ba2952ddcff3a400cd7e1e3d02b5 (patch)
tree12f3dbd8366e15b4a9a299b0368df6fafea11847
parentd859e08188eb5863888a9b018cf4aec6d0419c40 (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.cc11
-rw-r--r--src/abstract_hardware_model.h147
-rw-r--r--src/cuda-sim/cuda-sim.cc102
-rw-r--r--src/cuda-sim/cuda-sim.h11
-rw-r--r--src/cuda-sim/instructions.cc11
-rw-r--r--src/cuda-sim/ptx_ir.cc2
-rw-r--r--src/cuda-sim/ptx_ir.h2
-rw-r--r--src/cuda-sim/ptx_sim.h2
-rw-r--r--src/debug.cc8
-rw-r--r--src/gpgpu-sim/dwf.cc2606
-rw-r--r--src/gpgpu-sim/dwf.h121
-rw-r--r--src/gpgpu-sim/gpu-sim.cc137
-rw-r--r--src/gpgpu-sim/gpu-sim.h11
-rw-r--r--src/gpgpu-sim/mem_fetch.cc8
-rw-r--r--src/gpgpu-sim/mem_latency_stat.cc6
-rw-r--r--src/gpgpu-sim/scoreboard.cc3
-rw-r--r--src/gpgpu-sim/scoreboard.h2
-rw-r--r--src/gpgpu-sim/shader.cc1601
-rw-r--r--src/gpgpu-sim/shader.h186
-rw-r--r--src/gpgpu-sim/warp_tracker.cc271
-rw-r--r--src/gpgpu-sim/warp_tracker.h261
-rw-r--r--src/intersim/interconnect_interface.cpp2
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)) {